[cfe-commits] r58916 - in /cfe/trunk: include/clang/AST/DeclBase.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp test/SemaCXX/nested-name-spec.cpp

Douglas Gregor dgregor at apple.com
Tue Nov 18 08:32:12 PST 2008


On Nov 14, 2008, at 5:26 PM, Argiris Kirtzidis wrote:

> Douglas Gregor wrote:
>>
>>> +  /// PreDeclaratorDC - Keeps the declaration context before  
>>> switching to the
>>> +  /// context of a declarator's nested-name-specifier.
>>> +  DeclContext *PreDeclaratorDC;
>>
>> I assume that we'll eventually need this to be a stack of  
>> DeclContext *'s, to deal with something like:
>>
>>    ::foo::bar<wibble::wonka>::type
>>
>> Perhaps we should just make it a stack now so we're ready for the  
>> future.
>
> I prefer to avoid a stack, if it's possible, in favor of stricter  
> invariants of how DeclContext changes.
> In your particular example I don't think a stack is required, it's  
> just nested-name-specifier parsing which doesn't change Sema's  
> CurContext (wibble::wonka isn't looked up in the context of ::foo,  
> right ?)

Oh, I see now. I was convinced that CurContext was changing more often  
than it is. I think you're right that we don't need the stack.

>
>>
>>> +namespace {
>>> +  Decl *LookupNestedName(DeclContext *LookupCtx, bool  
>>> LookInParentCtx,
>>> +                         const IdentifierInfo &II, bool  
>>> &IdIsUndeclared) {
>>>
>>> +    IdentifierResolver::iterator
>>> +      I = IdentifierResolver::begin(&II, LookupCtx,  
>>> LookInParentCtx),
>>> +      E = IdentifierResolver::end();
>>> +
>>> +    if (I == E) {
>>> +      IdIsUndeclared = true;
>>> +      return 0;
>>> +    }
>>> +    IdIsUndeclared = false;
>>> +
>>> +    // C++ 3.4.3p1 :
>>> +    // During the lookup for a name preceding the :: scope  
>>> resolution operator,
>>> +    // object, function, and enumerator names are ignored. If the  
>>> name found is
>>> +    // not a class-name or namespace-name, the program is ill- 
>>> formed.
>>> +
>>> +    for (; I != E; ++I) {
>>> +      if (TypedefDecl *TD = dyn_cast<TypedefDecl>(*I)) {
>>> +        if (TD->getUnderlyingType()->isRecordType())
>>> +          break;
>>> +        continue;
>>> +      }
>>> +      if (((*I)->getIdentifierNamespace()&Decl::IDNS_Tag) && ! 
>>> isa<EnumDecl>(*I))
>>> +        break;
>>> +    }
>>
>> I don't think this is quite right for C++03. The standard says that  
>> we ignore enumerator names (e.g., an EnumConstantDecl), but the  
>> check in the "if" is skipping enumeration names (EnumDecl). Here's  
>> an example where it matters:
>>
>> namespace N {
>>  struct C {
>>    static float X;
>>  };
>>
>>  typedef C Typedef;
>>
>>  namespace M {
>>    enum E {
>>      X = 17
>>    };
>>
>>    typedef E Typedef;
>>
>>    void test() {
>>      float& f = Typedef::X;
>>    }
>>  }
>> }
>>
>> GCC rejects this example:
>>
>> /Users/dgregor/foo.C: In function ‘void N::M::test()’:
>> /Users/dgregor/foo.C:16: error: ‘Typedef’ is not a class or  
>> namespace
>>
>> Interestingly, EDG accepts the example, and so does Clang, but I'm  
>> pretty certain that both are wrong. Qualified name lookup should  
>> find the typedef for the enumeration 'E', and then fail because we  
>> can't do qualified name lookup into an enumeration type in C++03.
>
> MSVC and Comeau also accept the example. I find this weird, I  
> thought EDG and Comeau have a high standard-conformance reputation;

Comeau uses the EDG front end. EDG does have a reputation as being the  
most conforming C++ implementation, but they make mistakes, too :)

> and that the enumeration is ignored because enumerations don't  
> participate in qualified name lookup.

That isn't the way I read C++03 3.4.3p1. The second sentence says:

	"During the lookup for a name preceding the::scope resolution  
operator, object, function, and enumerator names are ignored."

An enumeration name is not an operator, object, function, or  
enumerator name, so we shouldn't be ignoring them.

>
>> In C++0x, we *can* do qualified name lookup into an enumeration, so  
>> the example fails because we can't bind an 'int' to a reference to  
>> a 'float'.
>
> I was under the impression that this happens to 'enum class' which  
> is different from 'enum'. You can do qualified name lookup even with  
> simple enums (not 'enum class') ?

Yes. The C++0x 3.4.3p1 says:

	"The name of a class, concept map (but not a concept), or namespace  
member or enumerator can be referred
to after the :: scope resolution operator (5.1) applied to a nested- 
name-specifier that nominates its class,
concept map, namespace, or enumeration."

Note that it says "enumeration" not "scoped enumeration". See also C+ 
+03 7.2p11, which gives an example of a qualified-id that refers to an  
enumerator of an unscoped enumeration type.

	- Doug




More information about the cfe-commits mailing list