Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Program with chaining of using-declarations compiles on MSVS and clang but not on GCC

Is the following program well-formed or ill-formed according to the c++ standard?

namespace X { int i; }

namespace Y { using X::i; }

int main() { using X::i; using Y::i; }

I'm getting different results with different compilers:

  • MSVS: Compiles ( http://webcompiler.cloudapp.net/ )
  • Clang: Compiles ( http://melpon.org/wandbox/permlink/KloDufJ5h1DalK4v )
  • GCC: Compile error ( http://melpon.org/wandbox/permlink/IKuuQGE1THofuUTr )

I don't want to fix this program to make it compile on GCC. I just want to know what the c++ standard says about this and why the three compilers behave differently. Also I want to if this is a result of a bug in any of these compilers.

like image 380
Supremum Avatar asked Jul 04 '15 20:07

Supremum


1 Answers

The program should not compile because it declares X::i twice in the same block scope.

C++14 §7.3.3/10:

A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple declarations are allowed. [Example:

namespace A {
    int i;
}

namespace A1 {
    using A::i;
    using A::i;           // OK: double declaration
}

void f() {
    using A::i;
    using A::i;           // error: double declaration
}

Edit: The non-normative comment quoted above, and which I thought answered the question, was there originally in C++98 and has survived through Technical Corrigendum 1 (C++03), C++11 and C++14. But apparently it's wrong. Richard Smith in his answer cites core issue 36 about it, first raised by Andrew Koenig on 2nd August 1998 (less than a month after ANSI approval of the first standard), which apparently means that a known incorrect comment can survive three revisions of the standard.

Citing the core issue itself about that:

C++ Standard Core Language Active Issues, issue 36:

Notes from 04/00 meeting:
The core language working group was unable to come to consensus over what kind of declaration a using-declaration should emulate. In a straw poll, 7 members favored allowing using-declarations wherever a non-definition declaration could appear, while 4 preferred to allow multiple using-eclarations only in namespace scope (the rationale being that the permission for multiple using-declarations is primarily to support its use in multiple header files, which are seldom included anywhere other than namespace scope). John Spicer pointed out that friend declarations can appear multiple times in class scope and asked if using-declarations would have the same property under the "like a declaration" resolution.

As a result of the lack of agreement, the issue was returned to "open" status.

The general discussion of multiple declarations of the same name is in §3.3.1/4 in both C++98 and C++14. As far as I can see the C++14 text is verbatim identical to the original C++98 text. And by itself it allows declaring the same name multiple times in the same declarative region in a number of cases, one of which is that all the declarations refer to the same entity:

C++14 §3.3.1/4:

Given a set of declarations in a single declarative region, each of which specifies the same unqualified name,

  • they shall all refer to the same entity, or all refer to functions and function templates; or

  • exactly one declaration shall declare a class name or enumeration name that is not a typedef name and the other declarations shall all refer to the same variable or enumerator, or all refer to functions and function templates; in this case the class name or enumeration name is hidden (3.3.10). [Note: A namespace name or a class template name must be unique in its declarative region (7.3.2, Clause 14). —end note]

However, the wording here only says what is not directly invalid. A declaration can be disallowed by other rules even if it's not disallowed by this one. For example, there is such a restriction for class member declarations:

C++14 §9.2/1:

[…] A member shall not be declared twice in the member- specification, except that a nested class or member class template can be declared and then later defined, and except that an enumeration can be introduced with an opaque-enum-declaration and later redeclared with an enum-specifier.

I fail to find such a restriction that supports the apparently incorrect comment in C++14 §7.3.3/10 quoted at the start above, i.e. I fail to find any special treatment of block scopes or namespace scopes, and so a tentative conclusion (keeping in mind the comment's survival in spite of being contested already in 1998) is that the contested comment actually is wrong and that this question's code, where two declarations in the same declarative region refer to the same entity, is valid and should be accepted by all compilers.

like image 135
Cheers and hth. - Alf Avatar answered Nov 03 '22 01:11

Cheers and hth. - Alf