diff options
| -rw-r--r-- | clang/lib/Sema/Sema.h | 7 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 160 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 60 | ||||
| -rw-r--r-- | clang/test/SemaTemplate/nested-name-spec-template.cpp | 13 | ||||
| -rw-r--r-- | clang/test/SemaTemplate/typename-specifier-4.cpp | 2 | 
5 files changed, 172 insertions, 70 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 02a86cd94db..4d107b5df24 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -3082,9 +3082,10 @@ public:                               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, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index d125d414e65..7a70c32877c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1922,6 +1922,71 @@ static bool isNearlyMatchingFunction(ASTContext &Context,    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 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,           (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; - -      if (T.isNull()) -        return DeclPtrTy(); -      DS.UpdateTypeRep(T.getAsOpaquePtr()); +  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 (!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 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,                          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 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,      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 diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index ad6cc2f4c86..70a92ca2e7d 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -5165,6 +5165,20 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,    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 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,                                   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 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,      // 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 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,  /// 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 diff --git a/clang/test/SemaTemplate/nested-name-spec-template.cpp b/clang/test/SemaTemplate/nested-name-spec-template.cpp index 1691db74a11..9d25a051e8a 100644 --- a/clang/test/SemaTemplate/nested-name-spec-template.cpp +++ b/clang/test/SemaTemplate/nested-name-spec-template.cpp @@ -51,3 +51,16 @@ struct TestA {    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 }; +} diff --git a/clang/test/SemaTemplate/typename-specifier-4.cpp b/clang/test/SemaTemplate/typename-specifier-4.cpp index 280a1b4c395..8dfb60d7071 100644 --- a/clang/test/SemaTemplate/typename-specifier-4.cpp +++ b/clang/test/SemaTemplate/typename-specifier-4.cpp @@ -113,6 +113,6 @@ namespace PR6463 {    // 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;    }  }  | 

