diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4362,6 +4362,8 @@ def err_default_arg_makes_ctor_special : Error< "addition of default argument on redeclaration makes this constructor a " "%select{default|copy|move}0 constructor">; +def err_expr_statement_in_default_arg : Error< + "expression statement not permitted in default argument">; def err_use_of_default_argument_to_function_declared_later : Error< "use of default argument to function %0 that is declared later in class %1">; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -7085,8 +7085,16 @@ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); DefArgResult = ParseBraceInitializer(); - } else + } else { + if (Tok.is(tok::l_paren) && NextToken().is(tok::l_brace)) { + Diag(Tok, diag::err_expr_statement_in_default_arg); + Actions.ActOnParamDefaultArgumentError(Param, EqualLoc); + // Skip the expression statement and continue parsing + SkipUntil(tok::comma, StopBeforeMatch); + continue; + } DefArgResult = ParseAssignmentExpression(); + } DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param, EqualLoc); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -19,6 +19,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/Support/TimeProfiler.h" using namespace clang; @@ -1007,18 +1008,23 @@ SourceLocation EqualLoc; ExprResult DefaultArg; if (TryConsumeToken(tok::equal, EqualLoc)) { - // C++ [temp.param]p15: - // When parsing a default template-argument for a non-type - // template-parameter, the first non-nested > is taken as the - // end of the template-parameter-list rather than a greater-than - // operator. - GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); - EnterExpressionEvaluationContext ConstantEvaluated( - Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - - DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); - if (DefaultArg.isInvalid()) + if (Tok.is(tok::l_paren) && NextToken().is(tok::l_brace)) { + Diag(Tok.getLocation(), diag::err_expr_statement_in_default_arg); SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); + } else { + // C++ [temp.param]p15: + // When parsing a default template-argument for a non-type + // template-parameter, the first non-nested > is taken as the + // end of the template-parameter-list rather than a greater-than + // operator. + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + DefaultArg = + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + if (DefaultArg.isInvalid()) + SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); + } } // Create the parameter. diff --git a/clang/test/Sema/err-expr-stmt-in-default-arg.cpp b/clang/test/Sema/err-expr-stmt-in-default-arg.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/err-expr-stmt-in-default-arg.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++20 + +void foo() { + void fn(int i, int = ({ 1; })); // expected-error {{expression statement not permitted in default argument}} + + auto a = [](int = ({ 1; })) {}; // expected-error {{expression statement not permitted in default argument}} + + auto b = [](){}; // expected-error {{expression statement not permitted in default argument}} + + void fn(int i, int j = ({{}, {}, {,}}), int k = ""); // expected-error {{expression statement not permitted in default argument}} expected-error {{cannot initialize a parameter of type 'int' with an lvalue of type 'const char[1]'}} expected-note {{passing argument to parameter 'k' here}} +} + +template +int bar(Callable &&Call) { + return Call(); +} + +int baz() { + auto l = [](int a = ({ int x = 12; x; })) { // expected-error {{expression statement not permitted in default argument}} + return 1; + }; + return bar(l); +} diff --git a/clang/test/SemaTemplate/dependent-expr.cpp b/clang/test/SemaTemplate/dependent-expr.cpp --- a/clang/test/SemaTemplate/dependent-expr.cpp +++ b/clang/test/SemaTemplate/dependent-expr.cpp @@ -141,15 +141,7 @@ using U = float; // expected-error {{different types ('float' vs 'decltype(g())' (aka 'void'))}} void h(auto a, decltype(g())*) {} // expected-note {{previous}} - void h(auto a, void*) {} // expected-error {{redefinition}} - - void i(auto a) { - [](auto a, int = ({decltype(a) i; i * 2;})){}(a); // expected-error {{invalid operands to binary expression ('decltype(a)' (aka 'void *') and 'int')}} expected-note {{in instantiation of}} - } - void use_i() { - i(0); - i((void*)0); // expected-note {{instantiation of}} - } + void h(auto a, void *) {} // expected-error {{redefinition}} } namespace BindingInStmtExpr {