16

Is the following allowed by the standard?

#include <iostream>

extern int a;
auto a = 3;

int main(int, char**)
{
    std::cout << a << std::endl;
    return 0;
}

clang accepts the code. g++ complains for conflicting declaration.

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
Jamboree
  • 5,139
  • 2
  • 16
  • 36
  • 1
    Surely this is a g++ bug – M.M May 24 '16 at 08:26
  • This code causes an error also in MS Visual Studio 2012, saying `error C2371: 'a' : redefinition; different basic types`. – nabroyan May 24 '16 at 08:38
  • What about: `extern int a; decltype(a) a;` ;) – Ajay May 24 '16 at 08:53
  • @Ajay That should be fine. Even: extern int a; decltype(a) a = 42; – Arunmu May 24 '16 at 09:24
  • It would be covered by [basic.link]/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, " . It seems hard to argue that `auto` specifies a different type to `int` for `a` , but even if you did argue that then I'm pretty confident in saying that the intent is for this code to be legal – M.M May 24 '16 at 09:34
  • @M.M: yes, provided that resolving auto is an "adjustment of types", and that the bit in parentheses is intended only as an *example* of something that happens during "adjustments of types", and not a *definition* of it. I think that's the difference of opinion between clang and gcc. I don't think the phrase appears anywhere else in the standard (I'm looking at C++11 right now, can't be bothered to check 14 too), so I'd argue that whichever way it was intended, the standard left itself a little open to misinterpretation. I may have missed something though, that makes it precise. – Steve Jessop May 24 '16 at 09:50
  • @SteveJessop either way, the exact texts is "the types...shall be identical". Note that `auto` is not a type so we cannot say "They are not identical because the types `int` and `auto` are different types". The text makes no sense unless you take "the type" to mean "the type deduced by `auto`" – M.M May 24 '16 at 09:54
  • @M.M. yes, I was just about to submit a comment saying the same thing. If it meant it the way gcc reads it then it should say "the types (if any)", or something like that, acknowledging the possibility that one of the two declarations doesn't (yet) have a type because we've refrained from resolving `auto`. In fact maybe I should consider `auto` to be already part of "the type specified by" the second declaration, never mind any "adjustments" :-) – Steve Jessop May 24 '16 at 09:56
  • @SteveJessop Actually my question is inspired by this [question](http://stackoverflow.com/questions/14285198/why-doesnt-the-c11-auto-keyword-work-for-static-members), which is occasionally answered by the same person as the question you linked to. It's interesting that he thinks one is legal and another is not. – Jamboree May 24 '16 at 12:42
  • @M.M Richard Smith agrees this is a gcc bug [see my answer to the other dup here](https://stackoverflow.com/a/52304618/1708801) – Shafik Yaghmour Sep 17 '18 at 04:51

2 Answers2

2

Its not much clear to me from the standard, but then, there is this written

section 7.1.6.4 auto specifier
A program that uses auto in a context not explicitly allowed in this section is ill-formed.

Better read the mentioned section of the standard for all the allowed contexts.

Considering this, I believe g++ is correct and clang is wrong. But I could be wrong, there could be some separate section in standard which might be implying this context, but I could not find it.

Arunmu
  • 6,837
  • 1
  • 24
  • 46
  • 2
    But `auto a = 3;` here is an explicitly allowed context . " This use is allowed when declaring variables in a block (6.3), **in namespace scope** (3.3.6), [...]" – M.M May 24 '16 at 09:36
  • Maybe in the contextual sense (to extern) its not applicable ? Or g++ and clang interpreted it differently as the language of standard seems to be pretty loose in this case. – Arunmu May 24 '16 at 09:59
-2

Edit answer: As mention in the comments. The problem in this case is that writting

external int a;
auto a = 3;

is the same as writting

external int a;
int a = 3;

that means you have a new definition of a and that causes an error.

First answer: For my understanding this breaks parts of the One definition rule. Specifically, I mean the following rule (in reference to MISRA C++ 2008) that says that an identifier with external linkage should always have only one definition. In your example you have a definition in the current file(auto a = 3;) and with external you also refer to a definition in another file.

cpow
  • 476
  • 4
  • 8
  • 6
    In this example, the variable is defined exactly once. There is no odr violation unless `auto a` conflicts with the original declaration. Extern doesn't have to refer to definition in another file. It simply refers to a definition in *some* file. It's OK to define a variable in the same file where it has been declared extern. – eerorika May 24 '16 at 09:08
  • Thats true. But when there is no external definition of 'external int a' then this would be the same as writing: extern int a; int a = 3; which means we have also two definitions – cpow May 24 '16 at 09:25
  • 1
    Jamboree has shown the entire code of the program in the question. There's only one definition of `a` in it. Sure, if you added more definitions by linking this TU against other TUs then you could violate the ODR, but I don't think that's what the question is about since that's nothing to do with `auto`. – Steve Jessop May 24 '16 at 09:28
  • 3
    @cpow `extern int a;` is a declaration, `int a = 3;` is a definition – M.M May 24 '16 at 09:30
  • @cpow: No, that does not mean we have two definitions. It is exactly one declaration and one definition. Hence completely obliges with ODR. – Arunmu May 24 '16 at 09:30
  • 2
    To put it another way, it would be really annoying if files that contain definitions of `extern` names weren't allowed to include the same header file that everyone else is including, containing the `extern` declaration. Fortunately, they are allowed to, and that's all you're seeing here. This is the TU that contains the (one) definition of `a`, and it also has an `extern` declaration of it. – Steve Jessop May 24 '16 at 09:32
  • 1
    ODR is not relevant anyway, we are talking about redeclaration within the same unit. The relevant rule is [basic.link]/10 – M.M May 24 '16 at 09:33
  • @ M.M That´s right. The real problem is redeclaration. I tried to stand that out with my first comment but use the wrong vocabulary. Sorry, my fault. – cpow May 24 '16 at 09:38
  • @cpow `extern int a; int a = 3;` would be correct code. Redeclaration is OK. Redeclaration with a wrong type is not OK. Here, `auto` will be deduced as `int`, which is the correct type but g++ and msvc complain about a **conflicting** declaration. So the question is, may `auto` be used in redeclarations. – eerorika May 24 '16 at 09:42