c++: constexpr and -fno-elide-constructors [PR101072]
We've been trying for a while to avoid TARGET_EXPRs in template code, but there were still a few that snuck through, and the one in this case broke the code that tried to handle it. Fixed by using IMPLICIT_CONV_EXPR, as we have done elsewhere. I also noticed that finish_compound_literal was assuming that all T{init} were for aggregate T, and we got a few more TARGET_EXPRs from that. Fixed by only messing with TARGET_EXPR if we actually have an aggregate init. PR c++/101072 gcc/cp/ChangeLog: * cp-tree.h (build_implicit_conv_flags): Declare. * call.cc (build_implicit_conv_flags): Split out from... (perform_implicit_conversion_flags): ...here. * decl.cc (check_initializer): Use it. * pt.cc (tsubst_copy_and_build): Remove TARGET_EXPR handling. * semantics.cc (finish_compound_literal): Don't treat scalar values like CONSTRUCTORs. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-empty14a.C: New test.
This commit is contained in:
parent
d43be9dcc1
commit
053bcc97f4
@ -12638,6 +12638,25 @@ can_convert_arg_bad (tree to, tree from, tree arg, int flags,
|
||||
return t != NULL;
|
||||
}
|
||||
|
||||
/* Return an IMPLICIT_CONV_EXPR from EXPR to TYPE with bits set from overload
|
||||
resolution FLAGS. */
|
||||
|
||||
tree
|
||||
build_implicit_conv_flags (tree type, tree expr, int flags)
|
||||
{
|
||||
/* In a template, we are only concerned about determining the
|
||||
type of non-dependent expressions, so we do not have to
|
||||
perform the actual conversion. But for initializers, we
|
||||
need to be able to perform it at instantiation
|
||||
(or instantiate_non_dependent_expr) time. */
|
||||
expr = build1 (IMPLICIT_CONV_EXPR, type, expr);
|
||||
if (!(flags & LOOKUP_ONLYCONVERTING))
|
||||
IMPLICIT_CONV_EXPR_DIRECT_INIT (expr) = true;
|
||||
if (flags & LOOKUP_NO_NARROWING)
|
||||
IMPLICIT_CONV_EXPR_BRACED_INIT (expr) = true;
|
||||
return expr;
|
||||
}
|
||||
|
||||
/* Convert EXPR to TYPE. Return the converted expression.
|
||||
|
||||
Note that we allow bad conversions here because by the time we get to
|
||||
@ -12674,18 +12693,7 @@ perform_implicit_conversion_flags (tree type, tree expr,
|
||||
expr = error_mark_node;
|
||||
}
|
||||
else if (processing_template_decl && conv->kind != ck_identity)
|
||||
{
|
||||
/* In a template, we are only concerned about determining the
|
||||
type of non-dependent expressions, so we do not have to
|
||||
perform the actual conversion. But for initializers, we
|
||||
need to be able to perform it at instantiation
|
||||
(or instantiate_non_dependent_expr) time. */
|
||||
expr = build1 (IMPLICIT_CONV_EXPR, type, expr);
|
||||
if (!(flags & LOOKUP_ONLYCONVERTING))
|
||||
IMPLICIT_CONV_EXPR_DIRECT_INIT (expr) = true;
|
||||
if (flags & LOOKUP_NO_NARROWING)
|
||||
IMPLICIT_CONV_EXPR_BRACED_INIT (expr) = true;
|
||||
}
|
||||
expr = build_implicit_conv_flags (type, expr, flags);
|
||||
else
|
||||
{
|
||||
/* Give a conversion call the same location as expr. */
|
||||
|
@ -6599,6 +6599,7 @@ extern tree strip_top_quals (tree);
|
||||
extern bool reference_related_p (tree, tree);
|
||||
extern bool reference_compatible_p (tree, tree);
|
||||
extern int remaining_arguments (tree);
|
||||
extern tree build_implicit_conv_flags (tree, tree, int);
|
||||
extern tree perform_implicit_conversion (tree, tree, tsubst_flags_t);
|
||||
extern tree perform_implicit_conversion_flags (tree, tree, tsubst_flags_t, int);
|
||||
extern tree build_converted_constant_expr (tree, tree, tsubst_flags_t);
|
||||
|
@ -7235,7 +7235,12 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
|
||||
/* In C++20, the call to build_aggr_init could have created
|
||||
an INIT_EXPR with a CONSTRUCTOR as the RHS to handle
|
||||
A(1, 2). */
|
||||
init = TREE_OPERAND (init_code, 1);
|
||||
tree rhs = TREE_OPERAND (init_code, 1);
|
||||
if (processing_template_decl && TREE_CODE (rhs) == TARGET_EXPR)
|
||||
/* Avoid leaking TARGET_EXPR into template trees. */
|
||||
rhs = build_implicit_conv_flags (type, init, flags);
|
||||
init = rhs;
|
||||
|
||||
init_code = NULL_TREE;
|
||||
/* Don't call digest_init; it's unnecessary and will complain
|
||||
about aggregate initialization of non-aggregate classes. */
|
||||
|
@ -21151,15 +21151,6 @@ tsubst_copy_and_build (tree t,
|
||||
RETURN (build_lambda_object (r));
|
||||
}
|
||||
|
||||
case TARGET_EXPR:
|
||||
/* We can get here for a constant initializer of non-dependent type.
|
||||
FIXME stop folding in cp_parser_initializer_clause. */
|
||||
{
|
||||
tree r = get_target_expr_sfinae (RECUR (TARGET_EXPR_INITIAL (t)),
|
||||
complain);
|
||||
RETURN (r);
|
||||
}
|
||||
|
||||
case TRANSACTION_EXPR:
|
||||
RETURN (tsubst_expr(t, args, complain, in_decl,
|
||||
integral_constant_expression_p));
|
||||
|
@ -3272,12 +3272,17 @@ finish_compound_literal (tree type, tree compound_literal,
|
||||
|
||||
/* Represent other compound literals with TARGET_EXPR so we produce
|
||||
a prvalue, and can elide copies. */
|
||||
if (!VECTOR_TYPE_P (type))
|
||||
if (TREE_CODE (compound_literal) == CONSTRUCTOR
|
||||
|| TREE_CODE (compound_literal) == VEC_INIT_EXPR)
|
||||
{
|
||||
/* The CONSTRUCTOR is now an initializer, not a compound literal. */
|
||||
TREE_HAS_CONSTRUCTOR (compound_literal) = false;
|
||||
if (TREE_CODE (compound_literal) == CONSTRUCTOR)
|
||||
TREE_HAS_CONSTRUCTOR (compound_literal) = false;
|
||||
compound_literal = get_target_expr_sfinae (compound_literal, complain);
|
||||
}
|
||||
else
|
||||
/* For e.g. int{42} just make sure it's a prvalue. */
|
||||
compound_literal = rvalue (compound_literal);
|
||||
|
||||
return compound_literal;
|
||||
}
|
||||
|
11
gcc/testsuite/g++.dg/cpp0x/constexpr-empty14a.C
Normal file
11
gcc/testsuite/g++.dg/cpp0x/constexpr-empty14a.C
Normal file
@ -0,0 +1,11 @@
|
||||
// PR c++/101072
|
||||
// { dg-do compile { target c++11 } }
|
||||
// { dg-additional-options -fno-elide-constructors }
|
||||
|
||||
struct S {};
|
||||
|
||||
template <class T> void
|
||||
foo (S s)
|
||||
{
|
||||
constexpr S x = s;
|
||||
}
|
Loading…
Reference in New Issue
Block a user