https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121563

--- Comment #16 from Christopher Bazley <Chris.Bazley at arm dot com> ---
(In reply to Harald van Dijk from comment #15)
> (In reply to Christopher Bazley from comment #14)
> > (In reply to Harald van Dijk from comment #12)
> > > (In reply to Christopher Bazley from comment #11)
> > > > It includes the following new argument against permitting
> > > > duplicate forward declarations (which may or may not be persuasive to 
> > > > the
> > > > reader).
> > > 
> > > That isn't persuasive to me, no.
> > 
> > It's not clear to me whether you read the relevant part of the paper,
> 
> I did.
> 
> >                                                                       or
> > only the words that I selectively quoted (which is my fault). The wider
> > context is that "the redeclaration semantics of the C language already vary
> > depending on the context in which a declaration appears". (In other words,
> > an argument in favour of permitting duplicate forward declarations, because
> > they appear in the context of a parameter-forward-declaration-list.)
> 
> My comment was pointing out that the redeclaration semantics *don't* vary
> like you say, there is a very simple general rule that they all follow, that

If I understood you correctly, your very simple general rule is "Multiple
declarations are valid in file scope and in function scope, so long as they are
not definitions." That seems a bit circular to me: it says that multiple
declarations are valid so long as they are not the kind of declaration that
would be invalid.

The existing rules for determining whether a declaration is a definition or not
are not simple to me; I think they are one of the most complex parts of the
language. Saying that the rule is simple if one can reliably distinguish a
declaration from a definition doesn't help the average programmer.

> you are proposing no longer following for parameter declarations. I also
> said that could be justifiable, but I struggle with the not acknowledging
> that such a rule even exists.
> 
> > > > Declarations that are valid at file scope are invalid in function scope:
> > > > 
> > > > int x, x; // valid
> > > > void f()
> > > > {
> > > >   int x, x; // invalid
> > > > }
> > > 
> > > That is a bit misleading.
> > 
> > It is potentially misleading that the two declarations above use the same
> > derivation rule in the syntax but have different semantics. Nevertheless,
> > both are declarations, as I wrote.
> 
> Yes. The ones at file scope are declarations that are not definitions. The
> ones at block scope are declarations that are definitions. That's such an
> essential difference in semantics that I'm going to mention that again here
> for the avoidance of confusion.
> 
> > Parameter forward declarations do not use the same derivation rule as
> > ordinary declarations, but they use the same derivation rule as parameter
> > declarations (and are indistinguishable from them).
> 
> Sure, but as you also wrote just above, it's possible for constructs using
> the same derivation rule in the syntax to have different semantics, so
> whether parameter forward declarations and parameter declarations use the
> same syntax is not sufficient to say whether their semantics should also be
> the same.
> 
> > "When existing syntax is given new semantics, it inevitably looks wrong
> > (regardless of whether it is subjectively ugly or not) if those semantics
> > contradict user expectations" (from my paper). If file-scope declarations
> > didn't exist and someone invented them with the same syntax as
> > function-scope declarations but different semantics then I think that would
> > be confusing. I also think that "int x, x" looks wrong because
> > function-scope declarations are more common than file-scope declarations.
> 
> So it sounds like you disagree with the existing general rule, not just for
> parameter forward declarations but in general, and have based your opinion
> for parameter forward declarations on that. My expectations as a user who
> gets and likes that general rule are different.

I don't disagree that "Multiple declarations are valid in file scope and in
function scope, so long as they are not definitions", I just don't find it of
much practical use. It hinges on the definition of "definition", which is
complex and context-dependent.

The problem isn't the semantics; it's the syntax. For example, I think it would
be better if 'extern' were not implicit on function declarations within a
function body and on file-scope definitions with external linkage.

> > Of course, but you have modified the declarations in such a way that they no
> > longer resemble one another.
> 
> Yes, because whether duplicate declarations are permitted depends on their
> semantics, not their appearance, so I modified it so that their semantics
> are sufficiently similar, rather than their appearance.
> 
> >                              If the syntax of parameter forward declarations
> > required a storage-class specifier like 'extern' then there would be no
> > ambiguity about whether they are definitions or not.
> 
> True. I think (and I think you will agree) that that would be a bad idea for
> other reasons, but it would have avoided this particular problem.
> 
> > As you noted, "a typedef name can be redefined to denote the same type as it
> > currently does, provided that type is not a variably modified type" (from
> > the ISO standard). I don't think the fact this is called a definition rather
> > than a declaration is relevant though.
> 
> Isn't it? Since the general rule I stated is that multiple declarations are
> okay so long as there aren't multiple definitions, it seems relevant to me
> what does and doesn't count as a definition.

This nuance did not seem to be relevant to me because I believed there to be no
observable difference between a typedef name declaration and a typedef name
definition. Typedef declarations do not behave like object definitions for
obvious reasons: they do not "cause storage to be reserved for that object".

> > In any case, I think there is little danger of either of the declarations
> > that you gave as examples being interpreted as definitions. That is why I
> > believe the situation is different from the situation with parameter
> > declarations.
> 
> Personally, I think parameter forward declarations are unclear in general:
> it's not just computers, it's also us who need to scan ahead to know that
> the first argument to a call to void f(int x, int y; int y, int x) is used
> for the parameter y, not x. If we say that this is acceptable to users, if
> we expect them to see the semicolon and realise that the initial int x, int
> y; are forward declarations, I think we are already saying that there is
> little danger of them being interpreted as definitions.

Why shouldn't parameter forward declarations be interpreted as definitions?

> If we instead say
> that that danger is there, I think it would be difficult to justify using
> that danger *only* for the purpose of diagnosing duplicate declarations, and
> not more generally.
> 
> > > They aren't. Because forward parameter declarations are never definitions,
> > > there is no ambiguity.
> > 
> > As far as I could tell from its source code, GCC provisionally treats
> > parameter forward declarations as definitions, similar to how tentative
> > definitions are provisionally treated as definitions. Have I misread the
> > code, or is your opinion based on the intended semantics of GCC's extension?
> > GCC's manual doesn't say anything about whether or not parameter forward
> > declarations are definitions.
> > 
> > I don't think the ISO C23 standard explicitly describes parameter
> > declarations as definitions either; it just says "Each parameter has
> > automatic storage duration; its identifier, if any, is an lvalue."
> 
> I'm going by the standard's meaning of "definition" in 6.7 Declarations, "A
> definition of an identifier is a declaration for that identifier that for:
> an object, causes storage to be reserved for that object".

Thanks. It's not clear to me how this applies to tentative definitions, if at
all. A whole translation unit must be parsed before it's possible to determine
that "the translation unit contains no external definition for that identifier"
(and then it seems to be unspecified which, if any, of the tentative
definitions becomes the one that "causes storage to be reserved").

> This applies to
> parameter declarations but not to parameter forward declarations.

Based on what? The proposed wording changes in n3681 or something else?

The ISO standard says "The layout of the storage for parameters is unspecified"
and the register(s) or stack location(s) in which an argument is passed to a
function aren't necessarily the same as the register(s) or stack location(s)
used to store that object's value within the function. Maybe it is at the level
of SSA name. I haven't looked into it.

The existing exceptions to the rule that "If an identifier has no linkage,
there shall be no more than one declaration of the identifier (in a declarator
or type specifier) with the same scope and in the same name space" (6.7.1
Constraints) concern typedef names and enumeration constants and tags. These
are the same kinds of declaration that are definitions by virtue of being
"...the first (or only) declaration of the identifier..." (6.7.1 Semantics).

N3681 proposes adding "a parameter in a parameter forward declaration list
shall be redeclared in the parameter type list as specified in 6.7.7.4" to the
list of exceptions in the Constraints; it would be possible to make the
equivalent change to the Semantics, i.e. add

A definition of an identifier is a declaration for that identifier that for:

- a parameter, is the first (or only) declaration of the identifier.

I don't think this would make any observable difference but it would clear up
the current ambiguity.

> > Do you have any specific concerns about the proposed wording changes in
> > https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3681.pdf ?
> 
> My objection is specifically about the rationale, not the wording, other
> than that changes to the rationale might possibly lead to changes in desired
> semantics, which would then result in changes to the wording.

See above.

Reply via email to