From a2b04ad5c4a0f2c1cbe75e206f960cfda4d9e025 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Mon, 21 Jan 2019 16:25:08 +0000 Subject: [PATCH] Mark the lambda function pointer conversion operator as noexcept. This implements CWG DR 1722 and fixes PR40309. Patch by Ignat Loskutov. llvm-svn: 351750 --- clang/lib/Sema/SemaLambda.cpp | 3 ++- clang/test/AST/ast-dump-expr.cpp | 14 +++++++------- clang/test/CXX/drs/dr17xx.cpp | 12 ++++++++++++ .../CXX/expr/expr.prim/expr.prim.lambda/p9.cpp | 8 ++++++++ clang/www/cxx_dr_status.html | 2 +- 5 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 clang/test/CXX/expr/expr.prim/expr.prim.lambda/p9.cpp diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 70fcacb157a1..4ed9fdc359d2 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1227,9 +1227,10 @@ static void addFunctionPointerConversion(Sema &S, FunctionProtoType::ExtProtoInfo ConvExtInfo( S.Context.getDefaultCallingConvention( /*IsVariadic=*/false, /*IsCXXMethod=*/true)); - // The conversion function is always const. + // The conversion function is always const and noexcept. ConvExtInfo.TypeQuals = Qualifiers(); ConvExtInfo.TypeQuals.addConst(); + ConvExtInfo.ExceptionSpec.Type = EST_BasicNoexcept; QualType ConvTy = S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo); diff --git a/clang/test/AST/ast-dump-expr.cpp b/clang/test/AST/ast-dump-expr.cpp index 915a14bc5639..0c85e2eea2df 100644 --- a/clang/test/AST/ast-dump-expr.cpp +++ b/clang/test/AST/ast-dump-expr.cpp @@ -290,7 +290,7 @@ void PrimaryExpressions(Ts... a) { // CHECK-NEXT: Destructor // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 operator() 'auto () const' inline // CHECK-NEXT: CompoundStmt - // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)() 'auto (*() const)()' inline + // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 implicit __invoke 'auto ()' static inline // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} @@ -307,7 +307,7 @@ void PrimaryExpressions(Ts... a) { // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 operator() 'auto (int, ...) const' inline // CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} col:10 a 'int' // CHECK-NEXT: CompoundStmt - // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)(int, ...) 'auto (*() const)(int, ...)' inline + // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)(int, ...) 'auto (*() const noexcept)(int, ...)' inline // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 implicit __invoke 'auto (int, ...)' static inline // CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} col:10 a 'int' // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} @@ -455,7 +455,7 @@ void PrimaryExpressions(Ts... a) { // CHECK-NEXT: Destructor // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 constexpr operator() 'auto () const' inline // CHECK-NEXT: CompoundStmt - // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)() 'auto (*() const)()' inline + // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 implicit __invoke 'auto ()' static inline // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} @@ -471,7 +471,7 @@ void PrimaryExpressions(Ts... a) { // CHECK-NEXT: Destructor // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 operator() 'auto ()' inline // CHECK-NEXT: CompoundStmt - // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)() 'auto (*() const)()' inline + // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 implicit __invoke 'auto ()' static inline // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} @@ -487,7 +487,7 @@ void PrimaryExpressions(Ts... a) { // CHECK-NEXT: Destructor // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 operator() 'auto () const noexcept' inline // CHECK-NEXT: CompoundStmt - // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)() noexcept 'auto (*() const)() noexcept' inline + // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator auto (*)() noexcept 'auto (*() const noexcept)() noexcept' inline // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 implicit __invoke 'auto () noexcept' static inline // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} @@ -505,7 +505,7 @@ void PrimaryExpressions(Ts... a) { // CHECK-NEXT: CompoundStmt // CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} // CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} 'int' 0 - // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator int (*)() 'auto (*() const)() -> int' inline + // CHECK-NEXT: CXXConversionDecl 0x{{[^ ]*}} col:3 implicit constexpr operator int (*)() 'auto (*() const noexcept)() -> int' inline // CHECK-NEXT: CXXMethodDecl 0x{{[^ ]*}} col:3 implicit __invoke 'auto () -> int' static inline // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} // CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} @@ -568,4 +568,4 @@ void NonADLCall3() { // CHECK: CallExpr 0x{{[^ ]*}} ]+}}> 'void'{{$}} f(x); } -} // namespace test_adl_call_three \ No newline at end of file +} // namespace test_adl_call_three diff --git a/clang/test/CXX/drs/dr17xx.cpp b/clang/test/CXX/drs/dr17xx.cpp index a917412adcbd..9f67b242710b 100644 --- a/clang/test/CXX/drs/dr17xx.cpp +++ b/clang/test/CXX/drs/dr17xx.cpp @@ -76,3 +76,15 @@ namespace dr1758 { // dr1758: 3.7 A a{b}; #endif } + +namespace dr1722 { // dr1722: 9.0 +#if __cplusplus >= 201103L +void f() { + const auto lambda = [](int x) { return x + 1; }; + // Without the DR applied, this static_assert would fail. + static_assert( + noexcept((int (*)(int))(lambda)), + "Lambda-to-function-pointer conversion is expected to be noexcept"); +} +#endif +} // namespace dr1722 diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p9.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p9.cpp new file mode 100644 index 000000000000..2d3c69fc38f6 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p9.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++17 %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"); +} diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index d33234ac064d..c0f6a9c340e9 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -10147,7 +10147,7 @@ and POD class 1722 CD4 Should lambda to function pointer conversion function be noexcept? - Unknown + Clang 9.0 1723