diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 11cce36a0906c..74f4fcd3ca63d 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -648,6 +648,7 @@ Bug Fixes in This Version an array via an element-at-a-time copy loop (#GH192026) - Fixed an issue where certain designated initializers would be rejected for constexpr variables. (#GH193373) - Fixed a crash when ``#embed`` is used with C++ modules (#GH195350) +- Fixed an assertion failure in constant evaluation/AST parsing when encountering malformed struct and enum declarations with missing closing braces. (#GH118061) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index e38481f05da63..3195c50650fb4 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -2807,6 +2807,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool StopIfCastExpr, return res; } + TentativeParsingAction TPA(*this); // Parse the type declarator. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); @@ -2820,6 +2821,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool StopIfCastExpr, if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) && !InMessageExpression && getLangOpts().ObjC && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { + TPA.Commit(); TypeResult Ty; { InMessageExpressionRAIIObject InMessage(*this, false); @@ -2830,9 +2832,19 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool StopIfCastExpr, Ty.get(), nullptr); } else { // Match the ')'. - T.consumeClose(); + bool MissingCloseParen = T.consumeClose(); ColonProtection.restore(); RParenLoc = T.getCloseLocation(); + + if (MissingCloseParen && (DS.getTypeSpecType() == DeclSpec::TST_struct || + DS.getTypeSpecType() == DeclSpec::TST_class || + DS.getTypeSpecType() == DeclSpec::TST_union)) { + TPA.Revert(); + return ExprError(); + } + + TPA.Commit(); + if (ParenBehavior == ParenExprKind::Unknown && Tok.is(tok::l_brace)) { ExprType = ParenParseOption::CompoundLiteral; TypeResult Ty; diff --git a/clang/test/Parser/gh118061.cpp b/clang/test/Parser/gh118061.cpp new file mode 100644 index 0000000000000..0d21f2e14a2a1 --- /dev/null +++ b/clang/test/Parser/gh118061.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// expected-warning@+2 {{declaration does not declare anything}} +// expected-error@+1 {{anonymous structs and classes must be class members}} +struct { + // expected-error@+1 {{types cannot be declared in an anonymous struct}} + enum a1 { + b1 = (struct c1 + // expected-error@-1 {{expected ';' after struct}} + // expected-note@-2 {{to match this '('}} +}; +// expected-error@-1 {{expected ')'}} +// expected-error@-2 {{expected ';' after enum}} + +struct c1 { +}; + +// expected-warning@+2 {{declaration does not declare anything}} +// expected-error@+1 {{anonymous unions at namespace or global scope must be declared 'static'}} +union { + // expected-error@+1 {{types cannot be declared in an anonymous union}} + enum a2 { + b2 = (union c2 + // expected-error@-1 {{expected ';' after union}} + // expected-note@-2 {{to match this '('}} +}; +// expected-error@-1 {{expected ')'}} +// expected-error@-2 {{expected ';' after enum}} + +union c2 { +}; + +// expected-warning@+2 {{declaration does not declare anything}} +// expected-error@+1 {{anonymous structs and classes must be class members}} +class { + // expected-error@+1 {{types cannot be declared in an anonymous struct}} + enum a3 { + b3 = (class c3 + // expected-error@-1 {{expected ';' after class}} + // expected-note@-2 {{to match this '('}} +}; +// expected-error@-1 {{expected ')'}} +// expected-error@-2 {{expected ';' after enum}} + +class c3 { +};