diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-04-24 16:38:41 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-04-24 16:38:41 +0000 |
commit | 48c89f4aa708e28310cb0c94b2d9d044b0ab806c (patch) | |
tree | 5eae1b37444f8cc0ed855d1ce1ab7145101f88fa | |
parent | 80971bdba20b5b280a00b7b9829026b33d3206f9 (diff) |
Be more careful around dependent nested-name-specifiers, complaining
when they are not complete (since we could not match them up to
anything) and ensuring that enum parsing can cope with dependent
elaborated-type-specifiers. Fixes PR6915 and PR6649.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102247 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 42 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 7 | ||||
-rw-r--r-- | test/SemaTemplate/elaborated-type-specifier.cpp | 35 |
6 files changed, 97 insertions, 5 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index af8946d16c..d26566684b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -513,6 +513,9 @@ def note_access_constrained_by_path : Note< // C++ name lookup def err_incomplete_nested_name_spec : Error< "incomplete type %0 named in nested name specifier">; +def err_dependent_nested_name_spec : Error< + "nested name specifier for a declaration cannot depend on a template " + "parameter">; def err_nested_name_member_ref_lookup_ambiguous : Error< "lookup of %0 in member access expression is ambiguous">; def note_ambig_member_ref_object_type : Note< @@ -1590,6 +1593,9 @@ def err_tag_reference_non_tag : Error< def err_tag_reference_conflict : Error< "implicit declaration introduced by elaborated type conflicts with " "%select{a declaration|a typedef|a template}0 of the same name">; +def err_dependent_tag_decl : Error< + "%select{declaration|definition}0 of %select{struct|union|class|enum}1 " + "in a dependent scope">; def err_tag_definition_of_typedef : Error< "definition of type %0 conflicts with typedef of the same name">; def err_conflicting_types : Error<"conflicting types for %0">; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index a034a325f4..6669d40cca 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1934,21 +1934,55 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, TUK = Action::TUK_Reference; bool Owned = false; bool IsDependent = false; + SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; + const char *PrevSpec = 0; + unsigned DiagID; DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, Attr.get(), AS, Action::MultiTemplateParamsArg(Actions), Owned, IsDependent); - assert(!IsDependent && "didn't expect dependent enum"); + if (IsDependent) { + // This enum has a dependent nested-name-specifier. Handle it as a + // dependent tag. + if (!Name) { + DS.SetTypeSpecError(); + Diag(Tok, diag::err_expected_type_name_after_typename); + return; + } + + TypeResult Type = Actions.ActOnDependentTag(CurScope, DeclSpec::TST_enum, + TUK, SS, Name, StartLoc, + NameLoc); + if (Type.isInvalid()) { + DS.SetTypeSpecError(); + return; + } + + if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID, + Type.get(), false)) + Diag(StartLoc, DiagID) << PrevSpec; + + return; + } + if (!TagDecl.get()) { + // The action failed to produce an enumeration tag. If this is a + // definition, consume the entire definition. + if (Tok.is(tok::l_brace)) { + ConsumeBrace(); + SkipUntil(tok::r_brace); + } + + DS.SetTypeSpecError(); + return; + } + if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); // FIXME: The DeclSpec should keep the locations of both the keyword and the // name (if there is one). - SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; - const char *PrevSpec = 0; - unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID, TagDecl.getAs<void>(), Owned)) Diag(StartLoc, DiagID) << PrevSpec; diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index e9d206e53b..89f8aec6e0 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -235,6 +235,16 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS) { return false; DeclContext *DC = computeDeclContext(SS, true); + if (!DC) { + // It's dependent. + assert(isDependentScopeSpecifier(SS) && + "No context for non-dependent scope specifier?"); + Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec) + << SS.getRange(); + SS.setScopeRep(0); + return true; + } + if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { // If this is a dependent type, then we consider it complete. if (Tag->isDependentContext()) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b8ff182be0..bf2cba10c7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5313,7 +5313,7 @@ CreateNewDecl: void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>()); - + // Enter the tag context. PushDeclContext(S, Tag); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 1075f41399..14d04563d6 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -5117,6 +5117,13 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } assert(Keyword != ETK_None && "Invalid tag kind!"); + if (TUK == TUK_Declaration || TUK == TUK_Definition) { + Diag(NameLoc, diag::err_dependent_tag_decl) + << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec) + << SS.getRange(); + return true; + } + return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr(); } diff --git a/test/SemaTemplate/elaborated-type-specifier.cpp b/test/SemaTemplate/elaborated-type-specifier.cpp new file mode 100644 index 0000000000..c38bf547a1 --- /dev/null +++ b/test/SemaTemplate/elaborated-type-specifier.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace PR6915 { + template <typename T> + class D { + enum T::X v; // expected-error{{use of 'X' with tag type that does not match previous declaration}} \ + // expected-error{{no enum named 'X' in 'PR6915::D3'}} + }; + + struct D1 { + enum X { value }; + }; + struct D2 { + class X { }; // expected-note{{previous use is here}} + }; + struct D3 { }; + + template class D<D1>; + template class D<D2>; // expected-note{{in instantiation of}} + template class D<D3>; // expected-note{{in instantiation of}} +} + +template<typename T> +struct DeclOrDef { + enum T::foo; // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}} + enum T::bar { // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}} + value + }; +}; + +namespace PR6649 { + template <typename T> struct foo { + class T::bar; // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}} + }; +} |