[cfe-commits] r81504 - in /cfe/trunk: include/clang/Parse/Action.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiate.cpp test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
John McCall
rjmccall at apple.com
Thu Sep 10 21:59:26 PDT 2009
Author: rjmccall
Date: Thu Sep 10 23:59:25 2009
New Revision: 81504
URL: http://llvm.org/viewvc/llvm-project?rev=81504&view=rev
Log:
Support elaborated dependent types and diagnose tag mismatches.
Added:
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
Modified:
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=81504&r1=81503&r2=81504&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Thu Sep 10 23:59:25 2009
@@ -522,10 +522,34 @@
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,
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=81504&r1=81503&r2=81504&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Sep 10 23:59:25 2009
@@ -1641,10 +1641,12 @@
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);
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=81504&r1=81503&r2=81504&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Sep 10 23:59:25 2009
@@ -619,7 +619,8 @@
}
// 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 @@
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 @@
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 @@
// 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 @@
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;
}
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=81504&r1=81503&r2=81504&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Sep 10 23:59:25 2009
@@ -609,7 +609,15 @@
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,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=81504&r1=81503&r2=81504&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Sep 10 23:59:25 2009
@@ -3988,7 +3988,7 @@
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 @@
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);
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=81504&r1=81503&r2=81504&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Sep 10 23:59:25 2009
@@ -1159,9 +1159,10 @@
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 @@
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::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
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=81504&r1=81503&r2=81504&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Sep 10 23:59:25 2009
@@ -391,6 +391,10 @@
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 @@
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());
Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp?rev=81504&r1=81503&r2=81504&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp Thu Sep 10 23:59:25 2009
@@ -11,7 +11,9 @@
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;
Added: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp?rev=81504&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp Thu Sep 10 23:59:25 2009
@@ -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}}
More information about the cfe-commits
mailing list