Skip to content

Commit 5c1399a

Browse files
committed
[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 llvm-svn: 348789
1 parent 5ec1460 commit 5c1399a

File tree

7 files changed

+112
-23
lines changed

7 files changed

+112
-23
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2357,6 +2357,13 @@ def warn_cxx11_compat_constexpr_body_invalid_stmt : Warning<
23572357
"use of this statement in a constexpr %select{function|constructor}0 "
23582358
"is incompatible with C++ standards before C++14">,
23592359
InGroup<CXXPre14Compat>, DefaultIgnore;
2360+
def ext_constexpr_body_invalid_stmt_cxx2a : ExtWarn<
2361+
"use of this statement in a constexpr %select{function|constructor}0 "
2362+
"is a C++2a extension">, InGroup<CXX2a>;
2363+
def warn_cxx17_compat_constexpr_body_invalid_stmt : Warning<
2364+
"use of this statement in a constexpr %select{function|constructor}0 "
2365+
"is incompatible with C++ standards before C++2a">,
2366+
InGroup<CXXPre2aCompat>, DefaultIgnore;
23602367
def ext_constexpr_type_definition : ExtWarn<
23612368
"type definition in a constexpr %select{function|constructor}0 "
23622369
"is a C++14 extension">, InGroup<CXX14>;
@@ -2409,6 +2416,16 @@ def note_constexpr_body_previous_return : Note<
24092416
"previous return statement is here">;
24102417
def err_constexpr_function_try_block : Error<
24112418
"function try block not allowed in constexpr %select{function|constructor}0">;
2419+
2420+
// c++2a function try blocks in constexpr
2421+
def ext_constexpr_function_try_block_cxx2a : ExtWarn<
2422+
"function try block in constexpr %select{function|constructor}0 is "
2423+
"a C++2a extension">, InGroup<CXX2a>;
2424+
def warn_cxx17_compat_constexpr_function_try_block : Warning<
2425+
"function try block in constexpr %select{function|constructor}0 is "
2426+
"incompatible with C++ standards before C++2a">,
2427+
InGroup<CXXPre2aCompat>, DefaultIgnore;
2428+
24122429
def err_constexpr_union_ctor_no_init : Error<
24132430
"constexpr union constructor does not initialize any member">;
24142431
def err_constexpr_ctor_missing_init : Error<

clang/lib/AST/ExprConstant.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4279,6 +4279,9 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
42794279
case Stmt::CaseStmtClass:
42804280
case Stmt::DefaultStmtClass:
42814281
return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(), Case);
4282+
case Stmt::CXXTryStmtClass:
4283+
// Evaluate try blocks by evaluating all sub statements.
4284+
return EvaluateStmt(Result, Info, cast<CXXTryStmt>(S)->getTryBlock(), Case);
42824285
}
42834286
}
42844287

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,7 +1803,7 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
18031803
static bool
18041804
CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
18051805
SmallVectorImpl<SourceLocation> &ReturnStmts,
1806-
SourceLocation &Cxx1yLoc) {
1806+
SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc) {
18071807
// - its function-body shall be [...] a compound-statement that contains only
18081808
switch (S->getStmtClass()) {
18091809
case Stmt::NullStmtClass:
@@ -1840,7 +1840,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
18401840
CompoundStmt *CompStmt = cast<CompoundStmt>(S);
18411841
for (auto *BodyIt : CompStmt->body()) {
18421842
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, BodyIt, ReturnStmts,
1843-
Cxx1yLoc))
1843+
Cxx1yLoc, Cxx2aLoc))
18441844
return false;
18451845
}
18461846
return true;
@@ -1858,11 +1858,11 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
18581858

18591859
IfStmt *If = cast<IfStmt>(S);
18601860
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts,
1861-
Cxx1yLoc))
1861+
Cxx1yLoc, Cxx2aLoc))
18621862
return false;
18631863
if (If->getElse() &&
18641864
!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts,
1865-
Cxx1yLoc))
1865+
Cxx1yLoc, Cxx2aLoc))
18661866
return false;
18671867
return true;
18681868
}
@@ -1881,7 +1881,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
18811881
for (Stmt *SubStmt : S->children())
18821882
if (SubStmt &&
18831883
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
1884-
Cxx1yLoc))
1884+
Cxx1yLoc, Cxx2aLoc))
18851885
return false;
18861886
return true;
18871887

