hazohelet created this revision. hazohelet added reviewers: tbaeder, cjdb, aaron.ballman. Herald added a project: All. hazohelet requested review of this revision. Herald added a project: clang.
This patch improves diagnostic for clang constexpr evaluator by adding a check for `nullptr` in function pointer call evaluations. This fixes https://github.com/llvm/llvm-project/issues/59872 ex. constexpr int foo(int (*bla)(void)) { return bla(); } static_assert(foo(nullptr) == 1); BEFORE this patch, clang generates the following diagnostic for the code above <source>:5:15: error: static assertion expression is not an integral constant expression static_assert(foo(nullptr) == 1); ^~~~~~~~~~~~~~~~~ <source>:2:10: note: subexpression not valid in a constant expression return bla(); ^ <source>:5:15: note: in call to 'foo(nullptr)' static_assert(foo(nullptr) == 1); ^ 1 error generated. AFTER this patch, `subexpression not valid in a constant expression` note is replaced with `function pointer 'bla' evaluates to a null pointer`. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D145793 Files: clang/include/clang/Basic/DiagnosticASTKinds.td clang/lib/AST/ExprConstant.cpp clang/test/SemaCXX/constant-expression-cxx11.cpp Index: clang/test/SemaCXX/constant-expression-cxx11.cpp =================================================================== --- clang/test/SemaCXX/constant-expression-cxx11.cpp +++ clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -279,7 +279,7 @@ constexpr auto Select(int n) -> int (*)(int) { return n == 2 ? &Double : n == 3 ? &Triple : n == 4 ? &Quadruple : 0; } - constexpr int Apply(int (*F)(int), int n) { return F(n); } // expected-note {{subexpression}} + constexpr int Apply(int (*F)(int), int n) { return F(n); } // expected-note {{function pointer 'F' evaluates to a null pointer}} static_assert(1 + Apply(Select(4), 5) + Apply(Select(3), 7) == 42, ""); Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -7668,6 +7668,11 @@ if (!CalleeLV.getLValueOffset().isZero()) return Error(Callee); + if (CalleeLV.isNullPointer()) { + Info.FFDiag(Callee, diag::note_constexpr_null_callee) + << const_cast<Expr *>(Callee); + return false; + } FD = dyn_cast_or_null<FunctionDecl>( CalleeLV.getLValueBase().dyn_cast<const ValueDecl *>()); if (!FD) Index: clang/include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticASTKinds.td +++ clang/include/clang/Basic/DiagnosticASTKinds.td @@ -127,6 +127,8 @@ "access array element of|perform pointer arithmetic on|" "access real component of|" "access imaginary component of}0 null pointer">; +def note_constexpr_null_callee : Note< + "function pointer '%0' evaluates to a null pointer">; def note_constexpr_function_param_value_unknown : Note< "function parameter %0 with unknown value cannot be used in a constant " "expression">;
Index: clang/test/SemaCXX/constant-expression-cxx11.cpp =================================================================== --- clang/test/SemaCXX/constant-expression-cxx11.cpp +++ clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -279,7 +279,7 @@ constexpr auto Select(int n) -> int (*)(int) { return n == 2 ? &Double : n == 3 ? &Triple : n == 4 ? &Quadruple : 0; } - constexpr int Apply(int (*F)(int), int n) { return F(n); } // expected-note {{subexpression}} + constexpr int Apply(int (*F)(int), int n) { return F(n); } // expected-note {{function pointer 'F' evaluates to a null pointer}} static_assert(1 + Apply(Select(4), 5) + Apply(Select(3), 7) == 42, ""); Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -7668,6 +7668,11 @@ if (!CalleeLV.getLValueOffset().isZero()) return Error(Callee); + if (CalleeLV.isNullPointer()) { + Info.FFDiag(Callee, diag::note_constexpr_null_callee) + << const_cast<Expr *>(Callee); + return false; + } FD = dyn_cast_or_null<FunctionDecl>( CalleeLV.getLValueBase().dyn_cast<const ValueDecl *>()); if (!FD) Index: clang/include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticASTKinds.td +++ clang/include/clang/Basic/DiagnosticASTKinds.td @@ -127,6 +127,8 @@ "access array element of|perform pointer arithmetic on|" "access real component of|" "access imaginary component of}0 null pointer">; +def note_constexpr_null_callee : Note< + "function pointer '%0' evaluates to a null pointer">; def note_constexpr_function_param_value_unknown : Note< "function parameter %0 with unknown value cannot be used in a constant " "expression">;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits