r348789 - [constexpr][c++2a] Try-catch blocks in constexpr functions
Bruno Cardoso Lopes via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 10 11:03:12 PST 2018
Author: bruno
Date: Mon Dec 10 11:03:12 2018
New Revision: 348789
URL: http://llvm.org/viewvc/llvm-project?rev=348789&view=rev
Log:
[constexpr][c++2a] Try-catch blocks in constexpr functions
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
Differential Revision: https://reviews.llvm.org/D55097
Modified:
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
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=348789&r1=348788&r2=348789&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Dec 10 11:03:12 2018
@@ -2357,6 +2357,13 @@ def warn_cxx11_compat_constexpr_body_inv
"use of this statement in a constexpr %select{function|constructor}0 "
"is incompatible with C++ standards before C++14">,
InGroup<CXXPre14Compat>, 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<CXX2a>;
+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<CXXPre2aCompat>, DefaultIgnore;
def ext_constexpr_type_definition : ExtWarn<
"type definition in a constexpr %select{function|constructor}0 "
"is a C++14 extension">, InGroup<CXX14>;
@@ -2409,6 +2416,16 @@ def note_constexpr_body_previous_return
"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<CXX2a>;
+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<CXXPre2aCompat>, DefaultIgnore;
+
def err_constexpr_union_ctor_no_init : Error<
"constexpr union constructor does not initialize any member">;
def err_constexpr_ctor_missing_init : Error<
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=348789&r1=348788&r2=348789&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Mon Dec 10 11:03:12 2018
@@ -4279,6 +4279,9 @@ static EvalStmtResult EvaluateStmt(StmtR
case Stmt::CaseStmtClass:
case Stmt::DefaultStmtClass:
return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(), Case);
+ case Stmt::CXXTryStmtClass:
+ // Evaluate try blocks by evaluating all sub statements.
+ return EvaluateStmt(Result, Info, cast<CXXTryStmt>(S)->getTryBlock(), Case);
}
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=348789&r1=348788&r2=348789&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Dec 10 11:03:12 2018
@@ -1803,7 +1803,7 @@ static void CheckConstexprCtorInitialize
static bool
CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
SmallVectorImpl<SourceLocation> &ReturnStmts,
- SourceLocation &Cxx1yLoc) {
+ SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc) {
// - its function-body shall be [...] a compound-statement that contains only
switch (S->getStmtClass()) {
case Stmt::NullStmtClass:
@@ -1840,7 +1840,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef
CompoundStmt *CompStmt = cast<CompoundStmt>(S);
for (auto *BodyIt : CompStmt->body()) {
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, BodyIt, ReturnStmts,
- Cxx1yLoc))
+ Cxx1yLoc, Cxx2aLoc))
return false;
}
return true;
@@ -1858,11 +1858,11 @@ CheckConstexprFunctionStmt(Sema &SemaRef
IfStmt *If = cast<IfStmt>(S);
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts,
- Cxx1yLoc))
+ Cxx1yLoc, Cxx2aLoc))
return false;
if (If->getElse() &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts,
- Cxx1yLoc))
+ Cxx1yLoc, Cxx2aLoc))
return false;
return true;
}
@@ -1881,7 +1881,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef
for (Stmt *SubStmt : S->children())
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc))
+ Cxx1yLoc, Cxx2aLoc))
return false;
return true;
@@ -1896,10 +1896,30 @@ CheckConstexprFunctionStmt(Sema &SemaRef
for (Stmt *SubStmt : S->children())
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc))
+ Cxx1yLoc, Cxx2aLoc))
return false;
return true;
+ case Stmt::CXXTryStmtClass:
+ if (Cxx2aLoc.isInvalid())
+ Cxx2aLoc = S->getBeginLoc();
+ for (Stmt *SubStmt : S->children()) {
+ if (SubStmt &&
+ !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
+ Cxx1yLoc, Cxx2aLoc))
+ return false;
+ }
+ return true;
+
+ case Stmt::CXXCatchStmtClass:
+ // Do not bother checking the language mode (already covered by the
+ // try block check).
+ if (!CheckConstexprFunctionStmt(SemaRef, Dcl,
+ cast<CXXCatchStmt>(S)->getHandlerBlock(),
+ ReturnStmts, Cxx1yLoc, Cxx2aLoc))
+ return false;
+ return true;
+
default:
if (!isa<Expr>(S))
break;
@@ -1920,6 +1940,8 @@ CheckConstexprFunctionStmt(Sema &SemaRef
///
/// \return true if the body is OK, false if we have diagnosed a problem.
bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
+ SmallVector<SourceLocation, 4> ReturnStmts;
+
if (isa<CXXTryStmt>(Body)) {
// C++11 [dcl.constexpr]p3:
// The definition of a constexpr function shall satisfy the following
@@ -1930,22 +1952,35 @@ bool Sema::CheckConstexprFunctionBody(co
// C++11 [dcl.constexpr]p4:
// In the definition of a constexpr constructor, [...]
// - its function-body shall not be a function-try-block;
- Diag(Body->getBeginLoc(), diag::err_constexpr_function_try_block)
+ //
+ // This restriction is lifted in C++2a, as long as inner statements also
+ // apply the general constexpr rules.
+ Diag(Body->getBeginLoc(),
+ !getLangOpts().CPlusPlus2a
+ ? diag::ext_constexpr_function_try_block_cxx2a
+ : diag::warn_cxx17_compat_constexpr_function_try_block)
<< isa<CXXConstructorDecl>(Dcl);
- return false;
}
- SmallVector<SourceLocation, 4> ReturnStmts;
-
// - its function-body shall be [...] a compound-statement that contains only
// [... list of cases ...]
- CompoundStmt *CompBody = cast<CompoundStmt>(Body);
- SourceLocation Cxx1yLoc;
- for (auto *BodyIt : CompBody->body()) {
- if (!CheckConstexprFunctionStmt(*this, Dcl, BodyIt, ReturnStmts, Cxx1yLoc))
+ //
+ // Note that walking the children here is enough to properly check for
+ // CompoundStmt and CXXTryStmt body.
+ SourceLocation Cxx1yLoc, Cxx2aLoc;
+ for (Stmt *SubStmt : Body->children()) {
+ if (SubStmt &&
+ !CheckConstexprFunctionStmt(*this, Dcl, SubStmt, ReturnStmts,
+ Cxx1yLoc, Cxx2aLoc))
return false;
}
+ if (Cxx2aLoc.isValid())
+ Diag(Cxx2aLoc,
+ getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_constexpr_body_invalid_stmt
+ : diag::ext_constexpr_body_invalid_stmt_cxx2a)
+ << isa<CXXConstructorDecl>(Dcl);
if (Cxx1yLoc.isValid())
Diag(Cxx1yLoc,
getLangOpts().CPlusPlus14
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp?rev=348789&r1=348788&r2=348789&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp Mon Dec 10 11:03:12 2018
@@ -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 T2 {
};
struct T3 {
constexpr T3 &operator=(const T3&) const = default;
- // expected-error at -1 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}}
+#ifndef CXX2A
+ // expected-error at -2 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}}
+#else
+ // expected-warning at -4 {{explicitly defaulted copy assignment operator is implicitly deleted}}
+ // expected-note at -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 @@ constexpr int DisallowedStmtsCXX1Y_2() {
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 at -2 {{use of this statement in a constexpr function is a C++2a extension}}
+#ifndef CXX1Y
+ // expected-error at -4 {{use of this statement in a constexpr function is a C++14 extension}}
+#endif
+#endif
return 0;
}
constexpr int DisallowedStmtsCXX1Y_4() {
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp?rev=348789&r1=348788&r2=348789&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp Mon Dec 10 11:03:12 2018
@@ -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 @@ namespace IndirectVBase {
// - 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 at -2 {{function try block in constexpr constructor is a C++2a extension}}
+#endif
: u() {
+#ifndef CXX1Y
+ // expected-error at -2 {{use of this statement in a constexpr constructor is a C++14 extension}}
+#endif
} catch (...) {
throw;
}
Modified: cfe/trunk/test/CXX/drs/dr6xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr6xx.cpp?rev=348789&r1=348788&r2=348789&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr6xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr6xx.cpp Mon Dec 10 11:03:12 2018
@@ -492,7 +492,13 @@ namespace dr647 { // dr647: yes
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 at -2 {{function try block in constexpr constructor is a C++2a extension}}
+#endif
+#if __cplusplus < 201402L
+ // expected-error at -5 {{use of this statement in a constexpr constructor is a C++14 extension}}
+#endif
};
struct D {
Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=348789&r1=348788&r2=348789&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Mon Dec 10 11:03:12 2018
@@ -953,13 +953,15 @@ as the draft C++2a standard evolves.
<tr>
<td rowspan=4>Relaxations of <tt>constexpr</tt> restrictions</td>
<td><a href="http://wg21.link/p1064r0">P1064R0</a></td>
- <td rowspan=4 class="none" align="center">No</td>
+ <td class="none" align="center">No</td>
</tr>
<tr> <!-- from San Diego -->
<td><a href="http://wg21.link/p1002r1">P1002R1</a></td>
+ <td class="full" align="center">SVN</td>
</tr>
<tr>
<td><a href="http://wg21.link/p1327r1">P1327R1</a></td>
+ <td rowspan=2 class="none" align="center">No</td>
</tr>
<tr>
<td><a href="http://wg21.link/p1330r0">P1330R0</a></td>
More information about the cfe-commits
mailing list