From: Douglas Gregor Date: Tue, 20 Oct 2009 05:58:46 +0000 (+0000) Subject: Handle substitutions into the "first qualifier in scope" of a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6cd219879ffce00920189ec1dcea927a42602961;p=clang Handle substitutions into the "first qualifier in scope" of a qualified member access expression (e.g., t->U::member) when that first qualifier refers to a template parameters. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84612 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 7f8960a2bf..75719b0de9 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -400,6 +400,10 @@ namespace { /// instantiating it. Decl *TransformDefinition(Decl *D); + /// \bried Transform the first qualifier within a scope by instantiating the + /// declaration. + NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc); + /// \brief Rebuild the exception declaration and register the declaration /// as an instantiated local. VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, @@ -457,6 +461,31 @@ Decl *TemplateInstantiator::TransformDefinition(Decl *D) { return Inst; } +NamedDecl * +TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, + SourceLocation Loc) { + // If the first part of the nested-name-specifier was a template type + // parameter, instantiate that type parameter down to a tag type. + if (TemplateTypeParmDecl *TTPD = dyn_cast_or_null(D)) { + const TemplateTypeParmType *TTP + = cast(getSema().Context.getTypeDeclType(TTPD)); + if (TTP->getDepth() < TemplateArgs.getNumLevels()) { + QualType T = TemplateArgs(TTP->getDepth(), TTP->getIndex()).getAsType(); + if (T.isNull()) + return cast_or_null(TransformDecl(D)); + + if (const TagType *Tag = T->getAs()) + return Tag->getDecl(); + + // The resulting type is not a tag; complain. + getSema().Diag(Loc, diag::err_nested_name_spec_non_tag) << T; + return 0; + } + } + + return cast_or_null(TransformDecl(D)); +} + VarDecl * TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 7360b8fc7a..fb0e2b1ae9 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -236,6 +236,19 @@ public: /// Subclasses may override this function to provide alternate behavior. Decl *TransformDefinition(Decl *D) { return getDerived().TransformDecl(D); } + /// \brief Transform the given declaration, which was the first part of a + /// nested-name-specifier in a member access expression. + /// + /// This specific declaration transformation only applies to the first + /// identifier in a nested-name-specifier of a member access expression, e.g., + /// the \c T in \c x->T::member + /// + /// By default, invokes TransformDecl() to transform the declaration. + /// Subclasses may override this function to provide alternate behavior. + NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc) { + return cast_or_null(getDerived().TransformDecl(D)); + } + /// \brief Transform the given nested-name-specifier. /// /// By default, transforms all of the types and declarations within the @@ -4195,6 +4208,7 @@ TreeTransform::TransformCXXUnresolvedMemberExpr( if (Base.isInvalid()) return SemaRef.ExprError(); + // Start the member reference and compute the object's type. Sema::TypeTy *ObjectType = 0; Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), E->getOperatorLoc(), @@ -4203,12 +4217,12 @@ TreeTransform::TransformCXXUnresolvedMemberExpr( if (Base.isInvalid()) return SemaRef.ExprError(); - // FIXME: The first qualifier found might be a template type parameter, - // in which case there is no transformed declaration to refer to (it might - // refer to a built-in type!). + // Transform the first part of the nested-name-specifier that qualifies + // the member name. NamedDecl *FirstQualifierInScope - = cast_or_null( - getDerived().TransformDecl(E->getFirstQualifierFoundInScope())); + = getDerived().TransformFirstQualifierInScope( + E->getFirstQualifierFoundInScope(), + E->getQualifierRange().getBegin()); NestedNameSpecifier *Qualifier = 0; if (E->getQualifier()) { diff --git a/test/SemaTemplate/member-template-access-expr.cpp b/test/SemaTemplate/member-template-access-expr.cpp index 9f227c05e1..0f9f21f339 100644 --- a/test/SemaTemplate/member-template-access-expr.cpp +++ b/test/SemaTemplate/member-template-access-expr.cpp @@ -24,8 +24,7 @@ struct XDerived : public X { }; void test_f1(XDerived xd) { - // FIXME: Not quite functional yet. -// int &ir = f1(xd); + int &ir = f1(xd); } // PR5213