From c96be1ea33cdf63d07cec48d18fe8e3afea48f8d Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 27 Apr 2010 18:19:34 +0000 Subject: [PATCH] During template instantiation, set the naming class of UnresolvedLookupExpr and UnresolvedMemberExpr by substituting the naming class we computed when building the expression in the template... ... which we didn't always do correctly. Teach UnresolvedMemberExpr::getNamingClass() all about the new representation of injected-class-names in templates, so that it can return a naming class that is the current instantiation. Also, when decomposing a template-id into its template name and its arguments, be sure to set the naming class on the LookupResult structure. Fixes PR6947 the right way. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102448 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Type.h | 5 +++++ lib/AST/ExprCXX.cpp | 16 ++++++++-------- lib/AST/Type.cpp | 10 ++++++++++ lib/Sema/SemaExpr.cpp | 24 ++++++++++++++++++++++++ lib/Sema/TreeTransform.h | 37 ++++++++++--------------------------- 5 files changed, 57 insertions(+), 35 deletions(-) diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 5f5377414d..7eb332bd95 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -923,6 +923,11 @@ public: const ObjCInterfaceType *getAsObjCQualifiedInterfaceType() const; const CXXRecordDecl *getCXXRecordDeclForPointerType() const; + /// \brief Retrieves the CXXRecordDecl that this type refers to, either + /// because the type is a RecordType or because it is the injected-class-name + /// type of a class template or class template partial specialization. + CXXRecordDecl *getAsCXXRecordDecl() const; + // Member-template getAs'. This scheme will eventually // replace the specific getAsXXXX methods above. // diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 5f908096bb..c394e476f8 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -728,15 +728,15 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { // If there was a nested name specifier, it names the naming class. // It can't be dependent: after all, we were actually able to do the // lookup. - const RecordType *RT; + CXXRecordDecl *Record = 0; if (getQualifier()) { Type *T = getQualifier()->getAsType(); assert(T && "qualifier in member expression does not name type"); - RT = T->getAs(); - assert(RT && "qualifier in member expression does not name record"); - + Record = T->getAsCXXRecordDecl(); + assert(Record && "qualifier in member expression does not name record"); + } // Otherwise the naming class must have been the base class. - } else { + else { QualType BaseType = getBaseType().getNonReferenceType(); if (isArrow()) { const PointerType *PT = BaseType->getAs(); @@ -744,11 +744,11 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { BaseType = PT->getPointeeType(); } - RT = BaseType->getAs(); - assert(RT && "base of member expression does not name record"); + Record = BaseType->getAsCXXRecordDecl(); + assert(Record && "base of member expression does not name record"); } - return cast(RT->getDecl()); + return Record; } Stmt::child_iterator UnresolvedMemberExpr::child_begin() { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 52ee60b984..05e7fdc49e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -415,6 +415,16 @@ const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const { return 0; } +CXXRecordDecl *Type::getAsCXXRecordDecl() const { + if (const RecordType *RT = getAs()) + return dyn_cast(RT->getDecl()); + else if (const InjectedClassNameType *Injected + = getAs()) + return Injected->getDecl(); + + return 0; +} + bool Type::isIntegerType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 088ca96edd..997b8f8dcb 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1063,6 +1063,15 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, if (TemplateArgs) { // Just re-use the lookup done by isTemplateName. DecomposeTemplateName(R, Id); + + // Re-derive the naming class. + if (SS.isSet()) { + NestedNameSpecifier *Qualifier + = static_cast(SS.getScopeRep()); + if (const Type *Ty = Qualifier->getAsType()) + if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl()) + R.setNamingClass(NamingClass); + } } else { bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); LookupParsedName(R, S, &SS, !IvarLookupFollowUp); @@ -3231,6 +3240,21 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, if (TemplateArgs) { // Re-use the lookup done for the template name. DecomposeTemplateName(R, Id); + + // Re-derive the naming class. + if (SS.isSet()) { + NestedNameSpecifier *Qualifier + = static_cast(SS.getScopeRep()); + if (const Type *Ty = Qualifier->getAsType()) + if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl()) + R.setNamingClass(NamingClass); + } else { + QualType BaseType = Base->getType(); + if (const PointerType *Ptr = BaseType->getAs()) + BaseType = Ptr->getPointeeType(); + if (CXXRecordDecl *NamingClass = BaseType->getAsCXXRecordDecl()) + R.setNamingClass(NamingClass); + } } else { Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, SS, ObjCImpDecl); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 2f36807659..cca14caa44 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -5336,19 +5336,16 @@ TreeTransform::TransformUnresolvedLookupExpr( SS.setScopeRep(Qualifier); SS.setRange(Old->getQualifierRange()); - - // If this nested-name-specifier refers to a class type, that is the - // naming class. - if (const Type *NamedType = Qualifier->getAsType()) - if (const RecordType *NamedRecord = NamedType->getAs()) - R.setNamingClass(cast(NamedRecord->getDecl())); - } else if (Old->getNamingClass()) { + } + + if (Old->getNamingClass()) { CXXRecordDecl *NamingClass = cast_or_null(getDerived().TransformDecl( Old->getNameLoc(), Old->getNamingClass())); if (!NamingClass) return SemaRef.ExprError(); + R.setNamingClass(NamingClass); } @@ -5735,7 +5732,6 @@ TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) BaseType = getDerived().TransformType(Old->getBaseType()); } - CXXRecordDecl *NamingClass = 0; NestedNameSpecifier *Qualifier = 0; if (Old->getQualifier()) { Qualifier @@ -5743,12 +5739,6 @@ TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) Old->getQualifierRange()); if (Qualifier == 0) return SemaRef.ExprError(); - - // If this nested-name-specifier refers to a class type, that is the - // naming class. - if (const Type *NamedType = Qualifier->getAsType()) - if (const RecordType *NamedRecord = NamedType->getAs()) - NamingClass = cast(NamedRecord->getDecl()); } LookupResult R(SemaRef, Old->getMemberName(), Old->getMemberLoc(), @@ -5783,24 +5773,17 @@ TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) R.resolveKind(); - // Determine the naming class, if we haven't already. - if (!NamingClass) { - QualType T = BaseType; - if (const PointerType *PointerTy = T->getAs()) - T = PointerTy->getPointeeType(); - if (const RecordType *NamedRecord = T->getAs()) - NamingClass = cast(NamedRecord->getDecl()); - } - - if (!NamingClass && Old->getNamingClass()) { - NamingClass = cast_or_null(getDerived().TransformDecl( + // Determine the naming class. + if (!Old->getNamingClass()) { + CXXRecordDecl *NamingClass + = cast_or_null(getDerived().TransformDecl( Old->getMemberLoc(), Old->getNamingClass())); if (!NamingClass) return SemaRef.ExprError(); - } - if (NamingClass) + R.setNamingClass(NamingClass); + } TemplateArgumentListInfo TransArgs; if (Old->hasExplicitTemplateArgs()) { -- 2.40.0