diff options
-rw-r--r-- | include/clang/Parse/Action.h | 26 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 46 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 10 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 31 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 32 | ||||
-rw-r--r-- | test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp | 4 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp | 61 |
9 files changed, 196 insertions, 30 deletions
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 27f690b6b3..0cacfdbf14 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -522,10 +522,34 @@ public: IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, MultiTemplateParamsArg TemplateParameterLists, - bool &OwnedDecl) { + bool &OwnedDecl, bool &IsDependent) { return DeclPtrTy(); } + /// Acts on a reference to a dependent tag name. This arises in + /// cases like: + /// + /// template <class T> class A; + /// template <class T> class B { + /// friend class A<T>::M; // here + /// }; + /// + /// \param TagSpec an instance of DeclSpec::TST corresponding to the + /// tag specifier. + /// + /// \param TUK the tag use kind (either TUK_Friend or TUK_Reference) + /// + /// \param SS the scope specifier (always defined) + virtual TypeResult ActOnDependentTag(Scope *S, + unsigned TagSpec, + TagUseKind TUK, + const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation KWLoc, + SourceLocation NameLoc) { + return TypeResult(); + } + /// Act on @defs() element found when parsing a structure. ClassName is the /// name of the referenced class. virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 5d62c0c67e..f08c481c52 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1641,10 +1641,12 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, else TUK = Action::TUK_Reference; bool Owned = false; + bool IsDependent = false; DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, Attr, AS, Action::MultiTemplateParamsArg(Actions), - Owned); + Owned, IsDependent); + assert(!IsDependent && "didn't expect dependent enum"); if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index fc3e6ae17f..8fa8525750 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -619,7 +619,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } // Create the tag portion of the class or class template. - Action::DeclResult TagOrTempResult; + Action::DeclResult TagOrTempResult = true; // invalid + Action::TypeResult TypeResult = true; // invalid TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; // FIXME: When TUK == TUK_Reference and we have a template-id, we need @@ -651,7 +652,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->RAngleLoc, Attr); } else if (TUK == Action::TUK_Reference || TUK == Action::TUK_Friend) { - Action::TypeResult Type + TypeResult = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, @@ -659,23 +660,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc); - Type = Actions.ActOnTagTemplateIdType(Type, TUK, TagType, StartLoc); - - TemplateId->Destroy(); - - if (Type.isInvalid()) { - DS.SetTypeSpecError(); - return; - } - - const char *PrevSpec = 0; - unsigned DiagID; - if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, PrevSpec, - DiagID, Type.get())) - Diag(StartLoc, DiagID) << PrevSpec; - - return; - + TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK, + TagType, StartLoc); } else { // This is an explicit specialization or a class template // partial specialization. @@ -746,13 +732,21 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // FIXME: Diagnose this particular error. } + bool IsDependent = false; + // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS, Name, NameLoc, Attr, AS, Action::MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0), - Owned); + Owned, IsDependent); + + // If ActOnTag said the type was dependent, try again with the + // less common call. + if (IsDependent) + TypeResult = Actions.ActOnDependentTag(CurScope, TagType, TUK, + SS, Name, StartLoc, NameLoc); } // Parse the optional base clause (C++ only). @@ -771,15 +765,23 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Diag(Tok, diag::err_expected_lbrace); } - if (TagOrTempResult.isInvalid()) { + void *Result; + if (!TypeResult.isInvalid()) { + TagType = DeclSpec::TST_typename; + Result = TypeResult.get(); + Owned = false; + } else if (!TagOrTempResult.isInvalid()) { + Result = TagOrTempResult.get().getAs<void>(); + } else { DS.SetTypeSpecError(); return; } const char *PrevSpec = 0; unsigned DiagID; + if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, DiagID, - TagOrTempResult.get().getAs<void>(), Owned)) + Result, Owned)) Diag(StartLoc, DiagID) << PrevSpec; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index dc41aba094..b17e54ebe3 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -609,7 +609,15 @@ public: IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, MultiTemplateParamsArg TemplateParameterLists, - bool &OwnedDecl); + bool &OwnedDecl, bool &IsDependent); + + virtual TypeResult ActOnDependentTag(Scope *S, + unsigned TagSpec, + TagUseKind TUK, + const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation TagLoc, + SourceLocation NameLoc); virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 65516f2c29..53fab18017 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3988,7 +3988,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, MultiTemplateParamsArg TemplateParameterLists, - bool &OwnedDecl) { + bool &OwnedDecl, bool &IsDependent) { // If this is not a definition, it must have a name. assert((Name != 0 || TUK == TUK_Definition) && "Nameless record must be a definition!"); @@ -4034,6 +4034,16 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, goto CreateNewDecl; } + // If this is a friend or a reference to a class in a dependent + // context, don't try to make a decl for it. + if (TUK == TUK_Friend || TUK == TUK_Reference) { + DC = computeDeclContext(SS, false); + if (!DC) { + IsDependent = true; + return DeclPtrTy(); + } + } + if (RequireCompleteDeclContext(SS)) return DeclPtrTy::make((Decl *)0); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index fceac854ee..63c29de82b 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1159,9 +1159,10 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) - << Id + << Type << CodeModificationHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); + Diag(D->getLocation(), diag::note_previous_use); } } @@ -3058,9 +3059,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, AttributeList *Attr) { bool Owned = false; + bool IsDependent = false; DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr, AS_none, - MultiTemplateParamsArg(*this, 0, 0), Owned); + MultiTemplateParamsArg(*this, 0, 0), + Owned, IsDependent); + assert(!IsDependent && "explicit instantiation of dependent name not yet handled"); + if (!TagD) return true; @@ -3124,6 +3129,28 @@ Sema::ActOnExplicitInstantiation(Scope *S, } Sema::TypeResult +Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, + const CXXScopeSpec &SS, IdentifierInfo *Name, + SourceLocation TagLoc, SourceLocation NameLoc) { + // This has to hold, because SS is expected to be defined. + assert(Name && "Expected a name in a dependent tag"); + + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + if (!NNS) + return true; + + QualType T = CheckTypenameType(NNS, *Name, SourceRange(TagLoc, NameLoc)); + if (T.isNull()) + return true; + + TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); + QualType ElabType = Context.getElaboratedType(T, TagKind); + + return ElabType.getAsOpaquePtr(); +} + +Sema::TypeResult Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc) { NestedNameSpecifier *NNS diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 651d4a50dc..e719bbde92 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -391,6 +391,10 @@ namespace { IdentifierInfo *Name, SourceLocation Loc, SourceRange TypeRange); + /// \brief Check for tag mismatches when instantiating an + /// elaborated type. + QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); + Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E); Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E); @@ -451,7 +455,33 @@ TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, return Var; } -Sema::OwningExprResult +QualType +TemplateInstantiator::RebuildElaboratedType(QualType T, + ElaboratedType::TagKind Tag) { + if (const TagType *TT = T->getAs<TagType>()) { + TagDecl* TD = TT->getDecl(); + + // FIXME: this location is very wrong; we really need typelocs. + SourceLocation TagLocation = TD->getTagKeywordLoc(); + + // FIXME: type might be anonymous. + IdentifierInfo *Id = TD->getIdentifier(); + + // TODO: should we even warn on struct/class mismatches for this? Seems + // like it's likely to produce a lot of spurious errors. + if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) { + SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) + << Id + << CodeModificationHint::CreateReplacement(SourceRange(TagLocation), + TD->getKindName()); + SemaRef.Diag(TD->getLocation(), diag::note_previous_use); + } + } + + return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag); +} + +Sema::OwningExprResult TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { if (!E->isTypeDependent()) return SemaRef.Owned(E->Retain()); diff --git a/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp b/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp index 4dc1cc7d7a..5346f36739 100644 --- a/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp +++ b/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp @@ -11,7 +11,9 @@ namespace A { template <typename> void Ident(); class Ident<int> AIdent; // expected-error {{refers to a function template}} - class ::Ident<int> AnotherIdent; + + // FIXME: this note should be on the template declaration, not the point of instantiation + class ::Ident<int> AnotherIdent; // expected-note {{previous use is here}} } class Ident<int> GlobalIdent; diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp new file mode 100644 index 0000000000..0c9f294d2b --- /dev/null +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp @@ -0,0 +1,61 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +class A {}; // expected-note 3 {{previous use is here}} + +void a1(struct A); +void a2(class A); +void a3(union A); // expected-error {{use of 'A' with tag type that does not match previous declaration}} +void a4(enum A); // expected-error {{use of 'A' with tag type that does not match previous declaration}} + +class A1 { + friend struct A; + friend class A; + friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}} + + // FIXME: a better error would be something like 'enum types cannot be friends' + friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}} +}; + +template <class T> struct B { + class Member {}; // expected-note 2 {{previous use is here}} +}; + +template <> class B<int> { + // no type Member +}; + +template <> struct B<A> { + // FIXME: the error here should be associated with the use at "void foo..." + union Member { // expected-note 4 {{previous use is here}} expected-error {{tag type that does not match previous declaration}} + void* a; + }; +}; + +// FIXME: this note should be on the template declaration, not the point of instantiation +void b1(struct B<float>); // expected-note {{previous use is here}} +void b2(class B<float>); +void b3(union B<float>); // expected-error {{use of 'B<float>' with tag type that does not match previous declaration}} +//void b4(enum B<float>); // this just doesn't parse; you can't template an enum directly + +void c1(struct B<float>::Member); +void c2(class B<float>::Member); +void c3(union B<float>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}} +void c4(enum B<float>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}} + +void d1(struct B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}} +void d2(class B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}} +void d3(union B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}} +void d4(enum B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}} + +void e1(struct B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}} +void e2(class B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}} +void e3(union B<A>::Member); +void e4(enum B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}} + +template <class T> struct C { + void foo(class B<T>::Member); // expected-error{{no type named 'Member' in 'B'}} +}; + +C<float> f1; +C<int> f2; // expected-note {{in instantiation of template class}} +C<A> f3; // expected-note {{in instantiation of template class}} |