Skip to content

CWG2634 [dcl.type.elab] p3 The nominated E is not clear in the rule such that implementations have a divergence #80

@xmh0511

Description

@xmh0511

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

[dcl.type.elab] p3 says

Otherwise, an elaborated-type-specifier E shall not have an attribute-specifier-seq. If E contains an identifier but no nested-name-specifier and (unqualified) lookup for the identifier finds nothing, E shall not be introduced by the enum keyword and declares the identifier as a class-name. The target scope of E is the nearest enclosing namespace or block scope.

What does E refer to in the emphasized wording? In this branch, E can refer to the elaborated-type-specifier in the declaration such as friend class-key nested-name-specifier identifier or friend class-key identifier. In other words, the elaborated-type-specifier in a declaration where the elaborated-type-specifier is not the sole constituent. The difference is one has a nested-name-specifier and the other does not.

Presumably, the intent refers to the E that does not have a nested-name-specifier. The other thing is whether the E referred to in the emphasized rule should satisfy the condition "(unqualified) lookup for the identifier finds nothing" or not? If the condition should be satisfied, then the target of E is said to be the nearest enclosing namespace or block scope, this makes [dcl.type.elab] p4 have a circularly definition

Any unqualified lookup for the identifier (in the first case) does not consider scopes that contain the target scope;

Because the definition of the target scope relies on whether the condition that the unqualified lookup for the identifier finds nothing is true, and the consideration of the scopes for the unqualified lookup conversely relies on the target scope.

Example A

See https://godbolt.org/z/TzWbjffxq

#include <tuple>
auto fun(){
    struct C{  // #1
        void show();
        int c;
    };
    {
        class U{
            friend struct C;  // #2  // target scope is the innermost block scope that contains `U`? 
            int u;
        };
        return std::tuple<C,U>{};
    }
}

using Ret = decltype(fun());
using Calias = std::tuple_element<0,Ret>::type;
using Ualias = std::tuple_element<1,Ret>::type;

void Calias::show(){
    c = 10;
    Ualias b;
    b.u = 0;  // GCC rejects it but Clang accepts it. 
}

The intent should be that the type at #1 and the type at #2 is not the same entity since their target scopes are different.

Example B

See https://godbolt.org/z/WG78Goqj5

namespace X{
    namespace C{
        struct F;
    }
    using namespace C;
    class A{
        friend struct F;  // what is the target scope? it's not specified in the current wording
        int c;
    };
    struct C::F{
       void fun(){
          A obj;
          obj.c = 0;  // Clang accepts it but GCC rejects it
       }
    };
}

[dcl.type.elab] p3 did not specify the target scope of E struct F.

The implementations have a divergence treatment in such two examples. Neither of them has a consensus for the same example.

It seems that GCC is right on the first example but not the second while Clang is right on the second example but not the first.

Suggested resolution

change [dcl.type.elab] p3

Otherwise, an elaborated-type-specifier E shall not have an attribute-specifier-seq. If E contains an identifier but no nested-name-specifier and (unqualified) lookup for the identifier finds nothing, E shall not be introduced by the enum keyword and declares the identifier as a class-name; the target scope of such E is the nearest enclosing namespace or block scope. Otherwise, the target scope of E is the scope that is the target scope of the declarations found by the lookup for the terminal name of E.

change [dcl.type.elab] p4

Any unqualified lookup for the identifier (in the first case) does not consider scopes that contain the nearest enclosing namespace or block scope; no name is bound.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions