"%select{typedef|type alias|type alias template}0 "
"redefinition with different types%diff{ ($ vs $)|}1,2">;
def err_tag_reference_non_tag : Error<
- "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template|a type alias template|a template template argument}0">;
+ "%select{non-struct type|non-class type|non-union type|non-enum "
+ "type|typedef|type alias|template|type alias template|template "
+ "template argument}1 %0 cannot be referenced with a "
+ "%select{struct|interface|union|class|enum}2 specifier">;
def err_tag_reference_conflict : Error<
- "implicit declaration introduced by elaborated type conflicts with "
- "%select{a declaration|a typedef|a type alias|a template}0 of the same name">;
+ "implicit declaration introduced by elaborated type conflicts with a "
+ "%select{non-struct type|non-class type|non-union type|non-enum "
+ "type|typedef|type alias|template|type alias template|template "
+ "template argument}0 of the same name">;
def err_dependent_tag_decl : Error<
"%select{declaration|definition}0 of "
"%select{struct|interface|union|class|enum}1 in a dependent scope">;
/// Common ways to introduce type names without a tag for use in diagnostics.
/// Keep in sync with err_tag_reference_non_tag.
enum NonTagKind {
- NTK_Unknown,
+ NTK_NonStruct,
+ NTK_NonClass,
+ NTK_NonUnion,
+ NTK_NonEnum,
NTK_Typedef,
NTK_TypeAlias,
NTK_Template,
/// Given a non-tag type declaration, returns an enum useful for indicating
/// what kind of non-tag type this is.
- NonTagKind getNonTagTypeDeclKind(const Decl *D);
+ NonTagKind getNonTagTypeDeclKind(const Decl *D, TagTypeKind TTK);
bool isAcceptableTagRedeclaration(const TagDecl *Previous,
TagTypeKind NewTag, bool isDefinition,
return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface;
}
-Sema::NonTagKind Sema::getNonTagTypeDeclKind(const Decl *PrevDecl) {
+Sema::NonTagKind Sema::getNonTagTypeDeclKind(const Decl *PrevDecl,
+ TagTypeKind TTK) {
if (isa<TypedefDecl>(PrevDecl))
return NTK_Typedef;
else if (isa<TypeAliasDecl>(PrevDecl))
return NTK_TypeAliasTemplate;
else if (isa<TemplateTemplateParmDecl>(PrevDecl))
return NTK_TemplateTemplateArgument;
- return NTK_Unknown;
+ switch (TTK) {
+ case TTK_Struct:
+ case TTK_Interface:
+ case TTK_Class:
+ return getLangOpts().CPlusPlus ? NTK_NonClass : NTK_NonStruct;
+ case TTK_Union:
+ return NTK_NonUnion;
+ case TTK_Enum:
+ return NTK_NonEnum;
+ }
+ llvm_unreachable("invalid TTK");
}
/// \brief Determine whether a tag with a given kind is acceptable
// (non-redeclaration) lookup.
if ((TUK == TUK_Reference || TUK == TUK_Friend) &&
!Previous.isForRedeclaration()) {
- NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl);
- Diag(NameLoc, diag::err_tag_reference_non_tag) << NTK;
+ NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl, Kind);
+ Diag(NameLoc, diag::err_tag_reference_non_tag) << PrevDecl << NTK
+ << Kind;
Diag(PrevDecl->getLocation(), diag::note_declared_at);
Invalid = true;
// Diagnose implicit declarations introduced by elaborated types.
} else if (TUK == TUK_Reference || TUK == TUK_Friend) {
- NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl);
+ NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl, Kind);
Diag(NameLoc, diag::err_tag_reference_conflict) << NTK;
Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
Invalid = true;
// If the identifier resolves to a typedef-name or the simple-template-id
// resolves to an alias template specialization, the
// elaborated-type-specifier is ill-formed.
- Diag(TemplateLoc, diag::err_tag_reference_non_tag) << NTK_TypeAliasTemplate;
+ Diag(TemplateLoc, diag::err_tag_reference_non_tag)
+ << TAT << NTK_TypeAliasTemplate << TagKind;
Diag(TAT->getLocation(), diag::note_declared_at);
}
ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(TD);
if (!ClassTemplate) {
- NonTagKind NTK = getNonTagTypeDeclKind(TD);
- Diag(TemplateNameLoc, diag::err_tag_reference_non_tag) << NTK;
+ NonTagKind NTK = getNonTagTypeDeclKind(TD, Kind);
+ Diag(TemplateNameLoc, diag::err_tag_reference_non_tag) << TD << NTK << Kind;
Diag(TD->getLocation(), diag::note_previous_use);
return true;
}
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue: {
NamedDecl *SomeDecl = Result.getRepresentativeDecl();
- Sema::NonTagKind NTK = SemaRef.getNonTagTypeDeclKind(SomeDecl);
- SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << NTK;
+ Sema::NonTagKind NTK = SemaRef.getNonTagTypeDeclKind(SomeDecl, Kind);
+ SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << SomeDecl
+ << NTK << Kind;
SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at);
break;
}
Template.getAsTemplateDecl())) {
SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(),
diag::err_tag_reference_non_tag)
- << Sema::NTK_TypeAliasTemplate;
+ << TAT << Sema::NTK_TypeAliasTemplate
+ << ElaboratedType::getTagTypeKindForKeyword(T->getKeyword());
SemaRef.Diag(TAT->getLocation(), diag::note_declared_at);
}
}
typedef int A; // expected-note {{declared here}}
int test() {
- struct A a; // expected-error {{elaborated type refers to a typedef}}
+ struct A a; // expected-error {{typedef 'A' cannot be referenced with a struct specifier}}
return a.foo;
}
}
template <class> class A; // expected-note {{declared here}}
int test() {
- struct A a; // expected-error {{elaborated type refers to a template}}
+ struct A a; // expected-error {{template 'A' cannot be referenced with a struct specifier}}
return a.foo;
}
}
struct A { typedef int type; };
template<typename T> using X = A; // expected-note {{declared here}}
-struct X<int>* p2; // expected-error {{elaborated type refers to a type alias template}}
+struct X<int>* p2; // expected-error {{type alias template 'X' cannot be referenced with a struct specifier}}
template<typename T> using Id = T; // expected-note {{declared here}}
template<template<typename> class F>
struct Y {
- struct F<int> i; // expected-error {{elaborated type refers to a type alias template}}
+ struct F<int> i; // expected-error {{type alias template 'Id' cannot be referenced with a struct specifier}}
typename F<A>::type j; // ok
// FIXME: don't produce the diagnostic both for the definition and the instantiation.
template<typename T> using U = F<char>; // expected-note 2{{declared here}}
- struct Y<F>::template U<char> k; // expected-error 2{{elaborated type refers to a type alias template}}
+ struct Y<F>::template U<char> k; // expected-error 2{{type alias template 'U' cannot be referenced with a struct specifier}}
typename Y<F>::template U<char> l; // ok
};
template struct Y<Id>; // expected-note {{requested here}}
template<typename T> struct A {
typedef typename T::type type; // ok even if this is a typedef-name, because
// it's not an elaborated-type-specifier
- typedef struct T::type foo; // expected-error {{elaborated type refers to a typedef}}
+ typedef struct T::type foo; // expected-error {{typedef 'type' cannot be referenced with a struct specifier}}
};
struct B { struct type {}; };
struct C { typedef struct {} type; }; // expected-note {{here}}
C::type i3;
struct A a;
- struct B b; // expected-error {{refers to a typedef}}
- struct C c; // expected-error {{refers to a typedef}}
+ struct B b; // expected-error {{typedef 'B' cannot be referenced with a struct specifier}}
+ struct C c; // expected-error {{typedef 'C' cannot be referenced with a struct specifier}}
B::B() {} // expected-error {{requires a type specifier}}
B::A() {} // ok
struct S *p;
{
typedef struct S S; // expected-note {{here}}
- struct S *p; // expected-error {{refers to a typedef}}
+ struct S *p; // expected-error {{typedef 'S' cannot be referenced with a struct specifier}}
}
}
struct S {};
// This shouldn't crash.
template <class T> class D {
- friend class A; // expected-error {{elaborated type refers to a template}}
+ friend class A; // expected-error {{template 'A' cannot be referenced with a class specifier}}
};
template class D<int>;
}
namespace unsupported {
#ifndef FIXING
- template struct y; // expected-error {{elaborated type refers to a template}}
+ template struct y; // expected-error {{template 'y' cannot be referenced with a struct specifier}}
#endif
}
template <typename T>
void f() {
- class A <T> ::iterator foo; // expected-error{{elaborated type refers to a typedef}}
+ class A <T> ::iterator foo; // expected-error{{typedef 'iterator' cannot be referenced with a class specifier}}
}
void g() {
template<typename T> struct A { };
template<typename T> using APtr = A<T*>; // expected-note{{previous use is here}}
- template struct APtr<int>; // expected-error{{elaborated type refers to a type alias template}}
+ template struct APtr<int>; // expected-error{{type alias template 'APtr' cannot be referenced with a struct specifier}}
}
namespace DontDiagnoseInvalidTest {
class C {};
template <template <typename> class D> // expected-note{{previous use is here}}
class E {
- template class D<C>; // expected-error {{elaborated type refers to a template template argument}}
+ template class D<C>; // expected-error {{template template argument 'D' cannot be referenced with a class specifier}}
};