@@ -1896,10 +1896,30 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
18961896
for (Stmt *SubStmt : S->children())
18971897
if (SubStmt &&
18981898
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
1899-
Cxx1yLoc))
1899+
Cxx1yLoc, Cxx2aLoc))
19001900
return false;
19011901
return true;
19021902

1903+
case Stmt::CXXTryStmtClass:
1904+
if (Cxx2aLoc.isInvalid())
1905+
Cxx2aLoc = S->getBeginLoc();
1906+
for (Stmt *SubStmt : S->children()) {
1907+
if (SubStmt &&
1908+
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
1909+
Cxx1yLoc, Cxx2aLoc))
1910+
return false;
1911+
}
1912+
return true;
1913+
1914+
case Stmt::CXXCatchStmtClass:
1915+
// Do not bother checking the language mode (already covered by the
1916+
// try block check).
1917+
if (!CheckConstexprFunctionStmt(SemaRef, Dcl,
1918+
cast<CXXCatchStmt>(S)->getHandlerBlock(),
1919+
ReturnStmts, Cxx1yLoc, Cxx2aLoc))
1920+
return false;
1921+
return true;
1922+
19031923
default:
19041924
if (!isa<Expr>(S))
19051925
break;
@@ -1920,6 +1940,8 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
19201940
///
19211941
/// \return true if the body is OK, false if we have diagnosed a problem.
19221942
bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
1943+
SmallVector<SourceLocation, 4> ReturnStmts;
1944+
19231945
if (isa<CXXTryStmt>(Body)) {
19241946
// C++11 [dcl.constexpr]p3:
19251947
// The definition of a constexpr function shall satisfy the following
@@ -1930,22 +1952,35 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
19301952
// C++11 [dcl.constexpr]p4:
19311953
// In the definition of a constexpr constructor, [...]
19321954
// - its function-body shall not be a function-try-block;
1933-
Diag(Body->getBeginLoc(), diag::err_constexpr_function_try_block)
1955+
//
1956+
// This restriction is lifted in C++2a, as long as inner statements also
1957+
// apply the general constexpr rules.
1958+
Diag(Body->getBeginLoc(),
1959+
!getLangOpts().CPlusPlus2a
1960+
? diag::ext_constexpr_function_try_block_cxx2a
1961+
: diag::warn_cxx17_compat_constexpr_function_try_block)
19341962
<< isa<CXXConstructorDecl>(Dcl);
1935-
return false;
19361963
}
19371964

