Does a declaration using "auto" match an extern declaration that uses a concrete type specifier?
There's surprisingly little in the standard about this. About all we hear about redeclaration is:
[C++11: 3.1/1]:
A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations. [..]
and the only relevant part of auto
's semantics:
[C++11: 7.1.6.4/3]:
Otherwise, the type of the variable is deduced from its initializer. [..]
(reminding us that the type of x
is int
).
We know that a variable must be given the same type by all declarations:
[C++11: 3.5/10]:
After all adjustments of types (during which typedefs (7.1.3) are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical, except that declarations for an array object can specify array types that differ by the presence or absence of a major array bound (8.3.4). A violation of this rule on type identity does not require a diagnostic.
and the "after all adjustments of types" ought to take care of any questions regarding auto
's participation in all of this; my interpretation, then, is that this is inherently a valid redeclaration (and definition) of the x
at global scope with type int
, and that Clang is correct. Even if we propose that auto
does not count as "adjustment of type", since no diagnostic is required, at worst all listed implementations are compliant in their own way.
I believe GCC and Visual Studio are taking the following as inspiration:
[C++11: 7.1.6.4/5]:
A program that usesauto
in a context not explicitly allowed in this section is ill-formed.
…but I think that this is short-sighted. It seems unlikely that the standard language is intended to prohibit the usual redeclaration rules, just because they are not repeated or explicitly referenced from within 7.1.6.4
.
C++14 adds wording that relates to declarations of functions with deduced types:
[C++14: 7.1.6.4/13]:
Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type. [..]
By symmetry one might suggest that, in your int
case, it is intended that GCC and VS be correct in rejecting the program. However, this is a different feature (since deduction cannot be applied to mere declarations) and thus a different scenario.
Either way, improved standard wording would help here. I consider it a [reasonably minor] editorial defect.
Note
I answered a question that was closed a duplicate of this one. I asked for merge and was told instead to provide an answer here. See below for my original answer.
Update clang is correct
I asked this question on twitter and the response I received from Richard Smith was as follows:
Not a defect, it's intentional that this restriction applies only to deduced return types and not to variable types. For variables, it's just a convenience shorthand, but return type deduction affects something more fundamental about functions (and especially function templates).
So the logic is that this is allowed by [dcl.spec.auto]
and to restrict this for deduced return types paragraph [dcl.spec.auto]p11
was added to the section. Otherwise there is no restriction and therefore this is not restricted for the variables case.
Original
Currently [dcl.spec.auto]
does not seem to cover this case explictly but it does say in [dcl.spec.auto]p5:
A program that uses auto or decltype(auto) in a context not explicitly allowed in this subclause is ill-formed.
and we can see it makes a similar case for functions ill-formed in [dcl.spec.auto]p11:
Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type. Similarly, redeclarations or specializations of a function or function template with a declared return type that does not use a placeholder type shall not use a placeholder. [ Example:
auto f(); auto f() { return 42; } // return type is int auto f(); // OK int f(); // error, cannot be overloaded with auto f()
....
So although this could use clarification as currently worded it feels like gcc is correct and this is ill-formed.