[cfe-commits] r102673 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/SemaTemplate/nested-name-spec-template.cpp test/SemaTemplate/typename-specifier-4.cpp

John McCall rjmccall at apple.com
Thu Apr 29 16:50:39 PDT 2010


Author: rjmccall
Date: Thu Apr 29 18:50:39 2010
New Revision: 102673

URL: http://llvm.org/viewvc/llvm-project?rev=102673&view=rev
Log:
Rebuild the nested name specifiers in member-pointer declarator chunks when
entering the current instantiation.  Set up a little to preserve type location
information for typename types while we're in there.

Fixes a Boost failure.


Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp
    cfe/trunk/test/SemaTemplate/typename-specifier-4.cpp

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=102673&r1=102672&r2=102673&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Apr 29 18:50:39 2010
@@ -3082,9 +3082,10 @@
                              const IdentifierInfo &II,
                              SourceRange Range);
 
-  QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
-                                             DeclarationName Name);
-  void RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS);
+  TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
+                                                    SourceLocation Loc,
+                                                    DeclarationName Name);
+  bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS);
 
   std::string
   getTemplateArgumentBindingsText(const TemplateParameterList *Params,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=102673&r1=102672&r2=102673&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Apr 29 18:50:39 2010
@@ -1922,6 +1922,71 @@
   return true;
 }
 
+/// NeedsRebuildingInCurrentInstantiation - Checks whether the given
+/// declarator needs to be rebuilt in the current instantiation.
+/// Any bits of declarator which appear before the name are valid for
+/// consideration here.  That's specifically the type in the decl spec
+/// and the base type in any member-pointer chunks.
+static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
+                                                    DeclarationName Name) {
+  // The types we specifically need to rebuild are:
+  //   - typenames, typeofs, and decltypes
+  //   - types which will become injected class names
+  // Of course, we also need to rebuild any type referencing such a
+  // type.  It's safest to just say "dependent", but we call out a
+  // few cases here.
+
+  DeclSpec &DS = D.getMutableDeclSpec();
+  switch (DS.getTypeSpecType()) {
+  case DeclSpec::TST_typename:
+  case DeclSpec::TST_typeofType:
+  case DeclSpec::TST_typeofExpr:
+  case DeclSpec::TST_decltype: {
+    // Grab the type from the parser.
+    TypeSourceInfo *TSI = 0;
+    QualType T = S.GetTypeFromParser(DS.getTypeRep(), &TSI);
+    if (T.isNull() || !T->isDependentType()) break;
+
+    // Make sure there's a type source info.  This isn't really much
+    // of a waste; most dependent types should have type source info
+    // attached already.
+    if (!TSI)
+      TSI = S.Context.getTrivialTypeSourceInfo(T, DS.getTypeSpecTypeLoc());
+
+    // Rebuild the type in the current instantiation.
+    TSI = S.RebuildTypeInCurrentInstantiation(TSI, D.getIdentifierLoc(), Name);
+    if (!TSI) return true;
+
+    // Store the new type back in the decl spec.
+    QualType LocType = S.CreateLocInfoType(TSI->getType(), TSI);
+    DS.UpdateTypeRep(LocType.getAsOpaquePtr());
+    break;
+  }
+
+  default:
+    // Nothing to do for these decl specs.
+    break;
+  }
+
+  // It doesn't matter what order we do this in.
+  for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {
+    DeclaratorChunk &Chunk = D.getTypeObject(I);
+
+    // The only type information in the declarator which can come
+    // before the declaration name is the base type of a member
+    // pointer.
+    if (Chunk.Kind != DeclaratorChunk::MemberPointer)
+      continue;
+
+    // Rebuild the scope specifier in-place.
+    CXXScopeSpec &SS = Chunk.Mem.Scope();
+    if (S.RebuildNestedNameSpecifierInCurrentInstantiation(SS))
+      return true;
+  }
+
+  return false;
+}
+
 Sema::DeclPtrTy
 Sema::HandleDeclarator(Scope *S, Declarator &D,
                        MultiTemplateParamsArg TemplateParamLists,
@@ -1944,35 +2009,47 @@
          (S->getFlags() & Scope::TemplateParamScope) != 0)
     S = S->getParent();
 
