Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CWG2938 [basic.link] Inheriting linkage from previous declaration #609

Open
Endilll opened this issue Sep 12, 2024 · 2 comments
Open

CWG2938 [basic.link] Inheriting linkage from previous declaration #609

Endilll opened this issue Sep 12, 2024 · 2 comments

Comments

@Endilll
Copy link

Endilll commented Sep 12, 2024

Full name of submitter (unless configured in github; will be published with the issue): Vlad Serebrennikov

Reference (section label): [basic.link]

Link to Mattermost thread: https://chat.isocpp.org/general/pl/7tdru1ma9fgrddm8h4tjozwwca

Issue description

Consider the following excerpt from https://eel.is/c++draft/basic.link#example-1 (numbering is mine):

static void f(); // #1
void q() {
  extern void f(); // #2, internal linkage
}

#1 has internal linkage without any doubt per [basic.link]/3.1.

Then we put #2 through [basic.link], and I think the following happens:

  1. #2 belongs to a namespace scope per [dcl.meaning]/3.5 and [basic.scope]/2.
  2. 3.1 doesn't apply, because #2 is not explicitly declared static.
  3. 3.2 and 3.3 don't apply to function declarations.
  4. Then we move to p4.
  5. #2 has not been given internal linkage "above" (which presumably is referring to p3).
  6. #2 is a function declaration, so p4 applies per [basic.link]/4.2.
  7. Friend declarations are not involved, so we skip over 4.7 and 4.8.
  8. Enclosing namespace is global, so it has external linkage, which means 4.9 also doesn't apply.
  9. Modules are not involved, so 4.10 doesn't apply either.
  10. [basic.link]/4.11 makes #2 to have external linkage.

[basic.link]/8 establishes that #1 and #2 declare the same entity, then [dcl.stc]/6 makes the example ill-formed.

That said, http://eel.is/c++draft/basic.link#example-1, https://eel.is/c++draft/dcl.stc#note-4, and https://eel.is/c++draft/dcl.stc#example-1 all imply that there's an interpretation of the wording that makes later declarations "inherit" linkage from the previous declaration, but I fail to read the wording this way. One could argue that linkage is a property of an entity, so "inheritance" could work automatically after doing declaration matching, but [basic.link]/2 explicitly says that linkage is a property of a name, and not of an entity being declared. Moreover, [basic.link]/8 requires linkage of both declarations to be known prior to declaration matching.

Note that language linkage has explicit wording for this in [dcl.link]/6. Prior to P1787R6, we had wording of a similar effect in [basic.link]/6 (emphasis mine):

If there is a visible declaration of an entity with linkage, ignoring entities declared outside the innermost enclosing namespace scope, such that the block scope declaration would be a (possibly ill-formed) redeclaration if the two declarations appeared in the same declarative region, the block scope declaration declares that same entity and receives the linkage of the previous declaration.

Could I get a clarification how the current wording supports aforementioned examples and notes, if they are correct?

This was discussed with Davis on Mattermost: https://chat.isocpp.org/general/pl/7tdru1ma9fgrddm8h4tjozwwca

@AaronBallman
Copy link

I think the wording could perhaps be made more clear, but I think the way this works is off an undocumented idea of "name matching" which is slightly different from lookup in that it's actually straightforward (there either is a name already bound to a namespace scope or there is not). I think the way this is supposed to work is:

  1. #2 belongs to a namespace scope per [dcl.meaning]p3.5 and [basic.scope]p2.
  2. p3 applies; there's either zero or one such name within the TU; because of the prior declaration, there is a name of an entity at namespace scope.
  3. We get to p3.1 because the entity that name refers to is a function which is explicitly declared static.
  4. Then we move to p4.
  5. The name of the entity which belongs to namespace scope was given internal linkage above (in p3), so p4 does not apply.
  6. We end up with the naming having internal linkage.

That said, it's unclear because there's only one name but there are multiple entities involved. So it's easy to get confused by which entity we mean when we say "the name of an entity that belongs to namespace scope". If I'm correct about the whole "name matching" business, maybe that could be made more clear too.

Also, I could be entirely off-base. :-)

@jensmaurer
Copy link
Member

CWG2938

@jensmaurer jensmaurer changed the title [basic.link] Inheriting linkage from previous declaration CWG2938 [basic.link] Inheriting linkage from previous declaration Oct 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants