[PATCH] D55097: [constexpr][c++2a] Try-catch blocks in constexpr functions
This revision was automatically updated to reflect the committed changes. Closed by commit rL348789: [constexpr][c++2a] Try-catch blocks in constexpr functions (authored by bruno, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D55097?vs=177367=177564#toc Repository: rL LLVM CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55097/new/ https://reviews.llvm.org/D55097 Files: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp cfe/trunk/test/CXX/drs/dr6xx.cpp cfe/trunk/www/cxx_status.html Index: cfe/trunk/www/cxx_status.html === --- cfe/trunk/www/cxx_status.html +++ cfe/trunk/www/cxx_status.html @@ -953,13 +953,15 @@ Relaxations of constexpr restrictions http://wg21.link/p1064r0;>P1064R0 - No + No http://wg21.link/p1002r1;>P1002R1 +SVN http://wg21.link/p1327r1;>P1327R1 +No http://wg21.link/p1330r0;>P1330R0 Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td === --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -2357,6 +2357,13 @@ "use of this statement in a constexpr %select{function|constructor}0 " "is incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; +def ext_constexpr_body_invalid_stmt_cxx2a : ExtWarn< + "use of this statement in a constexpr %select{function|constructor}0 " + "is a C++2a extension">, InGroup; +def warn_cxx17_compat_constexpr_body_invalid_stmt : Warning< + "use of this statement in a constexpr %select{function|constructor}0 " + "is incompatible with C++ standards before C++2a">, + InGroup, DefaultIgnore; def ext_constexpr_type_definition : ExtWarn< "type definition in a constexpr %select{function|constructor}0 " "is a C++14 extension">, InGroup; @@ -2409,6 +2416,16 @@ "previous return statement is here">; def err_constexpr_function_try_block : Error< "function try block not allowed in constexpr %select{function|constructor}0">; + +// c++2a function try blocks in constexpr +def ext_constexpr_function_try_block_cxx2a : ExtWarn< + "function try block in constexpr %select{function|constructor}0 is " + "a C++2a extension">, InGroup; +def warn_cxx17_compat_constexpr_function_try_block : Warning< + "function try block in constexpr %select{function|constructor}0 is " + "incompatible with C++ standards before C++2a">, + InGroup, DefaultIgnore; + def err_constexpr_union_ctor_no_init : Error< "constexpr union constructor does not initialize any member">; def err_constexpr_ctor_missing_init : Error< Index: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp === --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions %s -// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y %s +// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -std=c++2a -fcxx-exceptions -DCXX1Y -DCXX2A %s namespace N { typedef char C; @@ -49,8 +50,14 @@ // - its function-body shall not be a function-try-block; struct U { constexpr U() -try // expected-error {{function try block not allowed in constexpr constructor}} +try +#ifndef CXX2A + // expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}} +#endif : u() { +#ifndef CXX1Y + // expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}} +#endif } catch (...) { throw; } Index: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp === --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions %s -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -fcxx-exceptions
[PATCH] D55097: [constexpr][c++2a] Try-catch blocks in constexpr functions
aaron.ballman accepted this revision. aaron.ballman added a comment. This revision is now accepted and ready to land. LGTM aside from a few other small nits. Comment at: lib/Sema/SemaDeclCXX.cpp:1904 + case Stmt::CXXTryStmtClass: +if (!Cxx2aLoc.isValid()) + Cxx2aLoc = S->getBeginLoc(); `Cxx2aLoc.isInvalid()` Comment at: lib/Sema/SemaDeclCXX.cpp:1956 +// +// In C++2a lifts this restriction, as long as inner statements do also +// apply to general constexpr rules. This restriction is lifted in C++2a, as long as inner statements also apply the general constexpr rules. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55097/new/ https://reviews.llvm.org/D55097 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55097: [constexpr][c++2a] Try-catch blocks in constexpr functions
bruno updated this revision to Diff 177367. bruno marked an inline comment as done. bruno added a comment. Address @aaron.ballman and @erik.pilkington reviews. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55097/new/ https://reviews.llvm.org/D55097 Files: include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ExprConstant.cpp lib/Sema/SemaDeclCXX.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp test/CXX/drs/dr6xx.cpp www/cxx_status.html Index: www/cxx_status.html === --- www/cxx_status.html +++ www/cxx_status.html @@ -953,13 +953,15 @@ Relaxations of constexpr restrictions http://wg21.link/p1064r0;>P1064R0 - No + No http://wg21.link/p1002r1;>P1002R1 +SVN http://wg21.link/p1327r1;>P1327R1 +No http://wg21.link/p1330r0;>P1330R0 Index: test/CXX/drs/dr6xx.cpp === --- test/CXX/drs/dr6xx.cpp +++ test/CXX/drs/dr6xx.cpp @@ -492,7 +492,13 @@ struct C { constexpr C(NonLiteral); constexpr C(NonLiteral, int) {} // expected-error {{not a literal type}} -constexpr C() try {} catch (...) {} // expected-error {{function try block}} +constexpr C() try {} catch (...) {} +#if __cplusplus <= 201703L +// expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}} +#endif +#if __cplusplus < 201402L +// expected-error@-5 {{use of this statement in a constexpr constructor is a C++14 extension}} +#endif }; struct D { Index: test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions %s -// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y %s +// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -std=c++2a -fcxx-exceptions -DCXX1Y -DCXX2A %s namespace N { typedef char C; @@ -49,8 +50,14 @@ // - its function-body shall not be a function-try-block; struct U { constexpr U() -try // expected-error {{function try block not allowed in constexpr constructor}} +try +#ifndef CXX2A + // expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}} +#endif : u() { +#ifndef CXX1Y + // expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}} +#endif } catch (...) { throw; } Index: test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions %s -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++2a -DCXX1Y -DCXX2A %s namespace N { typedef char C; @@ -78,7 +79,12 @@ }; struct T3 { constexpr T3 =(const T3&) const = default; - // expected-error@-1 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}} +#ifndef CXX2A + // expected-error@-2 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}} +#else + // expected-warning@-4 {{explicitly defaulted copy assignment operator is implicitly deleted}} + // expected-note@-5 {{function is implicitly deleted because its declared type does not match the type of an implicit copy assignment operator}} +#endif }; #endif struct U { @@ -129,9 +135,22 @@ x: return 0; } +constexpr int DisallowedStmtsCXX1Y_2_1() { + try { +return 0; + } catch (...) { + merp: goto merp; // expected-error {{statement not allowed in constexpr function}} + } +} constexpr int DisallowedStmtsCXX1Y_3() { // - a try-block, - try {} catch (...) {} // expected-error {{statement not allowed in constexpr function}} + try {} catch (...) {} +#ifndef CXX2A + // expected-error@-2 {{use of this statement in a constexpr function is a C++2a extension}} +#ifndef CXX1Y + // expected-error@-4 {{use of this statement in a constexpr function is a C++14 extension}} +#endif +#endif return 0;
[PATCH] D55097: [constexpr][c++2a] Try-catch blocks in constexpr functions
aaron.ballman added a comment. Some minor nits from the peanut gallery. Comment at: lib/AST/ExprConstant.cpp:4278 + case Stmt::CXXTryStmtClass: +// Evaluate try blocks by evaluating all sub statements +return EvaluateStmt(Result, Info, cast(S)->getTryBlock(), Case); Missing full stop. Comment at: lib/Sema/SemaDeclCXX.cpp:1906 + Cxx2aLoc = S->getBeginLoc(); +for (Stmt *SubStmt : S->children()) + if (SubStmt && I'd appreciate curly braces here, even though they're not strictly required by the coding standard. ;-) Comment at: lib/Sema/SemaDeclCXX.cpp:1971 + SourceLocation Cxx1yLoc, Cxx2aLoc; + for (Stmt *SubStmt : Body->children()) +if (SubStmt && Likewise here. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55097/new/ https://reviews.llvm.org/D55097 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55097: [constexpr][c++2a] Try-catch blocks in constexpr functions
erik.pilkington added a comment. LGTM, but you should probably let @rsmith have the final word! Comment at: lib/Sema/SemaDeclCXX.cpp:1916-1919 +for (Stmt *SubStmt : S->children()) + if (SubStmt && + !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, + Cxx1yLoc, Cxx2aLoc)) Might be clearer to just write `if (!CheckConstexprFunctionStmt(SemaRef, Dcl, cast(SubStmt)->getHandlerBlock()))`, rather than looping over 1 statement. Could you also add that example I posted as a testcase for this? CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55097/new/ https://reviews.llvm.org/D55097 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55097: [constexpr][c++2a] Try-catch blocks in constexpr functions
bruno updated this revision to Diff 176733. bruno added a comment. Update patch after @erik.pilkington review! CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55097/new/ https://reviews.llvm.org/D55097 Files: include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ExprConstant.cpp lib/Sema/SemaDeclCXX.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp test/CXX/drs/dr6xx.cpp www/cxx_status.html Index: www/cxx_status.html === --- www/cxx_status.html +++ www/cxx_status.html @@ -953,13 +953,15 @@ Relaxations of constexpr restrictions http://wg21.link/p1064r0;>P1064R0 - No + No http://wg21.link/p1002r1;>P1002R1 +SVN http://wg21.link/p1327r1;>P1327R1 +No http://wg21.link/p1330r0;>P1330R0 Index: test/CXX/drs/dr6xx.cpp === --- test/CXX/drs/dr6xx.cpp +++ test/CXX/drs/dr6xx.cpp @@ -492,7 +492,13 @@ struct C { constexpr C(NonLiteral); constexpr C(NonLiteral, int) {} // expected-error {{not a literal type}} -constexpr C() try {} catch (...) {} // expected-error {{function try block}} +constexpr C() try {} catch (...) {} +#if __cplusplus <= 201703L +// expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}} +#endif +#if __cplusplus < 201402L +// expected-error@-5 {{use of this statement in a constexpr constructor is a C++14 extension}} +#endif }; struct D { Index: test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions %s -// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y %s +// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -std=c++2a -fcxx-exceptions -DCXX1Y -DCXX2A %s namespace N { typedef char C; @@ -49,8 +50,14 @@ // - its function-body shall not be a function-try-block; struct U { constexpr U() -try // expected-error {{function try block not allowed in constexpr constructor}} +try +#ifndef CXX2A + // expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}} +#endif : u() { +#ifndef CXX1Y + // expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}} +#endif } catch (...) { throw; } Index: test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions %s -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++2a -DCXX1Y -DCXX2A %s namespace N { typedef char C; @@ -78,7 +79,12 @@ }; struct T3 { constexpr T3 =(const T3&) const = default; - // expected-error@-1 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}} +#ifndef CXX2A + // expected-error@-2 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}} +#else + // expected-warning@-4 {{explicitly defaulted copy assignment operator is implicitly deleted}} + // expected-note@-5 {{function is implicitly deleted because its declared type does not match the type of an implicit copy assignment operator}} +#endif }; #endif struct U { @@ -131,7 +137,13 @@ } constexpr int DisallowedStmtsCXX1Y_3() { // - a try-block, - try {} catch (...) {} // expected-error {{statement not allowed in constexpr function}} + try {} catch (...) {} +#ifndef CXX2A + // expected-error@-2 {{use of this statement in a constexpr function is a C++2a extension}} +#ifndef CXX1Y + // expected-error@-4 {{use of this statement in a constexpr function is a C++14 extension}} +#endif +#endif return 0; } constexpr int DisallowedStmtsCXX1Y_4() { Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -1803,7 +1803,7 @@ static bool
[PATCH] D55097: [constexpr][c++2a] Try-catch blocks in constexpr functions
erik.pilkington added a comment. Hi Bruno, thanks for working on this! Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2370 + "use of this statement in a constexpr %select{function|constructor}0 " + "is incompatible with C++ standards before C++20">, + InGroup, DefaultIgnore; I guess this should technically be C++2a Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2431 + "function try block in constexpr %select{function|constructor}0 is " + "incompatible with C++ standards before C++20">, + InGroup, DefaultIgnore; (ditto) Comment at: lib/Sema/SemaDeclCXX.cpp:1913-1916 + case Stmt::CXXCatchStmtClass: +// In case we got a valid constexpr try block, the catch block can be +// ignored since it will never be evaluated in a constexpr context. +return true; I think we still need to check out the catch stmt (even if it'll never be evaluated) to make sure that it doesn't have any prohibited statements. i.e., we should error here: ``` constexpr int f() { try { return 0; } catch (...) { merp: goto merp; } } ``` But I believe that this patch will accept this. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55097/new/ https://reviews.llvm.org/D55097 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55097: [constexpr][c++2a] Try-catch blocks in constexpr functions
bruno updated this revision to Diff 176559. bruno added a comment. Address @rsmith comments CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55097/new/ https://reviews.llvm.org/D55097 Files: include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ExprConstant.cpp lib/Sema/SemaDeclCXX.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp test/CXX/drs/dr6xx.cpp www/cxx_status.html Index: www/cxx_status.html === --- www/cxx_status.html +++ www/cxx_status.html @@ -953,13 +953,15 @@ Relaxations of constexpr restrictions http://wg21.link/p1064r0;>P1064R0 - No + No http://wg21.link/p1002r1;>P1002R1 +SVN http://wg21.link/p1327r1;>P1327R1 +No http://wg21.link/p1330r0;>P1330R0 Index: test/CXX/drs/dr6xx.cpp === --- test/CXX/drs/dr6xx.cpp +++ test/CXX/drs/dr6xx.cpp @@ -492,7 +492,13 @@ struct C { constexpr C(NonLiteral); constexpr C(NonLiteral, int) {} // expected-error {{not a literal type}} -constexpr C() try {} catch (...) {} // expected-error {{function try block}} +constexpr C() try {} catch (...) {} +#if __cplusplus <= 201703L +// expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}} +#endif +#if __cplusplus < 201402L +// expected-error@-5 {{use of this statement in a constexpr constructor is a C++14 extension}} +#endif }; struct D { Index: test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions %s -// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y %s +// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -std=c++2a -fcxx-exceptions -DCXX1Y -DCXX2A %s namespace N { typedef char C; @@ -49,8 +50,14 @@ // - its function-body shall not be a function-try-block; struct U { constexpr U() -try // expected-error {{function try block not allowed in constexpr constructor}} +try +#ifndef CXX2A + // expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}} +#endif : u() { +#ifndef CXX1Y + // expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}} +#endif } catch (...) { throw; } Index: test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions %s -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y -Werror=c++2a-extensions %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++2a -DCXX1Y -DCXX2A %s namespace N { typedef char C; @@ -78,7 +79,12 @@ }; struct T3 { constexpr T3 =(const T3&) const = default; - // expected-error@-1 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}} +#ifndef CXX2A + // expected-error@-2 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}} +#else + // expected-warning@-4 {{explicitly defaulted copy assignment operator is implicitly deleted}} + // expected-note@-5 {{function is implicitly deleted because its declared type does not match the type of an implicit copy assignment operator}} +#endif }; #endif struct U { @@ -131,7 +137,13 @@ } constexpr int DisallowedStmtsCXX1Y_3() { // - a try-block, - try {} catch (...) {} // expected-error {{statement not allowed in constexpr function}} + try {} catch (...) {} +#ifndef CXX2A + // expected-error@-2 {{use of this statement in a constexpr function is a C++2a extension}} +#ifndef CXX1Y + // expected-error@-4 {{use of this statement in a constexpr function is a C++14 extension}} +#endif +#endif return 0; } constexpr int DisallowedStmtsCXX1Y_4() { Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -1803,7 +1803,7 @@ static bool
[PATCH] D55097: [constexpr][c++2a] Try-catch blocks in constexpr functions
rsmith added inline comments. Comment at: lib/AST/ExprConstant.cpp:4278-4287 +// Evaluate try blocks by evaluating all sub statements and keep track +// whether there's a return. +EvalStmtResult ESR = ESR_Succeeded; +for (const Stmt *SubStmt : S->children()) { + EvalStmtResult SubStmtESR = EvaluateStmt(Result, Info, SubStmt, Case); + if (SubStmtESR != ESR_Succeeded && SubStmtESR != ESR_Returned) +return ESR_Failed; The children of a `try` statement are the `try` body followed by the `catch` statements, in order. We only want to evaluate the normal body, so you should just recurse to evaluating `cast(S)->getTryBlock()`... Comment at: lib/AST/ExprConstant.cpp:4290-4294 + case Stmt::CXXCatchStmtClass: +// No need to evaluate catch since it will be ignored in case the try block +// is successfully evaluated. +return ESR_Succeeded; } ... and this should then be unreachable. Comment at: lib/Sema/SemaDeclCXX.cpp:1904-1905 + case Stmt::CXXTryStmtClass: +if (!SemaRef.getLangOpts().CPlusPlus2a) + break; +if (!Cxx1yLoc.isValid()) Is there a reason to not allow this as an extension in earlier language modes? Comment at: lib/Sema/SemaDeclCXX.cpp:1906-1907 + break; +if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getBeginLoc(); +for (Stmt *SubStmt : S->children()) `Cxx1yLoc` isn't right here; we should produce a -Wc++17-compat diagnostic, not a -Wc++14-compat diagnostic. We should probably prefer the `Cxx1zLoc` warning over the `Cxx1yLoc` warning if we have both. Comment at: lib/Sema/SemaDeclCXX.cpp:1915-1922 + case Stmt::CXXCatchStmtClass: +if (!SemaRef.getLangOpts().CPlusPlus2a) + break; +if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getBeginLoc(); +// In case we got a valid constexpr try block, the catch block can be +// ignored since it will never be evaluated in a constexpr context. We should just unconditionally allow `CXXCatchStmt`s (that is, don't bother checking the language mode, just walk the children), since whenever we encounter one we must also have a `CXXTryStmt`, which we'll already have checked. Comment at: lib/Sema/SemaDeclCXX.cpp:1962-1983 +// constexpr function try blocks are allowed in c++2a, assuming that the +// inner statements do also apply to general constexpr rules. +SourceLocation Cxx1yLoc; +for (Stmt *SubStmt : Body->children()) + if (SubStmt && + !CheckConstexprFunctionStmt(*this, Dcl, SubStmt, ReturnStmts, + Cxx1yLoc)) The repetition can be avoided here by walking the children of `Body` (regardless of what kind of statement it is), and checking them all. (We can't *quite* just pass `Body` directly to `CheckConstexprFunctionStmt` because (nested) compound statements aren't permitted until C++14.) Comment at: lib/Sema/SemaDeclCXX.cpp:1973 + << isa(Dcl); +return true; + } Don't return here: we still need to do the other checks below. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D55097/new/ https://reviews.llvm.org/D55097 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D55097: [constexpr][c++2a] Try-catch blocks in constexpr functions
bruno created this revision. bruno added reviewers: rsmith, ahatanak, erik.pilkington. Herald added subscribers: dexonsmith, jkorous. Implement support for try-catch blocks in constexpr functions, as proposed in http://wg21.link/P1002 and voted in San Diego for c++20. The idea is that we can still never throw inside constexpr, so the catch block is never entered. A try-catch block like this: try { f(); } catch (...) { } is then morally equivalent to just { f(); } Same idea should apply for function/constructor try blocks. rdar://problem/45530773 https://reviews.llvm.org/D55097 Files: lib/AST/ExprConstant.cpp lib/Sema/SemaDeclCXX.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp test/CXX/drs/dr6xx.cpp www/cxx_status.html Index: www/cxx_status.html === --- www/cxx_status.html +++ www/cxx_status.html @@ -953,13 +953,15 @@ Relaxations of constexpr restrictions http://wg21.link/p1064r0;>P1064R0 - No + No http://wg21.link/p1002r1;>P1002R1 +Clang 8 http://wg21.link/p1327r1;>P1327R1 +No http://wg21.link/p1330r0;>P1330R0 Index: test/CXX/drs/dr6xx.cpp === --- test/CXX/drs/dr6xx.cpp +++ test/CXX/drs/dr6xx.cpp @@ -492,7 +492,10 @@ struct C { constexpr C(NonLiteral); constexpr C(NonLiteral, int) {} // expected-error {{not a literal type}} -constexpr C() try {} catch (...) {} // expected-error {{function try block}} +constexpr C() try {} catch (...) {} +#if __cplusplus <= 201703L +// expected-error@-2 {{function try block}} +#endif }; struct D { Index: test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions %s // RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y %s +// RUN: %clang_cc1 -verify -std=c++2a -fcxx-exceptions -DCXX1Y -DCXX2A %s namespace N { typedef char C; @@ -49,7 +50,10 @@ // - its function-body shall not be a function-try-block; struct U { constexpr U() -try // expected-error {{function try block not allowed in constexpr constructor}} +try +#ifndef CXX2A +// expected-error@-2 {{function try block not allowed in constexpr constructor}} +#endif : u() { } catch (...) { throw; Index: test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions %s // RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++2a -DCXX1Y -DCXX2A %s namespace N { typedef char C; @@ -78,7 +79,12 @@ }; struct T3 { constexpr T3 =(const T3&) const = default; - // expected-error@-1 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}} +#ifndef CXX2A + // expected-error@-2 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}} +#else + // expected-warning@-4 {{explicitly defaulted copy assignment operator is implicitly deleted}} + // expected-note@-5 {{function is implicitly deleted because its declared type does not match the type of an implicit copy assignment operator}} +#endif }; #endif struct U { @@ -131,7 +137,10 @@ } constexpr int DisallowedStmtsCXX1Y_3() { // - a try-block, - try {} catch (...) {} // expected-error {{statement not allowed in constexpr function}} + try {} catch (...) {} +#ifndef CXX2A + // expected-error@-2 {{statement not allowed in constexpr function}} +#endif return 0; } constexpr int DisallowedStmtsCXX1Y_4() { Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -1900,6 +1900,27 @@ return false; return true; + case Stmt::CXXTryStmtClass: +if (!SemaRef.getLangOpts().CPlusPlus2a) + break; +if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getBeginLoc(); +for (Stmt *SubStmt : S->children()) + if (SubStmt && + !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, + Cxx1yLoc)) +return false; +return true; + + case Stmt::CXXCatchStmtClass: +if (!SemaRef.getLangOpts().CPlusPlus2a) + break; +if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getBeginLoc(); +