-  // If this is an out-of-line definition of a member of a class template
-  // or class template partial specialization, we may need to rebuild the
-  // type specifier in the declarator. See RebuildTypeInCurrentInstantiation()
-  // for more information.
-  // FIXME: cope with decltype(expr) and typeof(expr) once the rebuilder can
-  // handle expressions properly.
-  DeclSpec &DS = const_cast<DeclSpec&>(D.getDeclSpec());
-  if (D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid() &&
-      isDependentScopeSpecifier(D.getCXXScopeSpec()) &&
-      (DS.getTypeSpecType() == DeclSpec::TST_typename ||
-       DS.getTypeSpecType() == DeclSpec::TST_typeofType ||
-       DS.getTypeSpecType() == DeclSpec::TST_typeofExpr ||
-       DS.getTypeSpecType() == DeclSpec::TST_decltype)) {
-    if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) {
-      // FIXME: Preserve type source info.
-      QualType T = GetTypeFromParser(DS.getTypeRep());
-
-      DeclContext *SavedContext = CurContext;
-      CurContext = DC;
-      T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name);
-      CurContext = SavedContext;
+  DeclContext *DC = CurContext;
+  if (D.getCXXScopeSpec().isInvalid())
+    D.setInvalidType();
+  else if (D.getCXXScopeSpec().isSet()) {
+    bool EnteringContext = !D.getDeclSpec().isFriendSpecified();
+    DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext);
+    if (!DC) {
+      // If we could not compute the declaration context, it's because the
+      // declaration context is dependent but does not refer to a class,
+      // class template, or class template partial specialization. Complain
+      // and return early, to avoid the coming semantic disaster.
+      Diag(D.getIdentifierLoc(),
+           diag::err_template_qualified_declarator_no_match)
+        << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
+        << D.getCXXScopeSpec().getRange();
+      return DeclPtrTy();
+    }
+
+    bool IsDependentContext = DC->isDependentContext();
 
-      if (T.isNull())
-        return DeclPtrTy();
-      DS.UpdateTypeRep(T.getAsOpaquePtr());
+    if (!IsDependentContext && 
+        RequireCompleteDeclContext(D.getCXXScopeSpec()))
+      return DeclPtrTy();
+
+    if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) {
+      Diag(D.getIdentifierLoc(),
+           diag::err_member_def_undefined_record)
+        << Name << DC << D.getCXXScopeSpec().getRange();
+      D.setInvalidType();
+    }
+
+    // Check whether we need to rebuild the type of the given
+    // declaration in the current instantiation.
+    if (EnteringContext && IsDependentContext &&
+        TemplateParamLists.size() != 0) {
+      ContextRAII SavedContext(*this, DC);
+      if (RebuildDeclaratorInCurrentInstantiation(*this, D, Name))
+        D.setInvalidType();
     }
   }
 
-  DeclContext *DC;
   NamedDecl *New;
 
   TypeSourceInfo *TInfo = 0;
@@ -1982,10 +2059,7 @@
                         ForRedeclaration);
 
   // See if this is a redefinition of a variable in the same scope.
-  if (D.getCXXScopeSpec().isInvalid()) {
-    DC = CurContext;
-    D.setInvalidType();
-  } else if (!D.getCXXScopeSpec().isSet()) {
+  if (!D.getCXXScopeSpec().isSet()) {
     bool IsLinkageLookup = false;
 
     // If the declaration we're planning to build will be a function
@@ -2006,34 +2080,8 @@
     if (IsLinkageLookup)
       Previous.clear(LookupRedeclarationWithLinkage);
 
-    DC = CurContext;
     LookupName(Previous, S, /* CreateBuiltins = */ IsLinkageLookup);
   } else { // Something like "int foo::x;"
-    DC = computeDeclContext(D.getCXXScopeSpec(), true);
-
-    if (!DC) {
-      // If we could not compute the declaration context, it's because the
-      // declaration context is dependent but does not refer to a class,
-      // class template, or class template partial specialization. Complain
-      // and return early, to avoid the coming semantic disaster.
-      Diag(D.getIdentifierLoc(),
-           diag::err_template_qualified_declarator_no_match)
-        << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
-        << D.getCXXScopeSpec().getRange();
-      return DeclPtrTy();
-    }
-
-    if (!DC->isDependentContext() && 
-        RequireCompleteDeclContext(D.getCXXScopeSpec()))
-      return DeclPtrTy();
-
-    if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) {
-      Diag(D.getIdentifierLoc(),
-           diag::err_member_def_undefined_record)
-        << Name << DC << D.getCXXScopeSpec().getRange();
-      D.setInvalidType();
-    }
-    
     LookupQualifiedName(Previous, DC);
 
     // Don't consider using declarations as previous declarations for

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=102673&r1=102672&r2=102673&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Apr 29 18:50:39 2010
@@ -5165,6 +5165,20 @@
   return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
 }
 
