r289259 - Improve error message when referencing a non-tag type with a tag

Reid Kleckner via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 9 11:47:59 PST 2016


Author: rnk
Date: Fri Dec  9 13:47:58 2016
New Revision: 289259

URL: http://llvm.org/viewvc/llvm-project?rev=289259&view=rev
Log:
Improve error message when referencing a non-tag type with a tag

Other compilers accept invalid code here that we reject, and we need a
better error message to try to convince users that the code is really
incorrect. Consider:
  class Foo {
    typedef MyIterHelper<Foo> iterator;
    friend class iterator;
  };

Previously our wording was "elaborated type refers to a typedef".
"elaborated type" isn't widely known terminology, so the new diagnostic
says "typedef 'iterator' cannot be referenced with class specifier".

Reviewers: rsmith

Differential Revision: https://reviews.llvm.org/D25216

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp
    cfe/trunk/test/CXX/drs/dr2xx.cpp
    cfe/trunk/test/CXX/drs/dr4xx.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
    cfe/trunk/test/CXX/temp/temp.spec/no-body.cpp
    cfe/trunk/test/SemaCXX/PR8755.cpp
    cfe/trunk/test/SemaCXX/using-decl-templates.cpp
    cfe/trunk/test/SemaTemplate/template-id-expr.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Dec  9 13:47:58 2016
@@ -4564,10 +4564,15 @@ def err_redefinition_different_typedef :
   "%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">;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Dec  9 13:47:58 2016
@@ -1976,7 +1976,10 @@ public:
   /// 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,
@@ -1986,7 +1989,7 @@ public:
 
   /// 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,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Dec  9 13:47:58 2016
@@ -12430,7 +12430,8 @@ static bool isClassCompatTagKind(TagType
   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))
@@ -12441,7 +12442,17 @@ Sema::NonTagKind Sema::getNonTagTypeDecl
     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
@@ -13224,8 +13235,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
       // (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;
 
@@ -13236,7 +13248,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
 
       // 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;

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Dec  9 13:47:58 2016
@@ -2489,7 +2489,8 @@ TypeResult Sema::ActOnTagTemplateIdType(
     //   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);
   }
   
@@ -7508,8 +7509,8 @@ Sema::ActOnExplicitInstantiation(Scope *
   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;
   }

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Fri Dec  9 13:47:58 2016
@@ -1013,8 +1013,9 @@ public:
         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;
         }
@@ -5706,7 +5707,8 @@ TreeTransform<Derived>::TransformElabora
               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);
       }
     }

Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp Fri Dec  9 13:47:58 2016
@@ -9,7 +9,7 @@ namespace test0 {
     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;
     }
   }
@@ -18,7 +18,7 @@ namespace test0 {
     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;
     }
   }

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp Fri Dec  9 13:47:58 2016
@@ -2,18 +2,18 @@
 
 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}}

Modified: cfe/trunk/test/CXX/drs/dr2xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr2xx.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr2xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr2xx.cpp Fri Dec  9 13:47:58 2016
@@ -620,7 +620,7 @@ namespace dr254 { // dr254: yes
   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}}
@@ -1048,8 +1048,8 @@ namespace dr298 { // dr298: yes
   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

Modified: cfe/trunk/test/CXX/drs/dr4xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr4xx.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr4xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr4xx.cpp Fri Dec  9 13:47:58 2016
@@ -90,7 +90,7 @@ namespace dr407 { // dr407: 3.8
     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 {};

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp Fri Dec  9 13:47:58 2016
@@ -174,7 +174,7 @@ namespace test7 {
 
   // 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>;
 }

Modified: cfe/trunk/test/CXX/temp/temp.spec/no-body.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/no-body.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/no-body.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/no-body.cpp Fri Dec  9 13:47:58 2016
@@ -43,7 +43,7 @@ namespace good { // Only good in C++98/0
 
 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
 }
 

Modified: cfe/trunk/test/SemaCXX/PR8755.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/PR8755.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/PR8755.cpp (original)
+++ cfe/trunk/test/SemaCXX/PR8755.cpp Fri Dec  9 13:47:58 2016
@@ -7,7 +7,7 @@ struct A {
 
 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() {

Modified: cfe/trunk/test/SemaCXX/using-decl-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/using-decl-templates.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/using-decl-templates.cpp (original)
+++ cfe/trunk/test/SemaCXX/using-decl-templates.cpp Fri Dec  9 13:47:58 2016
@@ -90,7 +90,7 @@ namespace aliastemplateinst {
   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 {

Modified: cfe/trunk/test/SemaTemplate/template-id-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/template-id-expr.cpp?rev=289259&r1=289258&r2=289259&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/template-id-expr.cpp (original)
+++ cfe/trunk/test/SemaTemplate/template-id-expr.cpp Fri Dec  9 13:47:58 2016
@@ -100,5 +100,5 @@ template void f5<0>(); // expected-note
 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}}
 };




More information about the cfe-commits mailing list