loskutov created this revision.
loskutov added reviewers: llvm-commits, aaron.ballman, doug.gregor.
Herald added a subscriber: cfe-commits.

Starting from C++17, [expr.prim.lambda.closure]p9 requires that "The [lambda to 
function pointer] conversion function [...] has a non-throwing exception 
specification".
This commit adds such a specification to the generated conversion functions.
Pre-C++17 standards don't have this requirement; however, they don't forbid the 
conversion functions to have this specification either.
For the sake of consistency, the specification is added unconditionally, no 
matter what standard revision is used.

Issue related: https://bugs.llvm.org/show_bug.cgi?id=40309


Repository:
  rC Clang

https://reviews.llvm.org/D56992

Files:
  clang/lib/Sema/SemaLambda.cpp
  clang/test/AST/ast-dump-expr.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.lambda/p9.cpp


Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p9.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p9.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++1z %s -verify
+// expected-no-diagnostics
+
+void test_noexcept() {
+  const auto lambda = [](int x) { return x + 1; };
+  static_assert(noexcept((int (*)(int))(lambda)),
+                "Lambda-to-function-pointer conversion is expected to be 
noexcept");
+}
Index: clang/test/AST/ast-dump-expr.cpp
===================================================================
--- clang/test/AST/ast-dump-expr.cpp
+++ clang/test/AST/ast-dump-expr.cpp
@@ -290,7 +290,7 @@
   // CHECK-NEXT: Destructor
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:6, col:8> col:3 operator() 
'auto () const' inline
   // CHECK-NEXT: CompoundStmt
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:8> col:3 implicit 
constexpr operator auto (*)() 'auto (*() const)()' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:8> col:3 implicit 
constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:8> col:3 implicit 
__invoke 'auto ()' static inline
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:7, col:8>
 
@@ -307,7 +307,7 @@
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:16, col:18> col:3 operator() 
'auto (int, ...) const' inline
   // CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} <col:6, col:10> col:10 a 'int'
   // CHECK-NEXT: CompoundStmt
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit 
constexpr operator auto (*)(int, ...) 'auto (*() const)(int, ...)' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit 
constexpr operator auto (*)(int, ...) 'auto (*() const noexcept)(int, ...)' 
inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit 
__invoke 'auto (int, ...)' static inline
   // CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} <col:6, col:10> col:10 a 'int'
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:17, col:18>
@@ -455,7 +455,7 @@
   // CHECK-NEXT: Destructor
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:8, col:19> col:3 constexpr 
operator() 'auto () const' inline
   // CHECK-NEXT: CompoundStmt
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit 
constexpr operator auto (*)() 'auto (*() const)()' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit 
constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit 
__invoke 'auto ()' static inline
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:18, col:19>
 
@@ -471,7 +471,7 @@
   // CHECK-NEXT: Destructor
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:8, col:17> col:3 operator() 
'auto ()' inline
   // CHECK-NEXT: CompoundStmt
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:17> col:3 implicit 
constexpr operator auto (*)() 'auto (*() const)()' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:17> col:3 implicit 
constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:17> col:3 implicit 
__invoke 'auto ()' static inline
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:16, col:17>
 
@@ -487,7 +487,7 @@
   // CHECK-NEXT: Destructor
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:8, col:18> col:3 operator() 
'auto () const noexcept' inline
   // CHECK-NEXT: CompoundStmt
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit 
constexpr operator auto (*)() noexcept 'auto (*() const)() noexcept' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit 
constexpr operator auto (*)() noexcept 'auto (*() const noexcept)() noexcept' 
inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit 
__invoke 'auto () noexcept' static inline
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:17, col:18>
 
@@ -505,7 +505,7 @@
   // CHECK-NEXT: CompoundStmt
   // CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} <col:17, col:24>
   // CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col:24> 'int' 0
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:27> col:3 implicit 
constexpr operator int (*)() 'auto (*() const)() -> int' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:27> col:3 implicit 
constexpr operator int (*)() 'auto (*() const noexcept)() -> int' inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:27> col:3 implicit 
__invoke 'auto () -> int' static inline
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:15, col:27>
   // CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} <col:17, col:24>
@@ -568,4 +568,4 @@
   // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void'{{$}}
   f(x);
 }
-} // namespace test_adl_call_three
\ No newline at end of file
+} // namespace test_adl_call_three
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -1228,8 +1228,11 @@
       S.Context.getDefaultCallingConvention(
       /*IsVariadic=*/false, /*IsCXXMethod=*/true));
   // The conversion function is always const.
+  // C++17 also obliges it to be noexcept (which it in fact is),
+  // and previous standards don't forbid that either.
   ConvExtInfo.TypeQuals = Qualifiers();
   ConvExtInfo.TypeQuals.addConst();
+  ConvExtInfo.ExceptionSpec.Type = EST_BasicNoexcept;
   QualType ConvTy =
       S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo);
 


Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p9.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p9.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++1z %s -verify
+// expected-no-diagnostics
+
+void test_noexcept() {
+  const auto lambda = [](int x) { return x + 1; };
+  static_assert(noexcept((int (*)(int))(lambda)),
+                "Lambda-to-function-pointer conversion is expected to be noexcept");
+}
Index: clang/test/AST/ast-dump-expr.cpp
===================================================================
--- clang/test/AST/ast-dump-expr.cpp
+++ clang/test/AST/ast-dump-expr.cpp
@@ -290,7 +290,7 @@
   // CHECK-NEXT: Destructor
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:6, col:8> col:3 operator() 'auto () const' inline
   // CHECK-NEXT: CompoundStmt
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:8> col:3 implicit constexpr operator auto (*)() 'auto (*() const)()' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:8> col:3 implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:8> col:3 implicit __invoke 'auto ()' static inline
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:7, col:8>
 
@@ -307,7 +307,7 @@
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:16, col:18> col:3 operator() 'auto (int, ...) const' inline
   // CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} <col:6, col:10> col:10 a 'int'
   // CHECK-NEXT: CompoundStmt
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit constexpr operator auto (*)(int, ...) 'auto (*() const)(int, ...)' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit constexpr operator auto (*)(int, ...) 'auto (*() const noexcept)(int, ...)' inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit __invoke 'auto (int, ...)' static inline
   // CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} <col:6, col:10> col:10 a 'int'
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:17, col:18>
@@ -455,7 +455,7 @@
   // CHECK-NEXT: Destructor
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:8, col:19> col:3 constexpr operator() 'auto () const' inline
   // CHECK-NEXT: CompoundStmt
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit constexpr operator auto (*)() 'auto (*() const)()' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:19> col:3 implicit __invoke 'auto ()' static inline
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:18, col:19>
 
@@ -471,7 +471,7 @@
   // CHECK-NEXT: Destructor
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:8, col:17> col:3 operator() 'auto ()' inline
   // CHECK-NEXT: CompoundStmt
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:17> col:3 implicit constexpr operator auto (*)() 'auto (*() const)()' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:17> col:3 implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:17> col:3 implicit __invoke 'auto ()' static inline
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:16, col:17>
 
@@ -487,7 +487,7 @@
   // CHECK-NEXT: Destructor
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:8, col:18> col:3 operator() 'auto () const noexcept' inline
   // CHECK-NEXT: CompoundStmt
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit constexpr operator auto (*)() noexcept 'auto (*() const)() noexcept' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit constexpr operator auto (*)() noexcept 'auto (*() const noexcept)() noexcept' inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:18> col:3 implicit __invoke 'auto () noexcept' static inline
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:17, col:18>
 
@@ -505,7 +505,7 @@
   // CHECK-NEXT: CompoundStmt
   // CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} <col:17, col:24>
   // CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col:24> 'int' 0
-  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:27> col:3 implicit constexpr operator int (*)() 'auto (*() const)() -> int' inline
+  // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} <col:3, col:27> col:3 implicit constexpr operator int (*)() 'auto (*() const noexcept)() -> int' inline
   // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} <col:3, col:27> col:3 implicit __invoke 'auto () -> int' static inline
   // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:15, col:27>
   // CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} <col:17, col:24>
@@ -568,4 +568,4 @@
   // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void'{{$}}
   f(x);
 }
-} // namespace test_adl_call_three
\ No newline at end of file
+} // namespace test_adl_call_three
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -1228,8 +1228,11 @@
       S.Context.getDefaultCallingConvention(
       /*IsVariadic=*/false, /*IsCXXMethod=*/true));
   // The conversion function is always const.
+  // C++17 also obliges it to be noexcept (which it in fact is),
+  // and previous standards don't forbid that either.
   ConvExtInfo.TypeQuals = Qualifiers();
   ConvExtInfo.TypeQuals.addConst();
+  ConvExtInfo.ExceptionSpec.Type = EST_BasicNoexcept;
   QualType ConvTy =
       S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to