+static void FillTypeLoc(DependentNameTypeLoc TL,
+                        SourceLocation TypenameLoc,
+                        SourceRange QualifierRange) {
+  // FIXME: typename, qualifier range
+  TL.setNameLoc(TypenameLoc);
+}
+
+static void FillTypeLoc(QualifiedNameTypeLoc TL,
+                        SourceLocation TypenameLoc,
+                        SourceRange QualifierRange) {
+  // FIXME: typename, qualifier range
+  TL.setNameLoc(TypenameLoc);
+}
+
 Sema::TypeResult
 Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
                         const IdentifierInfo &II, SourceLocation IdLoc) {
@@ -5177,7 +5191,19 @@
                                  SourceRange(TypenameLoc, IdLoc));
   if (T.isNull())
     return true;
-  return T.getAsOpaquePtr();
+
+  TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
+  if (isa<DependentNameType>(T)) {
+    DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+    // FIXME: fill inner type loc
+    FillTypeLoc(TL, TypenameLoc, SS.getRange());
+  } else {
+    QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+    // FIXME: fill inner type loc
+    FillTypeLoc(TL, TypenameLoc, SS.getRange());
+  }
+  
+  return CreateLocInfoType(T, TSI).getAsOpaquePtr();
 }
 
 Sema::TypeResult
@@ -5196,11 +5222,21 @@
     // track of the nested-name-specifier.
 
     // FIXME: Note that the QualifiedNameType had the "typename" keyword!
-    return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
+    
+    T = Context.getQualifiedNameType(NNS, T);
+    TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
+    QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+    // FIXME: fill inner type loc
+    FillTypeLoc(TL, TypenameLoc, SS.getRange());
+    return CreateLocInfoType(T, TSI).getAsOpaquePtr();
   }
 
-  return Context.getDependentNameType(ETK_Typename, NNS, TemplateId)
-                                                            .getAsOpaquePtr();
+  T = Context.getDependentNameType(ETK_Typename, NNS, TemplateId);
+  TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
+  DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+  // FIXME: fill inner type loc
+  FillTypeLoc(TL, TypenameLoc, SS.getRange());
+  return CreateLocInfoType(T, TSI).getAsOpaquePtr();
 }
 
 /// \brief Build the type that describes a C++ typename specifier,
@@ -5419,24 +5455,28 @@
 /// in X<T> and returning a QualifiedNameType whose canonical type is the same
 /// as the canonical type of T*, allowing the return types of the out-of-line
 /// definition and the declaration to match.
-QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
-                                                 DeclarationName Name) {
-  if (T.isNull() || !T->isDependentType())
+TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
+                                                        SourceLocation Loc,
+                                                        DeclarationName Name) {
+  if (!T || !T->getType()->isDependentType())
     return T;
 
   CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name);
   return Rebuilder.TransformType(T);
 }
 
-void Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) {
-  if (SS.isInvalid()) return;
+bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) {
+  if (SS.isInvalid()) return true;
 
   NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
   CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(),
                                           DeclarationName());
   NestedNameSpecifier *Rebuilt = 
     Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange());
-  if (Rebuilt) SS.setScopeRep(Rebuilt);
+  if (!Rebuilt) return true;
+
+  SS.setScopeRep(Rebuilt);
+  return false;
 }
 
 /// \brief Produces a formatted string that describes the binding of

Modified: cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp?rev=102673&r1=102672&r2=102673&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp Thu Apr 29 18:50:39 2010
@@ -51,3 +51,16 @@
   typedef typename N::template B<T>::type type; // expected-error{{'B' following the 'template' keyword does not refer to a template}} \
                                                 // expected-error{{expected member name}}
 };
+
+// Reduced from a Boost failure.
+namespace test1 {
+  template <class T> struct pair {
+    T x;
+    T y;
+
+    static T pair<T>::* const mem_array[2];
+  };
+
+  template <class T>
+  T pair<T>::* const pair<T>::mem_array[2] = { &pair<T>::x, &pair<T>::y };
+}

Modified: cfe/trunk/test/SemaTemplate/typename-specifier-4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/typename-specifier-4.cpp?rev=102673&r1=102672&r2=102673&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/typename-specifier-4.cpp (original)
+++ cfe/trunk/test/SemaTemplate/typename-specifier-4.cpp Thu Apr 29 18:50:39 2010
@@ -113,6 +113,6 @@
   // FIXME: Improve source location info here.
   template<typename T>
   typename A<T>::type& A<T>::a() { // expected-error{{found in multiple base classes}}
-    return x;  // expected-error{{undeclared identifier}}
+    return x;
   }
 }





More information about the cfe-commits mailing list