diff options
| author | John McCall <rjmccall@apple.com> | 2009-09-08 17:47:29 +0000 | 
|---|---|---|
| committer | John McCall <rjmccall@apple.com> | 2009-09-08 17:47:29 +0000 | 
| commit | d8fe9af3a2e8916f7b528f72f35643ab4a9acf68 (patch) | |
| tree | 7f83f4faae5610e595195642182dbe012967cdd1 /clang/lib | |
| parent | 05b2f10e57afaed38209c558b2f48153c321cd6e (diff) | |
| download | bcm5719-llvm-d8fe9af3a2e8916f7b528f72f35643ab4a9acf68.tar.gz bcm5719-llvm-d8fe9af3a2e8916f7b528f72f35643ab4a9acf68.zip | |
Support templateids in friend declarations.  Fixes bug 4859.
llvm-svn: 81233
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 23 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 11 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 96 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 44 | 
4 files changed, 93 insertions, 81 deletions
| diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index c82f6a41147..55c7c85fa68 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -651,26 +651,27 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,                                               TemplateId->RAngleLoc,                                                Attr);      } else if (TUK == Action::TUK_Reference || TUK == Action::TUK_Friend) { -      Action::TypeResult TypeResult = -        Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), -                                    TemplateId->TemplateNameLoc, -                                    TemplateId->LAngleLoc, -                                    TemplateArgsPtr, -                                    TemplateId->getTemplateArgLocations(), -                                    TemplateId->RAngleLoc, -                                    TagType, StartLoc); +      Action::TypeResult Type +        = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), +                                      TemplateId->TemplateNameLoc, +                                      TemplateId->LAngleLoc, +                                      TemplateArgsPtr, +                                      TemplateId->getTemplateArgLocations(), +                                      TemplateId->RAngleLoc); + +      Type = Actions.ActOnTagTemplateIdType(Type, TUK, TagType, StartLoc);        TemplateId->Destroy(); -      if (TypeResult.isInvalid()) { +      if (Type.isInvalid()) {          DS.SetTypeSpecError();          return;        } -   +        const char *PrevSpec = 0;        unsigned DiagID;        if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, PrevSpec, -                             DiagID, TypeResult.get())) +                             DiagID, Type.get()))          Diag(StartLoc, DiagID) << PrevSpec;        return; diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index a040a0f169e..7c4bcab2deb 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2401,10 +2401,13 @@ public:                        SourceLocation LAngleLoc,                        ASTTemplateArgsPtr TemplateArgs,                        SourceLocation *TemplateArgLocs, -                      SourceLocation RAngleLoc, -                      DeclSpec::TST TagSpec, -                      SourceLocation TagLoc); -   +                      SourceLocation RAngleLoc); + +  virtual TypeResult ActOnTagTemplateIdType(TypeResult Type, +                                            TagUseKind TUK, +                                            DeclSpec::TST TagSpec, +                                            SourceLocation TagLoc); +        OwningExprResult BuildTemplateIdExpr(TemplateName Template,                                         SourceLocation TemplateNameLoc,                                         SourceLocation LAngleLoc, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c37ff10941c..1c7157c2c0e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3917,61 +3917,60 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S,    assert(DS.isFriendSpecified());    assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified); -  // Check to see if the decl spec was syntactically like "struct foo". -  RecordDecl *RD = NULL; - -  switch (DS.getTypeSpecType()) { -  case DeclSpec::TST_class: -  case DeclSpec::TST_struct: -  case DeclSpec::TST_union: -    RD = dyn_cast_or_null<CXXRecordDecl>((Decl*) DS.getTypeRep()); -    if (!RD) return DeclPtrTy(); - -    // The parser doesn't quite handle -    //   friend class A {} -    // as we'd like, because it might have been the (valid) prefix of -    //   friend class A {} foo(); -    // So even in C++0x mode we don't want to  -    IsDefinition |= RD->isDefinition(); -    break; - -  default: break; -  } - -  FriendDecl::FriendUnion FU = RD; +  // Try to convert the decl specifier to a type. +  bool invalid = false; +  QualType T = ConvertDeclSpecToType(DS, Loc, invalid); +  if (invalid) return DeclPtrTy();    // C++ [class.friend]p2:    //   An elaborated-type-specifier shall be used in a friend declaration    //   for a class.*    //   * The class-key of the elaborated-type-specifier is required. -  // So if we didn't get a record decl above, we're invalid in C++98 mode. -  if (!RD) { -    bool invalid = false; -    QualType T = ConvertDeclSpecToType(DS, Loc, invalid); -    if (invalid) return DeclPtrTy(); -     +  // This is one of the rare places in Clang where it's legitimate to +  // ask about the "spelling" of the type. +  if (!getLangOptions().CPlusPlus0x && !isa<ElaboratedType>(T)) { +    // If we evaluated the type to a record type, suggest putting +    // a tag in front.      if (const RecordType *RT = T->getAs<RecordType>()) { -      FU = RD = cast<CXXRecordDecl>(RT->getDecl()); -       -      // Untagged typenames are invalid prior to C++0x, but we can -      // suggest an easy fix which should work. -      if (!getLangOptions().CPlusPlus0x) { -        Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type) -          << (RD->isUnion()) -          << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(), -                                        RD->isUnion() ? " union" : " class"); -        return DeclPtrTy(); -      } -    }else if (!getLangOptions().CPlusPlus0x) { -      Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend) -          << DS.getSourceRange(); +      RecordDecl *RD = RT->getDecl(); + +      std::string InsertionText = std::string(" ") + RD->getKindName(); + +      Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type) +        << (RD->isUnion()) +        << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(), +                                                 InsertionText);        return DeclPtrTy();      }else { -      FU = T.getTypePtr(); +      Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend) +          << DS.getSourceRange(); +      return DeclPtrTy();            }    } -  assert(FU && "should have a friend decl/type by here!"); +  FriendDecl::FriendUnion FU = T.getTypePtr(); + +  // The parser doesn't quite handle +  //   friend class A { ... } +  // optimally, because it might have been the (valid) prefix of +  //   friend class A { ... } foo(); +  // So in a very particular set of circumstances, we need to adjust +  // IsDefinition. +  // +  // Also, if we made a RecordDecl in ActOnTag, we want that to be the +  // object of our friend declaration. +  switch (DS.getTypeSpecType()) { +  default: break; +  case DeclSpec::TST_class: +  case DeclSpec::TST_struct: +  case DeclSpec::TST_union: +    CXXRecordDecl *RD = cast_or_null<CXXRecordDecl>((Decl*) DS.getTypeRep()); +    if (RD) { +      IsDefinition |= RD->isDefinition(); +      FU = RD; +    } +    break; +  }    // C++ [class.friend]p2: A class shall not be defined inside    //   a friend declaration. @@ -3986,11 +3985,10 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S,    // But that's a silly restriction which nobody implements for    // inner classes, and C++0x removes it anyway, so we only report    // this (as a warning) if we're being pedantic. -  if (!getLangOptions().CPlusPlus0x) { -    assert(RD && "must have a record decl in C++98 mode"); -    if (RD->getDeclContext() == CurContext) -      Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class); -  } +  if (!getLangOptions().CPlusPlus0x) +    if (const RecordType *RT = T->getAs<RecordType>()) +      if (RT->getDecl()->getDeclContext() == CurContext) +        Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);    FriendDecl *FD = FriendDecl::Create(Context, CurContext, Loc, FU,                                        DS.getFriendSpecLoc()); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index c243765bec7..bc2c304ecc0 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1121,9 +1121,7 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,                            SourceLocation LAngleLoc,                             ASTTemplateArgsPtr TemplateArgsIn,                            SourceLocation *TemplateArgLocs, -                          SourceLocation RAngleLoc, -                          DeclSpec::TST TagSpec, -                          SourceLocation TagLoc) { +                          SourceLocation RAngleLoc) {    TemplateName Template = TemplateD.getAsVal<TemplateName>();    // Translate the parser's template argument list in our AST format. @@ -1139,26 +1137,38 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,    if (Result.isNull())      return true; -  // If we were given a tag specifier, verify it. -  if (TagSpec != DeclSpec::TST_unspecified) { -    TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); +  return Result.getAsOpaquePtr(); +} -    if (const RecordType *T = Result->getAs<RecordType>()) { -      RecordDecl *D = T->getDecl(); +Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, +                                              TagUseKind TUK, +                                              DeclSpec::TST TagSpec, +                                              SourceLocation TagLoc) { +  if (TypeResult.isInvalid()) +    return Sema::TypeResult(); -      IdentifierInfo *Id = D->getIdentifier(); -      assert(Id && "templated class must have an identifier"); +  QualType Type = QualType::getFromOpaquePtr(TypeResult.get()); -      if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { -        Diag(TagLoc, diag::err_use_with_wrong_tag) -          << Id -          << CodeModificationHint::CreateReplacement(SourceRange(TagLoc), -                                                     D->getKindName()); -      } +  // Verify the tag specifier. +  TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); +   +  if (const RecordType *RT = Type->getAs<RecordType>()) { +    RecordDecl *D = RT->getDecl(); + +    IdentifierInfo *Id = D->getIdentifier(); +    assert(Id && "templated class must have an identifier"); + +    if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { +      Diag(TagLoc, diag::err_use_with_wrong_tag) +        << Id +        << CodeModificationHint::CreateReplacement(SourceRange(TagLoc), +                                                   D->getKindName());      }    } -  return Result.getAsOpaquePtr(); +  QualType ElabType = Context.getElaboratedType(Type, TagKind); + +  return ElabType.getAsOpaquePtr();  }  Sema::OwningExprResult Sema::BuildTemplateIdExpr(TemplateName Template, | 

