aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-10-20 05:58:46 +0000
committerDouglas Gregor <dgregor@apple.com>2009-10-20 05:58:46 +0000
commit6cd219879ffce00920189ec1dcea927a42602961 (patch)
treecbaf0d413a75df7af09ee3f907fb3bbc020b0d07
parent8f99993856b4647a094bf1c2b703c4acc003f577 (diff)
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
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp29
-rw-r--r--lib/Sema/TreeTransform.h24
-rw-r--r--test/SemaTemplate/member-template-access-expr.cpp3
3 files changed, 49 insertions, 7 deletions
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<TemplateTypeParmDecl>(D)) {
+ const TemplateTypeParmType *TTP
+ = cast<TemplateTypeParmType>(getSema().Context.getTypeDeclType(TTPD));
+ if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
+ QualType T = TemplateArgs(TTP->getDepth(), TTP->getIndex()).getAsType();
+ if (T.isNull())
+ return cast_or_null<NamedDecl>(TransformDecl(D));
+
+ if (const TagType *Tag = T->getAs<TagType>())
+ 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<NamedDecl>(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<NamedDecl>(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<Derived>::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<Derived>::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<NamedDecl>(
- 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<X>(xd);
+ int &ir = f1<X>(xd);
}
// PR5213