[clang] aa7ce60 - [Clang] Avoid crashes when parsing using enum declarations
Shafik Yaghmour via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 27 15:42:26 PDT 2022
Author: Shafik Yaghmour
Date: 2022-08-27T15:18:36-07:00
New Revision: aa7ce60536a642e825d26d89b4a4347a36b63360
URL: https://github.com/llvm/llvm-project/commit/aa7ce60536a642e825d26d89b4a4347a36b63360
DIFF: https://github.com/llvm/llvm-project/commit/aa7ce60536a642e825d26d89b4a4347a36b63360.diff
LOG: [Clang] Avoid crashes when parsing using enum declarations
In Parser::ParseUsingDeclaration(...) when we call ParseEnumSpecifier(...) it is
not calling SetTypeSpecError() on DS when it detects an error. That means that
DS is left set to TST_unspecified. When we then pass DS into
Sema::ActOnUsingEnumDeclaration(...) we hit an llvm_unreachable(...) since it
expects it to be one of three states TST_error, TST_enum or TST_typename.
This fixes https://github.com/llvm/llvm-project/issues/57347
Differential Revision: https://reviews.llvm.org/D132695
Added:
clang/test/Parser/cxx20-using-enum.cpp
Modified:
clang/lib/Parse/ParseDecl.cpp
clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
clang/test/CXX/drs/dr3xx.cpp
clang/test/Parser/recovery.cpp
clang/test/Sema/enum.c
clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
clang/test/SemaCXX/enum-scoped.cpp
Removed:
################################################################################
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 97a856a4a8f50..c502fc5e01019 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4647,6 +4647,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Spec.isSet() && Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected) << tok::identifier;
+ DS.SetTypeSpecError();
if (Tok.isNot(tok::l_brace)) {
// Has no name and is not a definition.
// Skip the rest of this declarator, up until the comma or semicolon.
@@ -4663,6 +4664,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
+ DS.SetTypeSpecError();
// Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, StopAtSemi);
return;
@@ -4838,6 +4840,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (!Name && TUK != Sema::TUK_Definition) {
Diag(Tok, diag::err_enumerator_unnamed_no_def);
+ DS.SetTypeSpecError();
// Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, StopAtSemi);
return;
diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
index 719aeeddebcc0..93fad2ff90ec9 100644
--- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
@@ -4,4 +4,4 @@
// will necessarily be ill-formed as a trailing return type for a function
// definition), and recover with a "type cannot be defined in a trailing return
// type" error.
-auto j() -> enum { e3 }; // expected-error{{unnamed enumeration must be a definition}} expected-error {{expected a type}}
+auto j() -> enum { e3 }; // expected-error{{unnamed enumeration must be a definition}}
diff --git a/clang/test/CXX/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp
index 0278a7d7f4974..e6f7328dd4d6c 100644
--- a/clang/test/CXX/drs/dr3xx.cpp
+++ b/clang/test/CXX/drs/dr3xx.cpp
@@ -30,7 +30,7 @@ namespace dr301 { // dr301: yes
typename T::template operator+<int> a; // expected-error {{typename specifier refers to a non-type template}} expected-error +{{}}
// FIXME: This shouldn't say (null).
class T::template operator+<int> b; // expected-error {{identifier followed by '<' indicates a class template specialization but (null) refers to a function template}}
- enum T::template operator+<int> c; // expected-error {{expected identifier}} expected-error {{does not declare anything}}
+ enum T::template operator+<int> c; // expected-error {{expected identifier}}
enum T::template operator+<int>::E d; // expected-error {{qualified name refers into a specialization of function template 'T::template operator +'}} expected-error {{forward reference}}
enum T::template X<int>::E e;
T::template operator+<int>::foobar(); // expected-error {{qualified name refers into a specialization of function template 'T::template operator +'}}
diff --git a/clang/test/Parser/cxx20-using-enum.cpp b/clang/test/Parser/cxx20-using-enum.cpp
new file mode 100644
index 0000000000000..d6744d3a91290
--- /dev/null
+++ b/clang/test/Parser/cxx20-using-enum.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+namespace GH57347 {
+namespace A {}
+
+void f() {
+ using enum A::+; // expected-error {{expected identifier}}
+ using enum; // expected-error {{expected identifier or '{'}}
+ using enum class; // expected-error {{expected identifier or '{'}}
+ using enum : blah; // expected-error {{unknown type name 'blah'}} expected-error {{unnamed enumeration must be a definition}}
+}
+}
diff --git a/clang/test/Parser/recovery.cpp b/clang/test/Parser/recovery.cpp
index 28c8817ea0276..5a20f98d32912 100644
--- a/clang/test/Parser/recovery.cpp
+++ b/clang/test/Parser/recovery.cpp
@@ -209,7 +209,7 @@ namespace pr15133 {
namespace InvalidEmptyNames {
// These shouldn't crash, the diagnostics aren't important.
struct ::, struct ::; // expected-error 2 {{expected identifier}} expected-error 2 {{declaration of anonymous struct must be a definition}} expected-warning {{declaration does not declare anything}}
-enum ::, enum ::; // expected-error 2 {{expected identifier}} expected-warning {{declaration does not declare anything}}
+enum ::, enum ::; // expected-error 2 {{expected identifier}}
struct ::__super, struct ::__super; // expected-error 2 {{expected identifier}} expected-error 2 {{expected '::' after '__super'}}
struct ::template foo, struct ::template bar; // expected-error 2 {{expected identifier}} expected-error 2 {{declaration of anonymous struct must be a definition}} expected-warning {{declaration does not declare anything}}
struct ::foo struct::; // expected-error {{no struct named 'foo' in the global namespace}} expected-error {{expected identifier}} expected-error {{declaration of anonymous struct must be a definition}}
diff --git a/clang/test/Sema/enum.c b/clang/test/Sema/enum.c
index def1cad1798a6..ed9a2e932661a 100644
--- a/clang/test/Sema/enum.c
+++ b/clang/test/Sema/enum.c
@@ -160,7 +160,7 @@ struct EnumRedeclStruct {
} e;
};
-enum struct GH42372_1 { // expected-error {{expected identifier or '{'}} expected-warning {{declaration does not declare anything}}
+enum struct GH42372_1 { // expected-error {{expected identifier or '{'}}
One
};
diff --git a/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
index 26f4bd3ed7a0a..da1678ec68627 100644
--- a/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
+++ b/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
@@ -432,7 +432,7 @@ namespace nested_name {
a<int>::b c; // expected-error {{qualified name refers into a specialization of variable template 'a'}}
class a<int> {}; // expected-error {{identifier followed by '<' indicates a class template specialization but 'a' refers to a variable template}}
- enum a<int> {}; // expected-error {{expected identifier or '{'}} expected-warning {{does not declare anything}}
+ enum a<int> {}; // expected-error {{expected identifier or '{'}}
}
namespace PR18530 {
diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp
index 8bdd79d8cfdfd..1c6a6d7212665 100644
--- a/clang/test/SemaCXX/enum-scoped.cpp
+++ b/clang/test/SemaCXX/enum-scoped.cpp
@@ -114,8 +114,7 @@ enum : long {
long_enum_val = 10000
};
-enum : long x; // expected-error{{unnamed enumeration must be a definition}} \
-// expected-warning{{declaration does not declare anything}}
+enum : long x; // expected-error{{unnamed enumeration must be a definition}}
void PR9333() {
enum class scoped_enum { yes, no, maybe };
More information about the cfe-commits
mailing list