aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-10-28 10:02:34 +0200
committerMartin Liska <mliska@suse.cz>2022-10-28 10:02:34 +0200
commit1eb021edb27e26f95cda63df121f6bc951647599 (patch)
tree7f132fded85bd7d05d81cd4c1227da2fd0c3c2d5 /gcc/cp
parent62e475bad0d668c432bb97113cbf73fa281b8b55 (diff)
parent0607307768b66a90e27c5bc91a247acc938f070e (diff)
downloadgcc-1eb021edb27e26f95cda63df121f6bc951647599.zip
gcc-1eb021edb27e26f95cda63df121f6bc951647599.tar.gz
gcc-1eb021edb27e26f95cda63df121f6bc951647599.tar.bz2
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog31
-rw-r--r--gcc/cp/call.cc148
-rw-r--r--gcc/cp/cp-tree.h28
-rw-r--r--gcc/cp/mangle.cc68
-rw-r--r--gcc/cp/name-lookup.cc7
-rw-r--r--gcc/cp/typeck.cc14
6 files changed, 258 insertions, 38 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 550515c..d065fd1 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,34 @@
+2022-10-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/107379
+ * name-lookup.cc (push_namespace): Call find_namespace_slot again
+ after pushdecl as the hash table might be expanded during pushdecl.
+
+2022-10-27 Nathan Sidwell <nathan@acm.org>
+
+ * mangle.cc (write_closure_template_head): New.
+ (write_closure_type_name): Call it.
+
+2022-10-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/107382
+ PR c++/107383
+ * typeck.cc (cp_build_binary_op): Don't compute semantic_result_type
+ if result_type is NULL.
+
+2022-10-26 Marek Polacek <polacek@redhat.com>
+
+ PR c++/106393
+ * call.cc (expr_represents_temporary_p): New, factored out of...
+ (conv_binds_ref_to_temporary): ...here. Don't return false just
+ because a ck_base is missing. Use expr_represents_temporary_p.
+ (do_warn_dangling_reference): New.
+ (maybe_warn_dangling_reference): New.
+ (extend_ref_init_temps): Call maybe_warn_dangling_reference.
+ * cp-tree.h: Adjust comment.
+ * typeck.cc (check_return_expr): Suppress -Wdangling-reference
+ warnings.
+
2022-10-25 Nathan Sidwell <nathan@acm.org>
* parser.cc (synthesize_implicit_template_parm): Fix thinko about
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 6a34e9c..951b9fd 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9313,6 +9313,16 @@ conv_binds_ref_to_prvalue (conversion *c)
return conv_is_prvalue (next_conversion (c));
}
+/* True iff EXPR represents a (subobject of a) temporary. */
+
+static bool
+expr_represents_temporary_p (tree expr)
+{
+ while (handled_component_p (expr))
+ expr = TREE_OPERAND (expr, 0);
+ return TREE_CODE (expr) == TARGET_EXPR;
+}
+
/* True iff C is a conversion that binds a reference to a temporary.
This is a superset of conv_binds_ref_to_prvalue: here we're also
interested in xvalues. */
@@ -9330,18 +9340,14 @@ conv_binds_ref_to_temporary (conversion *c)
struct Derived : Base {};
const Base& b(Derived{});
where we bind 'b' to the Base subobject of a temporary object of type
- Derived. The subobject is an xvalue; the whole object is a prvalue. */
- if (c->kind != ck_base)
- return false;
- c = next_conversion (c);
- if (c->kind == ck_identity && c->u.expr)
- {
- tree expr = c->u.expr;
- while (handled_component_p (expr))
- expr = TREE_OPERAND (expr, 0);
- if (TREE_CODE (expr) == TARGET_EXPR)
- return true;
- }
+ Derived. The subobject is an xvalue; the whole object is a prvalue.
+
+ The ck_base doesn't have to be present for cases like X{}.m. */
+ if (c->kind == ck_base)
+ c = next_conversion (c);
+ if (c->kind == ck_identity && c->u.expr
+ && expr_represents_temporary_p (c->u.expr))
+ return true;
return false;
}
@@ -13428,6 +13434,121 @@ initialize_reference (tree type, tree expr,
return expr;
}
+/* Helper for maybe_warn_dangling_reference to find a problematic CALL_EXPR
+ that initializes the LHS (and at least one of its arguments represents
+ a temporary, as outlined in maybe_warn_dangling_reference), or NULL_TREE
+ if none found. For instance:
+
+ const S& s = S().self(); // S::self (&TARGET_EXPR <...>)
+ const int& r = (42, f(1)); // f(1)
+ const int& t = b ? f(1) : f(2); // f(1)
+ const int& u = b ? f(1) : f(g); // f(1)
+ const int& v = b ? f(g) : f(2); // f(2)
+ const int& w = b ? f(g) : f(g); // NULL_TREE
+ const int& y = (f(1), 42); // NULL_TREE
+ const int& z = f(f(1)); // f(f(1))
+
+ EXPR is the initializer. */
+
+static tree
+do_warn_dangling_reference (tree expr)
+{
+ STRIP_NOPS (expr);
+ switch (TREE_CODE (expr))
+ {
+ case CALL_EXPR:
+ {
+ tree fndecl = cp_get_callee_fndecl_nofold (expr);
+ if (!fndecl
+ || warning_suppressed_p (fndecl, OPT_Wdangling_reference)
+ || !warning_enabled_at (DECL_SOURCE_LOCATION (fndecl),
+ OPT_Wdangling_reference)
+ /* If the function doesn't return a reference, don't warn. This
+ can be e.g.
+ const int& z = std::min({1, 2, 3, 4, 5, 6, 7});
+ which doesn't dangle: std::min here returns an int. */
+ || !TYPE_REF_OBJ_P (TREE_TYPE (TREE_TYPE (fndecl))))
+ return NULL_TREE;
+
+ /* Here we're looking to see if any of the arguments is a temporary
+ initializing a reference parameter. */
+ for (int i = 0; i < call_expr_nargs (expr); ++i)
+ {
+ tree arg = CALL_EXPR_ARG (expr, i);
+ /* Check that this argument initializes a reference, except for
+ the argument initializing the object of a member function. */
+ if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
+ && !TYPE_REF_P (TREE_TYPE (arg)))
+ continue;
+ /* It could also be another call taking a temporary and returning
+ it and initializing this reference parameter. */
+ if (do_warn_dangling_reference (arg))
+ return expr;
+ STRIP_NOPS (arg);
+ if (TREE_CODE (arg) == ADDR_EXPR)
+ arg = TREE_OPERAND (arg, 0);
+ if (expr_represents_temporary_p (arg))
+ return expr;
+ /* Don't warn about member function like:
+ std::any a(...);
+ S& s = a.emplace<S>({0}, 0);
+ which constructs a new object and returns a reference to it, but
+ we still want to detect:
+ struct S { const S& self () { return *this; } };
+ const S& s = S().self();
+ where 's' dangles. If we've gotten here, the object this function
+ is invoked on is not a temporary. */
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl))
+ break;
+ }
+ return NULL_TREE;
+ }
+ case COMPOUND_EXPR:
+ return do_warn_dangling_reference (TREE_OPERAND (expr, 1));
+ case COND_EXPR:
+ if (tree t = do_warn_dangling_reference (TREE_OPERAND (expr, 1)))
+ return t;
+ return do_warn_dangling_reference (TREE_OPERAND (expr, 2));
+ case PAREN_EXPR:
+ return do_warn_dangling_reference (TREE_OPERAND (expr, 0));
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Implement -Wdangling-reference, to detect cases like
+
+ int n = 1;
+ const int& r = std::max(n - 1, n + 1); // r is dangling
+
+ This creates temporaries from the arguments, returns a reference to
+ one of the temporaries, but both temporaries are destroyed at the end
+ of the full expression.
+
+ This works by checking if a reference is initialized with a function
+ that returns a reference, and at least one parameter of the function
+ is a reference that is bound to a temporary. It assumes that such a
+ function actually returns one of its arguments.
+
+ DECL is the reference being initialized, INIT is the initializer. */
+
+static void
+maybe_warn_dangling_reference (const_tree decl, tree init)
+{
+ if (!warn_dangling_reference)
+ return;
+ if (!TYPE_REF_P (TREE_TYPE (decl)))
+ return;
+ if (tree call = do_warn_dangling_reference (init))
+ {
+ auto_diagnostic_group d;
+ if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wdangling_reference,
+ "possibly dangling reference to a temporary"))
+ inform (EXPR_LOCATION (call), "the temporary was destroyed at "
+ "the end of the full expression %qE", call);
+ }
+}
+
/* If *P is an xvalue expression, prevent temporary lifetime extension if it
gets used to initialize a reference. */
@@ -13525,6 +13646,9 @@ extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups,
tree type = TREE_TYPE (init);
if (processing_template_decl)
return init;
+
+ maybe_warn_dangling_reference (decl, init);
+
if (TYPE_REF_P (type))
init = extend_ref_init_temps_1 (decl, init, cleanups, cond_guard);
else
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 867096b..6d84514 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -459,7 +459,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
DELETE_EXPR_USE_VEC (in DELETE_EXPR).
- (TREE_CALLS_NEW) (in _EXPR or _REF) (commented-out).
ICS_ELLIPSIS_FLAG (in _CONV)
DECL_INITIALIZED_P (in VAR_DECL)
TYPENAME_IS_CLASS_P (in TYPENAME_TYPE)
@@ -4508,30 +4507,6 @@ get_vec_init_expr (tree t)
#define OPAQUE_ENUM_P(TYPE) \
(TREE_CODE (TYPE) == ENUMERAL_TYPE && ENUM_IS_OPAQUE (TYPE))
-/* Determines whether an ENUMERAL_TYPE has an explicit
- underlying type. */
-#define ENUM_FIXED_UNDERLYING_TYPE_P(NODE) (TYPE_LANG_FLAG_5 (NODE))
-
-/* Returns the underlying type of the given enumeration type. The
- underlying type is determined in different ways, depending on the
- properties of the enum:
-
- - In C++0x, the underlying type can be explicitly specified, e.g.,
-
- enum E1 : char { ... } // underlying type is char
-
- - In a C++0x scoped enumeration, the underlying type is int
- unless otherwises specified:
-
- enum class E2 { ... } // underlying type is int
-
- - Otherwise, the underlying type is determined based on the
- values of the enumerators. In this case, the
- ENUM_UNDERLYING_TYPE will not be set until after the definition
- of the enumeration is completed by finish_enum. */
-#define ENUM_UNDERLYING_TYPE(TYPE) \
- TREE_TYPE (ENUMERAL_TYPE_CHECK (TYPE))
-
/* [dcl.init.aggr]
An aggregate is an array or a class with no user-provided
@@ -4567,6 +4542,9 @@ get_vec_init_expr (tree t)
When appearing in a CONSTRUCTOR, the expression is an unconverted
compound literal.
+ When appearing in a CALL_EXPR, it means that it is a call to
+ a constructor.
+
When appearing in a FIELD_DECL, it means that this field
has been duly initialized in its constructor. */
#define TREE_HAS_CONSTRUCTOR(NODE) (TREE_LANG_FLAG_4 (NODE))
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 1215463..e396218 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -1727,6 +1727,66 @@ write_unnamed_type_name (const tree type)
write_compact_number (discriminator);
}
+// A template head, for templated lambdas.
+// <template-head> ::= Tp* Ty
+// Tp* Tn <type>
+// Tp* Tt <template-head> E
+// New in ABI=18. Returns true iff we emitted anything -- used for ABI
+// version warning.
+
+static bool
+write_closure_template_head (tree tmpl)
+{
+ bool any = false;
+
+ // We only need one level of template parms
+ tree inner = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
+
+ for (int ix = 0, len = TREE_VEC_LENGTH (inner); ix != len; ix++)
+ {
+ tree parm = TREE_VEC_ELT (inner, ix);
+ if (parm == error_mark_node)
+ continue;
+ parm = TREE_VALUE (parm);
+
+ if (DECL_VIRTUAL_P (parm))
+ // A synthetic parm, we're done.
+ break;
+
+ any = true;
+ if (abi_version_at_least (18))
+ {
+ if (TREE_CODE (parm) == PARM_DECL
+ ? TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
+ : TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm)))
+ write_string ("Tp");
+
+ switch (TREE_CODE (parm))
+ {
+ default:
+ gcc_unreachable ();
+
+ case TYPE_DECL:
+ write_string ("Ty");
+ break;
+
+ case PARM_DECL:
+ write_string ("Tn");
+ write_type (TREE_TYPE (parm));
+ break;
+
+ case TEMPLATE_DECL:
+ write_string ("Tt");
+ write_closure_template_head (parm);
+ write_string ("E");
+ break;
+ }
+ }
+ }
+
+ return any;
+}
+
/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
<lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters */
@@ -1740,6 +1800,14 @@ write_closure_type_name (const tree type)
MANGLE_TRACE_TREE ("closure-type-name", type);
write_string ("Ul");
+
+ if (auto ti = maybe_template_info (fn))
+ if (write_closure_template_head (TI_TEMPLATE (ti)))
+ // If there were any explicit template parms, we may need to
+ // issue a mangling diagnostic.
+ if (abi_warn_or_compat_version_crosses (18))
+ G.need_abi_warning = true;
+
write_method_parms (parms, /*method_p=*/1, fn);
write_char ('E');
write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda));
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 14e937d..dfa6fb4 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -8596,6 +8596,13 @@ push_namespace (tree name, bool make_inline)
/* This should find the slot created by pushdecl. */
gcc_checking_assert (slot && *slot == ns);
}
+ else
+ {
+ /* pushdecl could have expanded the hash table, so
+ slot might be invalid. */
+ slot = find_namespace_slot (current_namespace, name);
+ gcc_checking_assert (slot);
+ }
make_namespace_finish (ns, slot);
/* Add the anon using-directive here, we don't do it in
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index ab6979b..2e0fd8f 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -6179,7 +6179,8 @@ cp_build_binary_op (const op_location_t &location,
}
if (may_need_excess_precision
&& (orig_type0 != type0 || orig_type1 != type1)
- && build_type == NULL_TREE)
+ && build_type == NULL_TREE
+ && result_type)
{
gcc_assert (common);
semantic_result_type = cp_common_type (orig_type0, orig_type1);
@@ -11246,6 +11247,17 @@ check_return_expr (tree retval, bool *no_warning)
if (processing_template_decl)
return saved_retval;
+ /* A naive attempt to reduce the number of -Wdangling-reference false
+ positives: if we know that this function can return a variable with
+ static storage duration rather than one of its parameters, suppress
+ the warning. */
+ if (warn_dangling_reference
+ && TYPE_REF_P (functype)
+ && bare_retval
+ && VAR_P (bare_retval)
+ && TREE_STATIC (bare_retval))
+ suppress_warning (current_function_decl, OPT_Wdangling_reference);
+
/* Actually copy the value returned into the appropriate location. */
if (retval && retval != result)
retval = cp_build_init_expr (result, retval);