1938-
SmallVector<SourceLocation, 4> ReturnStmts;
1939-
19401965
// - its function-body shall be [...] a compound-statement that contains only
19411966
// [... list of cases ...]
1942-
CompoundStmt *CompBody = cast<CompoundStmt>(Body);
1943-
SourceLocation Cxx1yLoc;
1944-
for (auto *BodyIt : CompBody->body()) {
1945-
if (!CheckConstexprFunctionStmt(*this, Dcl, BodyIt, ReturnStmts, Cxx1yLoc))
1967+
//
1968+
// Note that walking the children here is enough to properly check for
1969+
// CompoundStmt and CXXTryStmt body.
1970+
SourceLocation Cxx1yLoc, Cxx2aLoc;
1971+
for (Stmt *SubStmt : Body->children()) {
1972+
if (SubStmt &&
1973+
!CheckConstexprFunctionStmt(*this, Dcl, SubStmt, ReturnStmts,
1974+
Cxx1yLoc, Cxx2aLoc))
19461975
return false;
19471976
}
19481977

1978+
if (Cxx2aLoc.isValid())
1979+
Diag(Cxx2aLoc,
1980+
getLangOpts().CPlusPlus2a
1981+
? diag::warn_cxx17_compat_constexpr_body_invalid_stmt
1982+
: diag::ext_constexpr_body_invalid_stmt_cxx2a)
1983+
<< isa<CXXConstructorDecl>(Dcl);
19491984
if (Cxx1yLoc.isValid())
19501985
Diag(Cxx1yLoc,
19511986
getLangOpts().CPlusPlus14

clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions %s
2-
// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y %s
1+
// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions -Werror=c++2a-extensions %s
2+
// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y -Werror=c++2a-extensions %s
3+
// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++2a -DCXX1Y -DCXX2A %s
34

45
namespace N {
56
typedef char C;
@@ -78,7 +79,12 @@ struct T2 {
7879
};
7980
struct T3 {
8081
constexpr T3 &operator=(const T3&) const = default;
81-
// expected-error@-1 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}}
82+
#ifndef CXX2A
83+
// expected-error@-2 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}}
84+
#else
85+
// expected-warning@-4 {{explicitly defaulted copy assignment operator is implicitly deleted}}
86+
// expected-note@-5 {{function is implicitly deleted because its declared type does not match the type of an implicit copy assignment operator}}
87+
#endif
8288
};
8389
#endif
8490
struct U {
@@ -129,9 +135,22 @@ constexpr int DisallowedStmtsCXX1Y_2() {
129135
x:
130136
return 0;
131137
}
138+
constexpr int DisallowedStmtsCXX1Y_2_1() {
139+
try {
140+
return 0;
141+
} catch (...) {
142+
merp: goto merp; // expected-error {{statement not allowed in constexpr function}}
143+
}
144+
}
132145
constexpr int DisallowedStmtsCXX1Y_3() {
133146
// - a try-block,
134-
try {} catch (...) {} // expected-error {{statement not allowed in constexpr function}}
147+
try {} catch (...) {}
148+
#ifndef CXX2A
149+
// expected-error@-2 {{use of this statement in a constexpr function is a C++2a extension}}
150+
#ifndef CXX1Y
151+
// expected-error@-4 {{use of this statement in a constexpr function is a C++14 extension}}
152+
#endif
153+
#endif
135154
return 0;
136155
}
137156
constexpr int DisallowedStmtsCXX1Y_4() {

clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions %s
2-
// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y %s
1+
// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions -Werror=c++2a-extensions %s
2+
// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y -Werror=c++2a-extensions %s
3+
// RUN: %clang_cc1 -verify -std=c++2a -fcxx-exceptions -DCXX1Y -DCXX2A %s
34

45
namespace N {
56
typedef char C;
@@ -49,8 +50,14 @@ namespace IndirectVBase {
4950
// - its function-body shall not be a function-try-block;
5051
struct U {
5152
constexpr U()
52-
try // expected-error {{function try block not allowed in constexpr constructor}}
53+
try
54+
#ifndef CXX2A
55+
// expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}}
56+
#endif
5357
: u() {
58+
#ifndef CXX1Y
59+
// expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}}
60+
#endif
5461
} catch (...) {
5562
throw;
5663
}

clang/test/CXX/drs/dr6xx.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,13 @@ namespace dr647 { // dr647: yes
492492
struct C {
493493
constexpr C(NonLiteral);
494494
constexpr C(NonLiteral, int) {} // expected-error {{not a literal type}}
495-
constexpr C() try {} catch (...) {} // expected-error {{function try block}}
495+
constexpr C() try {} catch (...) {}
496+
#if __cplusplus <= 201703L
497+
// expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}}
498+
#endif
499+
#if __cplusplus < 201402L
500+
// expected-error@-5 {{use of this statement in a constexpr constructor is a C++14 extension}}
501+
#endif
496502
};
497503

498504
struct D {

clang/www/cxx_status.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -953,13 +953,15 @@ <h2 id="cxx20">C++2a implementation status</h2>
953953
<tr>
954954
<td rowspan=4>Relaxations of <tt>constexpr</tt> restrictions</td>
955955
<td><a href="http://wg21.link/p1064r0">P1064R0</a></td>
956-
<td rowspan=4 class="none" align="center">No</td>
956+
<td class="none" align="center">No</td>
957957
</tr>
958958
<tr> <!-- from San Diego -->
959959
<td><a href="http://wg21.link/p1002r1">P1002R1</a></td>
960+
<td class="full" align="center">SVN</td>
960961
</tr>
961962
<tr>
962963
<td><a href="http://wg21.link/p1327r1">P1327R1</a></td>
964+
<td rowspan=2 class="none" align="center">No</td>
963965
</tr>
964966
<tr>
965967
<td><a href="http://wg21.link/p1330r0">P1330R0</a></td>

0 commit comments

Comments
 (0)