From: Douglas Gregor Date: Fri, 20 Nov 2009 22:03:38 +0000 (+0000) Subject: Implement C++ [basic.lookup.classref]p3, which states how the type X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f6e6fc801c700c7b8ac202ddbe550d9843a816fc;p=clang Implement C++ [basic.lookup.classref]p3, which states how the type name 'T' is looked up in the expression t.~T() Previously, we weren't looking into the type of "t", and therefore would fail when T actually referred to an injected-class-name. Fixes PR5530. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89493 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 45891bc0c9..018cc14540 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -203,11 +203,15 @@ public: /// this occurs when deriving from "std::vector::allocator_type", where T /// is a template parameter. /// + /// \param ObjectType if we're checking whether an identifier is a type + /// within a C++ member access expression, this will be the type of the + /// /// \returns the type referred to by this identifier, or NULL if the type /// does not name an identifier. virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS = 0, - bool isClassName = false) = 0; + bool isClassName = false, + TypeTy *ObjectType = 0) = 0; /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If @@ -2518,7 +2522,8 @@ public: /// does not name an identifier. virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS, - bool isClassName = false); + bool isClassName = false, + TypeTy *ObjectType = 0); /// isCurrentClassName - Always returns false, because MinimalAction /// does not support C++ classes with constructors. diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 7681eac6ed..aa0b89b1a3 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -144,7 +144,7 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Action::TypeTy * MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc, Scope *S, const CXXScopeSpec *SS, - bool isClassName) { + bool isClassName, TypeTy *ObjectType) { if (TypeNameInfo *TI = II.getFETokenInfo()) if (TI->isTypeName) return TI; diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index b2ecc9e827..145c8616eb 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1010,7 +1010,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // Parse the type-specifier-seq. DeclSpec DS; - if (ParseCXXTypeSpecifierSeq(DS)) + if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType? return true; // Parse the conversion-declarator, which is merely a sequence of @@ -1152,7 +1152,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // Note that this is a destructor name. Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc, - CurScope, &SS); + CurScope, &SS, false, ObjectType); if (!Ty) { if (ObjectType) Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 72039e2756..6e74f9277a 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -533,7 +533,8 @@ public: virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS, - bool isClassName = false); + bool isClassName = false, + TypeTy *ObjectType = 0); virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S); virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b5109f825e..27c491c882 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -66,31 +66,68 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) { /// and then return NULL. Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS, - bool isClassName) { - // C++ [temp.res]p3: - // A qualified-id that refers to a type and in which the - // nested-name-specifier depends on a template-parameter (14.6.2) - // shall be prefixed by the keyword typename to indicate that the - // qualified-id denotes a type, forming an - // elaborated-type-specifier (7.1.5.3). - // - // We therefore do not perform any name lookup if the result would - // refer to a member of an unknown specialization. - if (SS && isUnknownSpecialization(*SS)) { - if (!isClassName) + bool isClassName, + TypeTy *ObjectTypePtr) { + // Determine where we will perform name lookup. + DeclContext *LookupCtx = 0; + if (ObjectTypePtr) { + QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); + if (ObjectType->isRecordType()) + LookupCtx = computeDeclContext(ObjectType); + } else if (SS && SS->isSet()) { + LookupCtx = computeDeclContext(*SS, false); + + if (!LookupCtx) { + if (isDependentScopeSpecifier(*SS)) { + // C++ [temp.res]p3: + // A qualified-id that refers to a type and in which the + // nested-name-specifier depends on a template-parameter (14.6.2) + // shall be prefixed by the keyword typename to indicate that the + // qualified-id denotes a type, forming an + // elaborated-type-specifier (7.1.5.3). + // + // We therefore do not perform any name lookup if the result would + // refer to a member of an unknown specialization. + if (!isClassName) + return 0; + + // We know from the grammar that this name refers to a type, so build a + // TypenameType node to describe the type. + // FIXME: Record somewhere that this TypenameType node has no "typename" + // keyword associated with it. + return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(), + II, SS->getRange()).getAsOpaquePtr(); + } + + return 0; + } + + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS)) return 0; - - // We know from the grammar that this name refers to a type, so build a - // TypenameType node to describe the type. - // FIXME: Record somewhere that this TypenameType node has no "typename" - // keyword associated with it. - return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(), - II, SS->getRange()).getAsOpaquePtr(); } - + LookupResult Result(*this, &II, NameLoc, LookupOrdinaryName); - LookupParsedName(Result, S, SS, false); - + if (LookupCtx) { + // Perform "qualified" name lookup into the declaration context we + // computed, which is either the type of the base of a member access + // expression or the declaration context associated with a prior + // nested-name-specifier. + LookupQualifiedName(Result, LookupCtx); + + if (ObjectTypePtr && Result.empty()) { + // C++ [basic.lookup.classref]p3: + // If the unqualified-id is ~type-name, the type-name is looked up + // in the context of the entire postfix-expression. If the type T of + // the object expression is of a class type C, the type-name is also + // looked up in the scope of class C. At least one of the lookups shall + // find a name that refers to (possibly cv-qualified) T. + LookupName(Result, S); + } + } else { + // Perform unqualified name lookup. + LookupName(Result, S); + } + NamedDecl *IIDecl = 0; switch (Result.getResultKind()) { case LookupResult::NotFound: diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp index 0850c44a36..8f69def9fd 100644 --- a/test/SemaCXX/pseudo-destructors.cpp +++ b/test/SemaCXX/pseudo-destructors.cpp @@ -38,3 +38,12 @@ typedef int Integer; void destroy_without_call(int *ip) { ip->~Integer; // expected-error{{called immediately}} } + +// PR5530 +namespace N1 { + class X0 { }; +} + +void test_X0(N1::X0 &x0) { + x0.~X0(); +}