vsapsai created this revision.

This fixes PR28903 by avoiding access check for inner enum constant. We
are performing access check because one enum constant references another
and because enum is defined in CXXRecordDecl. But access check doesn't
work because FindDeclaringClass doesn't expect more than one EnumDecl
and because inner enum has access AS_none due to not being an immediate
child of a record.

The change detects an enum is defined in wrong place and allows to skip
parsing its body. Access check is skipped together with body parsing.
There was no crash in C, added test case to cover the new error.

rdar://problem/28530809


https://reviews.llvm.org/D37089

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaDecl.cpp
  clang/test/Sema/enum.c
  clang/test/SemaCXX/enum.cpp


Index: clang/test/SemaCXX/enum.cpp
===================================================================
--- clang/test/SemaCXX/enum.cpp
+++ clang/test/SemaCXX/enum.cpp
@@ -110,3 +110,13 @@
 // expected-warning@-2 {{not an integral constant expression}}
 // expected-note@-3 {{value 28958703552 is outside the range of representable 
values}}
 #endif
+
+// PR28903
+struct PR28903 {
+  enum {
+    PR28903_A = (enum { // expected-error-re {{'PR28903::(anonymous enum at 
{{.*}})' cannot be defined in an enumeration}}
+      PR28903_B,
+      PR28903_C = PR28903_B
+    })
+  };
+};
Index: clang/test/Sema/enum.c
===================================================================
--- clang/test/Sema/enum.c
+++ clang/test/Sema/enum.c
@@ -123,3 +123,13 @@
 // PR24610
 enum Color { Red, Green, Blue }; // expected-note{{previous use is here}}
 typedef struct Color NewColor; // expected-error {{use of 'Color' with tag 
type that does not match previous declaration}}
+
+// PR28903
+struct PR28903 { // expected-warning {{empty struct is a GNU extension}}
+  enum {
+    PR28903_A = (enum { // expected-error-re {{'enum PR28903::(anonymous at 
{{.*}})' cannot be defined in an enumeration}}
+      PR28903_B,
+      PR28903_C = PR28903_B
+    })
+  };  // expected-error {{expected expression}}
+};
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -13929,6 +13929,12 @@
     Invalid = true;
   }
 
+  if (!Invalid && TUK == TUK_Definition && DC->getDeclKind() == Decl::Enum) {
+    Diag(New->getLocation(), diag::err_type_defined_in_enum)
+      << Context.getTagDeclType(New);
+    Invalid = true;
+  }
+
   // Maybe add qualifier info.
   if (SS.isNotEmpty()) {
     if (SS.isSet()) {
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1329,6 +1329,8 @@
   "%0 cannot be defined in a type alias template">;
 def err_type_defined_in_condition : Error<
   "%0 cannot be defined in a condition">;
+def err_type_defined_in_enum : Error<
+  "%0 cannot be defined in an enumeration">;
 
 def note_pure_virtual_function : Note<
   "unimplemented pure virtual method %0 in %1">;


Index: clang/test/SemaCXX/enum.cpp
===================================================================
--- clang/test/SemaCXX/enum.cpp
+++ clang/test/SemaCXX/enum.cpp
@@ -110,3 +110,13 @@
 // expected-warning@-2 {{not an integral constant expression}}
 // expected-note@-3 {{value 28958703552 is outside the range of representable values}}
 #endif
+
+// PR28903
+struct PR28903 {
+  enum {
+    PR28903_A = (enum { // expected-error-re {{'PR28903::(anonymous enum at {{.*}})' cannot be defined in an enumeration}}
+      PR28903_B,
+      PR28903_C = PR28903_B
+    })
+  };
+};
Index: clang/test/Sema/enum.c
===================================================================
--- clang/test/Sema/enum.c
+++ clang/test/Sema/enum.c
@@ -123,3 +123,13 @@
 // PR24610
 enum Color { Red, Green, Blue }; // expected-note{{previous use is here}}
 typedef struct Color NewColor; // expected-error {{use of 'Color' with tag type that does not match previous declaration}}
+
+// PR28903
+struct PR28903 { // expected-warning {{empty struct is a GNU extension}}
+  enum {
+    PR28903_A = (enum { // expected-error-re {{'enum PR28903::(anonymous at {{.*}})' cannot be defined in an enumeration}}
+      PR28903_B,
+      PR28903_C = PR28903_B
+    })
+  };  // expected-error {{expected expression}}
+};
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -13929,6 +13929,12 @@
     Invalid = true;
   }
 
+  if (!Invalid && TUK == TUK_Definition && DC->getDeclKind() == Decl::Enum) {
+    Diag(New->getLocation(), diag::err_type_defined_in_enum)
+      << Context.getTagDeclType(New);
+    Invalid = true;
+  }
+
   // Maybe add qualifier info.
   if (SS.isNotEmpty()) {
     if (SS.isSet()) {
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1329,6 +1329,8 @@
   "%0 cannot be defined in a type alias template">;
 def err_type_defined_in_condition : Error<
   "%0 cannot be defined in a condition">;
+def err_type_defined_in_enum : Error<
+  "%0 cannot be defined in an enumeration">;
 
 def note_pure_virtual_function : Note<
   "unimplemented pure virtual method %0 in %1">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to