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 @@
     <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">Clang 8</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>
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 &operator=(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();
+    // 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;
+
   default:
     if (!isa<Expr>(S))
       break;
@@ -1920,6 +1941,8 @@
 ///
 /// \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,12 +1953,25 @@
     // 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)
-        << isa<CXXConstructorDecl>(Dcl);
-    return false;
-  }
+    if (!getLangOpts().CPlusPlus2a) {
+      Diag(Body->getBeginLoc(), diag::err_constexpr_function_try_block)
+          << isa<CXXConstructorDecl>(Dcl);
+      return false;
+    }
 
-  SmallVector<SourceLocation, 4> ReturnStmts;
+    // 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))
+        return false;
+    if (Cxx1yLoc.isValid())
+      Diag(Cxx1yLoc, diag::warn_cxx11_compat_constexpr_body_invalid_stmt)
+          << isa<CXXConstructorDecl>(Dcl);
+    return true;
+  }
 
   // - its function-body shall be [...] a compound-statement that contains only
   //   [... list of cases ...]
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -4274,6 +4274,23 @@
   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 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;
+      if (SubStmtESR == ESR_Returned)
+        ESR = SubStmtESR;
+    }
+    return ESR;
+  }
+  case Stmt::CXXCatchStmtClass:
+    // No need to evaluate catch since it will be ignored in case the try block
+    // is successfully evaluated.
+    return ESR_Succeeded;
   }
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to