diff options
| author | John McCall <rjmccall@apple.com> | 2010-03-25 06:39:04 +0000 | 
|---|---|---|
| committer | John McCall <rjmccall@apple.com> | 2010-03-25 06:39:04 +0000 | 
| commit | 598b4405a663cc1fada596033fdab0c5799a08ea (patch) | |
| tree | 783101c591ffb93a3487e8747c1ca87427793a07 /clang/lib | |
| parent | 169b5b189edde1a6e314662e039c66aa8a85ad9d (diff) | |
| download | bcm5719-llvm-598b4405a663cc1fada596033fdab0c5799a08ea.tar.gz bcm5719-llvm-598b4405a663cc1fada596033fdab0c5799a08ea.zip | |
Properly instantiate friend class template declarations and link them into
the redeclaration chain.  Recommitted from r99477 with a fix:  we need to
merge in default template arguments from previous declarations.
llvm-svn: 99496
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Sema/SemaAccess.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 117 | 
2 files changed, 101 insertions, 26 deletions
| diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index 7e2520c9eee..62b13d4e95b 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -240,13 +240,13 @@ static Sema::AccessResult MatchesFriend(Sema &S,                                          ClassTemplateDecl *Friend) {    Sema::AccessResult OnFailure = Sema::AR_inaccessible; +  // Check whether the friend is the template of a class in the +  // context chain.    for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator           I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {      CXXRecordDecl *Record = *I; -    // Check whether the friend is the template of a class in the -    // context chain.  To do that, we need to figure out whether the -    // current class has a template: +    // Figure out whether the current class has a template:      ClassTemplateDecl *CTD;      // A specialization of the template... @@ -264,6 +264,10 @@ static Sema::AccessResult MatchesFriend(Sema &S,      if (Friend == CTD->getCanonicalDecl())        return Sema::AR_accessible; +    // If the context isn't dependent, it can't be a dependent match. +    if (!EC.isDependent()) +      continue; +      // If the template names don't match, it can't be a dependent      // match.  This isn't true in C++0x because of template aliases.      if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName()) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7b0e88d1634..de6fff7bb91 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -500,21 +500,17 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {      // Hack to make this work almost well pending a rewrite.      if (ND->getDeclContext()->isRecord()) { -      if (!ND->getDeclContext()->isDependentContext()) { -        NewND = SemaRef.FindInstantiatedDecl(D->getLocation(), ND,  -                                             TemplateArgs); -      } else { -        // FIXME: Hack to avoid crashing when incorrectly trying to instantiate -        // templated friend declarations. This doesn't produce a correct AST; -        // however this is sufficient for some AST analysis. The real solution -        // must be put in place during the pending rewrite. See PR5848. -        return 0; -      } +      // FIXME: Hack to avoid crashing when incorrectly trying to instantiate +      // templated friend declarations. This doesn't produce a correct AST; +      // however this is sufficient for some AST analysis. The real solution +      // must be put in place during the pending rewrite. See PR5848. +      return 0;      } else if (D->wasSpecialization()) {        // Totally egregious hack to work around PR5866        return 0; -    } else +    } else {        NewND = Visit(ND); +    }      if (!NewND) return 0;      FU = cast<NamedDecl>(NewND); @@ -641,6 +637,8 @@ namespace {  }  Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { +  bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None); +    // Create a local instantiation scope for this class template, which    // will contain the instantiations of the template parameters.    Sema::LocalInstantiationScope Scope(SemaRef); @@ -650,32 +648,105 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {      return NULL;    CXXRecordDecl *Pattern = D->getTemplatedDecl(); + +  // Instantiate the qualifier.  We have to do this first in case +  // we're a friend declaration, because if we are then we need to put +  // the new declaration in the appropriate context. +  NestedNameSpecifier *Qualifier = Pattern->getQualifier(); +  if (Qualifier) { +    Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier, +                                                 Pattern->getQualifierRange(), +                                                 TemplateArgs); +    if (!Qualifier) return 0; +  } + +  CXXRecordDecl *PrevDecl = 0; +  ClassTemplateDecl *PrevClassTemplate = 0; + +  // If this isn't a friend, then it's a member template, in which +  // case we just want to build the instantiation in the +  // specialization.  If it is a friend, we want to build it in +  // the appropriate context. +  DeclContext *DC = Owner; +  if (isFriend) { +    if (Qualifier) { +      CXXScopeSpec SS; +      SS.setScopeRep(Qualifier); +      SS.setRange(Pattern->getQualifierRange()); +      DC = SemaRef.computeDeclContext(SS); +      if (!DC) return 0; +    } else { +      DC = SemaRef.FindInstantiatedContext(Pattern->getLocation(), +                                           Pattern->getDeclContext(), +                                           TemplateArgs); +    } + +    // Look for a previous declaration of the template in the owning +    // context. +    LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(), +                   Sema::LookupOrdinaryName, Sema::ForRedeclaration); +    SemaRef.LookupQualifiedName(R, DC); + +    if (R.isSingleResult()) { +      PrevClassTemplate = R.getAsSingle<ClassTemplateDecl>(); +      if (PrevClassTemplate) +        PrevDecl = PrevClassTemplate->getTemplatedDecl(); +    } + +    if (!PrevClassTemplate && Qualifier) { +      SemaRef.Diag(Pattern->getLocation(), diag::err_not_tag_in_scope) +        << Pattern->getDeclName() << Pattern->getQualifierRange(); +      return 0; +    } + +    if (PrevClassTemplate) { +      TemplateParameterList *PrevParams +        = PrevClassTemplate->getTemplateParameters(); + +      // Make sure the parameter lists match. +      if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, +                                                  /*Complain=*/true, +                                                  Sema::TPL_TemplateMatch)) +        return 0; + +      // Do some additional validation, then merge default arguments +      // from the existing declarations. +      if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams, +                                             Sema::TPC_ClassTemplate)) +        return 0; +    } +  } +    CXXRecordDecl *RecordInst -    = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner, +    = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), DC,                              Pattern->getLocation(), Pattern->getIdentifier(), -                            Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL, +                            Pattern->getTagKeywordLoc(), PrevDecl,                              /*DelayTypeCreation=*/true); -  // Substitute the nested name specifier, if any. -  if (SubstQualifier(Pattern, RecordInst)) -    return 0; +  if (Qualifier) +    RecordInst->setQualifierInfo(Qualifier, Pattern->getQualifierRange());    ClassTemplateDecl *Inst -    = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), -                                D->getIdentifier(), InstParams, RecordInst, 0); +    = ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(), +                                D->getIdentifier(), InstParams, RecordInst, +                                PrevClassTemplate);    RecordInst->setDescribedClassTemplate(Inst); -  if (D->getFriendObjectKind()) -    Inst->setObjectOfFriendDecl(true); -  else +  if (isFriend) { +    Inst->setObjectOfFriendDecl(PrevClassTemplate != 0); +    // TODO: do we want to track the instantiation progeny of this +    // friend target decl? +  } else {      Inst->setAccess(D->getAccess()); -  Inst->setInstantiatedFromMemberTemplate(D); +    Inst->setInstantiatedFromMemberTemplate(D); +  }    // Trigger creation of the type for the instantiation.    SemaRef.Context.getInjectedClassNameType(RecordInst,                    Inst->getInjectedClassNameSpecialization(SemaRef.Context));    // Finish handling of friends. -  if (Inst->getFriendObjectKind()) { +  if (isFriend) { +    DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false);      return Inst;    } | 

