diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c62823ddec980..9601849bd67d3 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -449,8 +449,6 @@ Bug Fixes to C++ Support - Some predefined expressions are now treated as string literals in MSVC compatibility mode. (`#114 `_) -- Fix parsing of `auto(x)`, when it is surrounded by parentheses. - (`#62494 `_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 8927af55e3712..fc892d71b51bf 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2521,10 +2521,10 @@ class Parser : public CodeCompletionHandler { enum TentativeCXXTypeIdContext { TypeIdInParens, TypeIdUnambiguous, - TypeIdAsTemplateArgument, - TypeIdInTrailingReturnType, + TypeIdAsTemplateArgument }; + /// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know /// whether the parens contain an expression or a type-id. /// Returns true for a type-id and false for an expression. @@ -2652,15 +2652,14 @@ class Parser : public CodeCompletionHandler { TPResult TryParseProtocolQualifiers(); TPResult TryParsePtrOperatorSeq(); TPResult TryParseOperatorId(); - TPResult TryParseInitDeclaratorList(bool MayHaveTrailingReturnType = false); + TPResult TryParseInitDeclaratorList(); TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier = true, - bool mayHaveDirectInit = false, - bool mayHaveTrailingReturnType = false); + bool mayHaveDirectInit = false); TPResult TryParseParameterDeclarationClause( bool *InvalidAsDeclaration = nullptr, bool VersusTemplateArg = false, ImplicitTypenameContext AllowImplicitTypename = ImplicitTypenameContext::No); - TPResult TryParseFunctionDeclarator(bool MayHaveTrailingReturnType = false); + TPResult TryParseFunctionDeclarator(); TPResult TryParseBracketDeclarator(); TPResult TryConsumeDeclarationSpecifier(); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 15a38e647b2de..92fa7d8a8a759 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -6494,9 +6494,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // that it's an initializer instead. if (D.mayOmitIdentifier() && D.mayBeFollowedByCXXDirectInit()) { RevertingTentativeParsingAction PA(*this); - if (TryParseDeclarator(true, D.mayHaveIdentifier(), true, - D.getDeclSpec().getTypeSpecType() == TST_auto) == - TPResult::False) { + if (TryParseDeclarator(true, D.mayHaveIdentifier(), true) == + TPResult::False) { D.SetIdentifier(nullptr, Tok.getLocation()); goto PastIdentifier; } diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index bdb462d086f2c..02aa59ec6fa1f 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -262,7 +262,6 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() { /// attribute-specifier-seqopt type-specifier-seq declarator /// Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { - bool DeclSpecifierIsAuto = Tok.is(tok::kw_auto); if (TryConsumeDeclarationSpecifier() == TPResult::Error) return TPResult::Error; @@ -278,8 +277,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { assert(TPR == TPResult::False); } - TPResult TPR = TryParseInitDeclaratorList( - /*mayHaveTrailingReturnType=*/DeclSpecifierIsAuto); + TPResult TPR = TryParseInitDeclaratorList(); if (TPR != TPResult::Ambiguous) return TPR; @@ -316,15 +314,10 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { /// '{' initializer-list ','[opt] '}' /// '{' '}' /// -Parser::TPResult -Parser::TryParseInitDeclaratorList(bool MayHaveTrailingReturnType) { +Parser::TPResult Parser::TryParseInitDeclaratorList() { while (true) { // declarator - TPResult TPR = TryParseDeclarator( - /*mayBeAbstract=*/false, - /*mayHaveIdentifier=*/true, - /*mayHaveDirectInit=*/false, - /*mayHaveTrailingReturnType=*/MayHaveTrailingReturnType); + TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/); if (TPR != TPResult::Ambiguous) return TPR; @@ -539,18 +532,13 @@ Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement, RevertingTentativeParsingAction PA(*this); // FIXME: A tag definition unambiguously tells us this is an init-statement. - bool MayHaveTrailingReturnType = Tok.is(tok::kw_auto); if (State.update(TryConsumeDeclarationSpecifier())) return State.result(); assert(Tok.is(tok::l_paren) && "Expected '('"); while (true) { // Consume a declarator. - if (State.update(TryParseDeclarator( - /*mayBeAbstract=*/false, - /*mayHaveIdentifier=*/true, - /*mayHaveDirectInit=*/false, - /*mayHaveTrailingReturnType=*/MayHaveTrailingReturnType))) + if (State.update(TryParseDeclarator(false/*mayBeAbstract*/))) return State.result(); // Attributes, asm label, or an initializer imply this is not an expression. @@ -635,16 +623,13 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { // We need tentative parsing... RevertingTentativeParsingAction PA(*this); - bool MayHaveTrailingReturnType = Tok.is(tok::kw_auto); // type-specifier-seq TryConsumeDeclarationSpecifier(); assert(Tok.is(tok::l_paren) && "Expected '('"); // declarator - TPR = TryParseDeclarator(true /*mayBeAbstract*/, false /*mayHaveIdentifier*/, - /*mayHaveDirectInit=*/false, - MayHaveTrailingReturnType); + TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/); // In case of an error, let the declaration parsing code handle it. if (TPR == TPResult::Error) @@ -673,9 +658,6 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { TPR = TPResult::True; isAmbiguous = true; - } else if (Context == TypeIdInTrailingReturnType) { - TPR = TPResult::True; - isAmbiguous = true; } else TPR = TPResult::False; } @@ -1060,8 +1042,7 @@ Parser::TPResult Parser::TryParseOperatorId() { /// Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier, - bool mayHaveDirectInit, - bool mayHaveTrailingReturnType) { + bool mayHaveDirectInit) { // declarator: // direct-declarator // ptr-operator declarator @@ -1103,7 +1084,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, ImplicitTypenameContext::No))) { // 'int(int)' is a function. // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] // exception-specification[opt] - TPResult TPR = TryParseFunctionDeclarator(mayHaveTrailingReturnType); + TPResult TPR = TryParseFunctionDeclarator(); if (TPR != TPResult::Ambiguous) return TPR; } else { @@ -1142,7 +1123,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // direct-declarator '(' parameter-declaration-clause ')' // cv-qualifier-seq[opt] exception-specification[opt] ConsumeParen(); - TPR = TryParseFunctionDeclarator(mayHaveTrailingReturnType); + TPR = TryParseFunctionDeclarator(); } else if (Tok.is(tok::l_square)) { // direct-declarator '[' constant-expression[opt] ']' // direct-abstract-declarator[opt] '[' constant-expression[opt] ']' @@ -1409,16 +1390,6 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, return isCXXDeclarationSpecifier(ImplicitTypenameContext::Yes, BracedCastResult, InvalidAsDeclSpec); - case tok::kw_auto: { - if (!getLangOpts().CPlusPlus23) - return TPResult::True; - if (NextToken().is(tok::l_brace)) - return TPResult::False; - if (NextToken().is(tok::l_paren)) - return TPResult::Ambiguous; - return TPResult::True; - } - case tok::coloncolon: { // ::foo::bar const Token &Next = NextToken(); if (Next.isOneOf(tok::kw_new, // ::new @@ -1452,6 +1423,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, case tok::kw_static: case tok::kw_extern: case tok::kw_mutable: + case tok::kw_auto: case tok::kw___thread: case tok::kw_thread_local: case tok::kw__Thread_local: @@ -2051,10 +2023,7 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause( // declarator // abstract-declarator[opt] - TPR = TryParseDeclarator(/*mayBeAbstract=*/true, - /*mayHaveIdentifier=*/true, - /*mayHaveDirectInit=*/false, - /*mayHaveTrailingReturnType=*/true); + TPR = TryParseDeclarator(true/*mayBeAbstract*/); if (TPR != TPResult::Ambiguous) return TPR; @@ -2108,8 +2077,7 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause( /// exception-specification: /// 'throw' '(' type-id-list[opt] ')' /// -Parser::TPResult -Parser::TryParseFunctionDeclarator(bool MayHaveTrailingReturnType) { +Parser::TPResult Parser::TryParseFunctionDeclarator() { // The '(' is already parsed. TPResult TPR = TryParseParameterDeclarationClause(); @@ -2154,19 +2122,6 @@ Parser::TryParseFunctionDeclarator(bool MayHaveTrailingReturnType) { } } - // attribute-specifier-seq - if (!TrySkipAttributes()) - return TPResult::Ambiguous; - - // trailing-return-type - if (Tok.is(tok::arrow) && MayHaveTrailingReturnType) { - if (TPR == TPResult::True) - return TPR; - ConsumeToken(); - if (isCXXTypeId(TentativeCXXTypeIdContext::TypeIdInTrailingReturnType)) - return TPResult::True; - } - return TPResult::Ambiguous; } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index f0fa075a91125..c0f4556d743b2 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1950,7 +1950,7 @@ bool Parser::TryAnnotateTypeOrScopeToken( assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) || Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) || - Tok.is(tok::kw___super) || Tok.is(tok::kw_auto)) && + Tok.is(tok::kw___super)) && "Cannot be a type or scope token!"); if (Tok.is(tok::kw_typename)) { diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index 90d60df2e47fe..10ef464bda50c 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -std=c++17 %s -verify=expected,cxx17 -fcxx-exceptions -// RUN: %clang_cc1 -std=c++2b %s -verify=expected,cxx2b -fcxx-exceptions +// RUN: %clang_cc1 -std=c++17 %s -verify -fcxx-exceptions // RUN: not %clang_cc1 -std=c++17 %s -emit-llvm-only -fcxx-exceptions struct S { int a, b, c; }; @@ -31,7 +30,7 @@ namespace ForRangeDecl { namespace OtherDecl { // A parameter-declaration is not a simple-declaration. // This parses as an array declaration. - void f(auto [a, b, c]); // cxx17-error {{'auto' not allowed in function prototype}} expected-error {{'a'}} + void f(auto [a, b, c]); // expected-error {{'auto' not allowed in function prototype}} expected-error {{'a'}} void g() { // A condition is allowed as a Clang extension. @@ -58,7 +57,7 @@ namespace OtherDecl { namespace GoodSpecifiers { void f() { int n[1]; - const volatile auto &[a] = n; // cxx2b-warning {{volatile qualifier in structured binding declaration is deprecated}} + const volatile auto &[a] = n; } } @@ -68,8 +67,8 @@ namespace BadSpecifiers { struct S { int n; } s; void f() { // storage-class-specifiers - static auto &[a] = n; // cxx17-warning {{declared 'static' is a C++20 extension}} - thread_local auto &[b] = n; // cxx17-warning {{declared 'thread_local' is a C++20 extension}} + static auto &[a] = n; // expected-warning {{declared 'static' is a C++20 extension}} + thread_local auto &[b] = n; // expected-warning {{declared 'thread_local' is a C++20 extension}} extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{declaration of block scope identifier with linkage cannot have an initializer}} struct S { mutable auto &[d] = n; // expected-error {{not permitted in this context}} @@ -86,19 +85,16 @@ namespace BadSpecifiers { } static constexpr inline thread_local auto &[j1] = n; // expected-error {{cannot be declared with 'constexpr inline' specifiers}} - static thread_local auto &[j2] = n; // cxx17-warning {{declared with 'static thread_local' specifiers is a C++20 extension}} + static thread_local auto &[j2] = n; // expected-warning {{declared with 'static thread_local' specifiers is a C++20 extension}} inline auto &[k] = n; // expected-error {{cannot be declared 'inline'}} const int K = 5; - auto ([c]) = s; // expected-error {{decomposition declaration cannot be declared with parentheses}} void g() { // defining-type-specifiers other than cv-qualifiers and 'auto' S [a] = s; // expected-error {{cannot be declared with type 'S'}} decltype(auto) [b] = s; // expected-error {{cannot be declared with type 'decltype(auto)'}} - auto ([c2]) = s; // cxx17-error {{decomposition declaration cannot be declared with parenthese}} \ - // cxx2b-error {{use of undeclared identifier 'c2'}} \ - // cxx2b-error {{expected body of lambda expression}} \ + auto ([c]) = s; // expected-error {{cannot be declared with parentheses}} // FIXME: This error is not very good. auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}} diff --git a/clang/test/Parser/cxx2b-auto-x.cpp b/clang/test/Parser/cxx2b-auto-x.cpp index 9e0277eee76a9..5ca11d5f39950 100644 --- a/clang/test/Parser/cxx2b-auto-x.cpp +++ b/clang/test/Parser/cxx2b-auto-x.cpp @@ -18,37 +18,7 @@ struct looks_like_declaration { using T = looks_like_declaration *; void f() { T(&a)->n = 1; } -void g() { auto(&a)->n = 0; } // cxx23-warning {{before C++23}} \ - // cxx20-error {{declaration of variable 'a' with deduced type 'auto (&)' requires an initializer}} \ - // cxx20-error {{expected ';' at end of declaration}} -void h() { auto{&a}->n = 0; } // cxx23-warning {{before C++23}} \ - // cxx20-error {{expected unqualified-id}} \ - // cxx20-error {{expected expression}} - -void e(auto (*p)(int y) -> decltype(y)) {} - -struct M; -struct S{ - S operator()(); - S* operator->(); - int N; - int M; -} s; // expected-note {{here}} - -void test() { - auto(s)()->N; // cxx23-warning {{expression result unused}} \ - // cxx23-warning {{before C++23}} \ - // cxx20-error {{unknown type name 'N'}} - auto(s)()->M; // expected-error {{redefinition of 's' as different kind of symbol}} -} - -void test_paren() { - int a = (auto(0)); // cxx23-warning {{before C++23}} \ - // cxx20-error {{expected expression}} \ - // cxx20-error {{expected ')'}} \ - // cxx20-note {{to match this '('}} - int b = (auto{0}); // cxx23-warning {{before C++23}} \ - // cxx20-error {{expected expression}} \ - // cxx20-error {{expected ')'}} \ - // cxx20-note {{to match this '('}} -} +// FIXME: They should be deemed expressions without breaking function pointer +// parameter declarations with trailing return types. +// void g() { auto(&a)->n = 0; } +// void h() { auto{&a}->n = 0; }