From 14da3939da3adcef84816573caa9d93c7367507e Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 28 Aug 2019 02:03:48 +0000 Subject: [PATCH] PR c++/91428 - warn about std::is_constant_evaluated in if constexpr. * cp-tree.h (decl_in_std_namespace_p): Declare. * semantics.c (is_std_constant_evaluated_p): New. (finish_if_stmt_cond): Warn about "std::is_constant_evaluated ()" in an if-constexpr. * typeck.c (decl_in_std_namespace_p): No longer static. * g++.dg/cpp2a/is-constant-evaluated9.C: New test. From-SVN: r274981 --- gcc/cp/ChangeLog | 9 ++++ gcc/cp/cp-tree.h | 1 + gcc/cp/semantics.c | 36 ++++++++++++++ gcc/cp/typeck.c | 2 +- gcc/testsuite/ChangeLog | 5 ++ .../g++.dg/cpp2a/is-constant-evaluated9.C | 49 +++++++++++++++++++ 6 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated9.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 162b2c81c75..c2f19670a24 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2019-08-27 Marek Polacek + + PR c++/91428 - warn about std::is_constant_evaluated in if constexpr. + * cp-tree.h (decl_in_std_namespace_p): Declare. + * semantics.c (is_std_constant_evaluated_p): New. + (finish_if_stmt_cond): Warn about "std::is_constant_evaluated ()" in + an if-constexpr. + * typeck.c (decl_in_std_namespace_p): No longer static. + 2019-08-26 Jason Merrill * decl.c (duplicate_decls): Always merge DECL_DECLARED_CONSTEXPR_P. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 42f180d1dd3..225dbb67c63 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7496,6 +7496,7 @@ extern tree finish_left_unary_fold_expr (tree, int); extern tree finish_right_unary_fold_expr (tree, int); extern tree finish_binary_fold_expr (tree, tree, int); extern bool treat_lvalue_as_rvalue_p (tree, bool); +extern bool decl_in_std_namespace_p (tree); /* in typeck2.c */ extern void require_complete_eh_spec_types (tree, tree); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 1f7745933f9..8603e57e7f7 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -723,6 +723,28 @@ begin_if_stmt (void) return r; } +/* Returns true if FN, a CALL_EXPR, is a call to + std::is_constant_evaluated or __builtin_is_constant_evaluated. */ + +static bool +is_std_constant_evaluated_p (tree fn) +{ + /* std::is_constant_evaluated takes no arguments. */ + if (call_expr_nargs (fn) != 0) + return false; + + tree fndecl = cp_get_callee_fndecl_nofold (fn); + if (fndecl_built_in_p (fndecl, CP_BUILT_IN_IS_CONSTANT_EVALUATED, + BUILT_IN_FRONTEND)) + return true; + + if (!decl_in_std_namespace_p (fndecl)) + return false; + + tree name = DECL_NAME (fndecl); + return name && id_equal (name, "is_constant_evaluated"); +} + /* Process the COND of an if-statement, which may be given by IF_STMT. */ @@ -738,6 +760,20 @@ finish_if_stmt_cond (tree cond, tree if_stmt) converted to bool. */ && TYPE_MAIN_VARIANT (TREE_TYPE (cond)) == boolean_type_node) { + /* if constexpr (std::is_constant_evaluated()) is always true, + so give the user a clue. */ + if (warn_tautological_compare) + { + tree t = cond; + if (TREE_CODE (t) == CLEANUP_POINT_EXPR) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == CALL_EXPR + && is_std_constant_evaluated_p (t)) + warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare, + "%qs always evaluates to true in %", + "std::is_constant_evaluated"); + } + cond = instantiate_non_dependent_expr (cond); cond = cxx_constant_value (cond, NULL_TREE); } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index e2a4f285a72..c09bb309142 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -9328,7 +9328,7 @@ maybe_warn_about_returning_address_of_local (tree retval) /* Returns true if DECL is in the std namespace. */ -static bool +bool decl_in_std_namespace_p (tree decl) { return (decl != NULL_TREE diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cd6fb7fc8f6..ade1a69767f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-08-27 Marek Polacek + + PR c++/91428 - warn about std::is_constant_evaluated in if constexpr. + * g++.dg/cpp2a/is-constant-evaluated9.C: New test. + 2019-08-27 Martin Sebor PR tree-optimization/91567 diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated9.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated9.C new file mode 100644 index 00000000000..37833698992 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated9.C @@ -0,0 +1,49 @@ +// PR c++/91428 - warn about std::is_constant_evaluated in if constexpr. +// { dg-do compile { target c++2a } } +// { dg-options "-Wtautological-compare" } + +namespace std { + constexpr inline bool + is_constant_evaluated () noexcept + { + return __builtin_is_constant_evaluated (); + } +} + +constexpr int +foo(int i) +{ + if constexpr (std::is_constant_evaluated ()) // { dg-warning ".std::is_constant_evaluated. always evaluates to true in .if constexpr." } + return 42; + else + return i; +} + +constexpr int +foo2(int i) +{ + if constexpr (__builtin_is_constant_evaluated ()) // { dg-warning ".std::is_constant_evaluated. always evaluates to true in .if constexpr." } + return 42; + else + return i; +} + +constexpr int +foo3(int i) +{ + // I is not a constant expression but we short-circuit it. + if constexpr (__builtin_is_constant_evaluated () || i) + return 42; + else + return i; +} + +constexpr int +foo4(int i) +{ + const int j = 0; + if constexpr (j && __builtin_is_constant_evaluated ()) + return 42; + else + return i; +} -- 2.30.2