]> granicus.if.org Git - clang/commitdiff
Handle substitutions into the "first qualifier in scope" of a
authorDouglas Gregor <dgregor@apple.com>
Tue, 20 Oct 2009 05:58:46 +0000 (05:58 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 20 Oct 2009 05:58:46 +0000 (05:58 +0000)
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

lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/TreeTransform.h
test/SemaTemplate/member-template-access-expr.cpp

index 7f8960a2bf48d0b01359452a6619a5c0023c1a6a..75719b0de975f4e15ae35f9296fdc6550c83066e 100644 (file)
@@ -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,
index 7360b8fc7a86028e96d3c6da4ff25079169a27fd..fb0e2b1ae9baf8db36c88aa5bc19de25ffd61c14 100644 (file)
@@ -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()) {
index 9f227c05e1d4566fbf23bb56cbbc6f20a2125b25..0f9f21f339d1cd89cfd7d3184be74fdab653a25f 100644 (file)
@@ -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