diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index f57341977748dbef68355e492fc6d328fcea21a5..206e791fcfd7f15038609fb89e399e7ebe434f53 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -1336,9 +1336,27 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) break; case RETURN_EXPR: - if (TREE_OPERAND (stmt, 0) && is_invisiref_parm (TREE_OPERAND (stmt, 0))) - /* Don't dereference an invisiref RESULT_DECL inside a RETURN_EXPR. */ - *walk_subtrees = 0; + if (TREE_OPERAND (stmt, 0)) + { + if (is_invisiref_parm (TREE_OPERAND (stmt, 0))) + /* Don't dereference an invisiref RESULT_DECL inside a + RETURN_EXPR. */ + *walk_subtrees = 0; + if (RETURN_EXPR_LOCAL_ADDR_P (stmt)) + { + /* Don't return the address of a local variable. */ + tree *p = &TREE_OPERAND (stmt, 0); + while (TREE_CODE (*p) == COMPOUND_EXPR) + p = &TREE_OPERAND (*p, 0); + if (TREE_CODE (*p) == INIT_EXPR) + { + tree op = TREE_OPERAND (*p, 1); + tree new_op = build2 (COMPOUND_EXPR, TREE_TYPE (op), op, + build_zero_cst (TREE_TYPE (op))); + TREE_OPERAND (*p, 1) = new_op; + } + } + } break; case OMP_CLAUSE: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3de0e154c124c880629d80cdfe569d58fb45b577..e0c181d9aef271f0d133bbc23f29d958a818cf23 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -447,6 +447,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; INIT_EXPR_NRV_P (in INIT_EXPR) ATOMIC_CONSTR_MAP_INSTANTIATED_P (in ATOMIC_CONSTR) contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) + RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR) 1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -4071,6 +4072,11 @@ struct GTY(()) lang_decl { (LANG_DECL_FN_CHECK (FUNCTION_DECL_CHECK (NODE)) \ ->u.saved_auto_return_type) +/* In a RETURN_EXPR, whether the expression refers to the address + of a local variable. */ +#define RETURN_EXPR_LOCAL_ADDR_P(NODE) \ + TREE_LANG_FLAG_0 (RETURN_EXPR_CHECK (NODE)) + /* True if NODE is an implicit INDIRECT_REF from convert_from_reference. */ #define REFERENCE_REF_P(NODE) \ (INDIRECT_REF_P (NODE) \ @@ -8139,7 +8145,7 @@ extern tree composite_pointer_type (const op_location_t &, tsubst_flags_t); extern tree merge_types (tree, tree); extern tree strip_array_domain (tree); -extern tree check_return_expr (tree, bool *); +extern tree check_return_expr (tree, bool *, bool *); extern tree spaceship_type (tree, tsubst_flags_t = tf_warning_or_error); extern tree genericize_spaceship (location_t, tree, tree, tree); extern tree cp_build_binary_op (const op_location_t &, diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 8fb47fd179eb2af2e82bf31d188023e9b9d41de9..720521b7f1aa0986d2d35f798ba3a62486e3c3d5 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -1240,8 +1240,9 @@ finish_return_stmt (tree expr) { tree r; bool no_warning; + bool dangling; - expr = check_return_expr (expr, &no_warning); + expr = check_return_expr (expr, &no_warning, &dangling); if (error_operand_p (expr) || (flag_openmp && !check_omp_return ())) @@ -1259,6 +1260,7 @@ finish_return_stmt (tree expr) } r = build_stmt (input_location, RETURN_EXPR, expr); + RETURN_EXPR_LOCAL_ADDR_P (r) = dangling; if (no_warning) suppress_warning (r, OPT_Wreturn_type); r = maybe_cleanup_point_expr_void (r); diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 859b133a18d8967acd7b573bac6b96e8ada13322..d5c0c85ed51b93b6e2a27ca2807e890047e57083 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -10920,10 +10920,11 @@ maybe_warn_pessimizing_move (tree expr, tree type, bool return_p) change RETVAL into the function return type, and to assign it to the DECL_RESULT for the function. Set *NO_WARNING to true if code reaches end of non-void function warning shouldn't be issued - on this RETURN_EXPR. */ + on this RETURN_EXPR. Set *DANGLING to true if code returns the + address of a local variable. */ tree -check_return_expr (tree retval, bool *no_warning) +check_return_expr (tree retval, bool *no_warning, bool *dangling) { tree result; /* The type actually returned by the function. */ @@ -10935,6 +10936,7 @@ check_return_expr (tree retval, bool *no_warning) location_t loc = cp_expr_loc_or_input_loc (retval); *no_warning = false; + *dangling = false; /* A `volatile' function is one that isn't supposed to return, ever. (This is a G++ extension, used to get better code for functions @@ -11273,8 +11275,7 @@ check_return_expr (tree retval, bool *no_warning) else if (!processing_template_decl && maybe_warn_about_returning_address_of_local (retval, loc) && INDIRECT_TYPE_P (valtype)) - retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval, - build_zero_cst (TREE_TYPE (retval))); + *dangling = true; } /* A naive attempt to reduce the number of -Wdangling-reference false diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C new file mode 100644 index 0000000000000000000000000000000000000000..cca13302238003b5e4cfeb1dac555d93b45854b8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C @@ -0,0 +1,10 @@ +// { dg-do compile { target c++14 } } +// { dg-options "-Wno-return-local-addr" } +// PR c++/110619 + +constexpr auto f() { + int i = 0; + return &i; +}; + +static_assert( f() != nullptr );