Author: Saar Raz Date: 2020-01-26T20:46:53+02:00 New Revision: 5043962dd3150c6ac72b75174b9460a510d1b5c3
URL: https://github.com/llvm/llvm-project/commit/5043962dd3150c6ac72b75174b9460a510d1b5c3 DIFF: https://github.com/llvm/llvm-project/commit/5043962dd3150c6ac72b75174b9460a510d1b5c3.diff LOG: [Concepts] Fix parsing of scope specifier in compound-requirements, add more tests for scope specifiers in type-constraints The code for parsing of type-constraints in compound-requirements was not adapted for the new TryAnnotateTypeConstraint which caused compound-requirements with scope specifiers to ignore them. Also add regression tests for scope specifiers in type-constraints in more contexts. Added: clang/test/Parser/cxx2a-abbreviated-templates.cpp Modified: clang/lib/Parse/ParseExprCXX.cpp clang/test/Parser/cxx2a-concepts-requires-expr.cpp clang/test/Parser/cxx2a-placeholder-type-constraint.cpp Removed: ################################################################################ diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 73d15cbc20c1..5b604f940ab8 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3383,25 +3383,6 @@ ExprResult Parser::ParseRequiresExpression() { Diag(Tok, diag::err_requires_expr_missing_arrow) << FixItHint::CreateInsertion(Tok.getLocation(), "->"); // Try to parse a 'type-constraint' - CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), - /*EnteringContext=*/false, - /*MayBePseudoDestructor=*/nullptr, - // If this is not a type-constraint, - // then this scope-spec is part of - // the typename of a non-type - // template parameter - /*IsTypename=*/true, - /*LastII=*/nullptr, - // We won't find concepts in - // non-namespaces anyway, so might as - // well parse this correctly for - // possible type names. - /*OnlyNamespace=*/false, - /*SuppressDiagnostic=*/true)) { - SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); - break; - } if (TryAnnotateTypeConstraint()) { SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); break; @@ -3411,8 +3392,13 @@ ExprResult Parser::ParseRequiresExpression() { SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); break; } - if (Tok.is(tok::annot_cxxscope)) + CXXScopeSpec SS; + if (Tok.is(tok::annot_cxxscope)) { + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); ConsumeAnnotationToken(); + } Req = Actions.ActOnCompoundRequirement( Expression.get(), NoexceptLoc, SS, takeTemplateIdAnnotation(Tok), diff --git a/clang/test/Parser/cxx2a-abbreviated-templates.cpp b/clang/test/Parser/cxx2a-abbreviated-templates.cpp new file mode 100644 index 000000000000..e2b3803c807e --- /dev/null +++ b/clang/test/Parser/cxx2a-abbreviated-templates.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify +// expected-no-diagnostics + +template<typename T, typename U=void> +concept C = true; + +namespace ns { + template<typename T, typename U=void> + concept D = true; +} + +void foo(C auto a, + C<int> auto b, + ns::D auto c, + ns::D<int> auto d, + const C auto e, + const C<int> auto f, + const ns::D auto g, + const ns::D<int> auto h); \ No newline at end of file diff --git a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp index 6b4a5d62b407..fa42b0633850 100644 --- a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp +++ b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp @@ -108,34 +108,38 @@ bool r29 = requires { { 0 } noexcept C1; }; bool r30 = requires { { 0 } noexcept -> C2<int>; }; +namespace ns { template<typename T> concept C = true; } + +bool r31 = requires { { 0 } noexcept -> ns::C; }; + template<typename T> T i1 = 0; -bool r31 = requires { requires false, 1; }; +bool r32 = requires { requires false, 1; }; // expected-error@-1 {{expected ';' at end of requirement}} -bool r32 = requires { 0 noexcept; }; +bool r33 = requires { 0 noexcept; }; // expected-error@-1 {{'noexcept' can only be used in a compound requirement (with '{' '}' around the expression)}} -bool r33 = requires { 0 int; }; +bool r34 = requires { 0 int; }; // expected-error@-1 {{expected ';' at end of requirement}} -bool r34 = requires { requires true }; +bool r35 = requires { requires true }; // expected-error@-1 {{expected ';' at end of requirement}} -bool r35 = requires (bool b) { requires sizeof(b) == 1; }; +bool r36 = requires (bool b) { requires sizeof(b) == 1; }; -void r36(bool b) requires requires { 1 } {} +void r37(bool b) requires requires { 1 } {} // expected-error@-1 {{expected ';' at end of requirement}} -bool r37 = requires { requires { 1; }; }; +bool r38 = requires { requires { 1; }; }; // expected-warning@-1 {{this requires expression will only be checked for syntactic validity; did you intend to place it in a nested requirement? (add another 'requires' before the expression)}} -bool r38 = requires { requires () { 1; }; }; +bool r39 = requires { requires () { 1; }; }; // expected-warning@-1 {{this requires expression will only be checked for syntactic validity; did you intend to place it in a nested requirement? (add another 'requires' before the expression)}} -bool r39 = requires { requires (int i) { i; }; }; +bool r40 = requires { requires (int i) { i; }; }; // expected-warning@-1 {{this requires expression will only be checked for syntactic validity; did you intend to place it in a nested requirement? (add another 'requires' before the expression)}} -bool r40 = requires { requires (); }; +bool r41 = requires { requires (); }; // expected-error@-1 {{expected expression}} diff --git a/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp b/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp index 7c94cd526340..dc1d75e1d960 100644 --- a/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp +++ b/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp @@ -3,24 +3,33 @@ template<typename T, typename U=void> concept C = true; +namespace ns { + template<typename T, typename U=void> + concept D = true; +} + int foo() { - C auto a4 = 1; - C<> auto a5 = 1; - C<int> auto a6 = 1; - const C auto &a7 = 1; - const C<> auto &a8 = 1; - const C<int> auto &a9 = 1; - C decltype(auto) a10 = 1; - C<> decltype(auto) a11 = 1; - C<int> decltype(auto) a12 = 1; - const C<> decltype(auto) &a13 = 1; // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}} + {ns::D auto a = 1;} + {C auto a = 1;} + {C<> auto a = 1;} + {C<int> auto a = 1;} + {ns::D<int> auto a = 1;} + {const ns::D auto &a = 1;} + {const C auto &a = 1;} + {const C<> auto &a = 1;} + {const C<int> auto &a = 1;} + {const ns::D<int> auto &a = 1;} + {C decltype(auto) a = 1;} + {C<> decltype(auto) a = 1;} + {C<int> decltype(auto) a = 1;} + {const C<> decltype(auto) &a = 1;} // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}} // expected-error@-1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} - const C<int> decltype(auto) &a14 = 1; // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}} + {const C<int> decltype(auto) &a = 1;} // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}} // expected-error@-1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} - C a15 = 1; + {C a = 1;} // expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}} - C decltype a19 = 1; + {C decltype a19 = 1;} // expected-error@-1{{expected '('}} - C decltype(1) a20 = 1; + {C decltype(1) a20 = 1;} // expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}} } \ No newline at end of file _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits