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