Implement N3653 (Member initializers and aggregates) and fix references to 'this' in constexpr constructors.
Implement N3653 (Member initializers and aggregates) and fix references to 'this' in constexpr constructors. * class.c (check_field_decls): In C++14 an NSDMI does not make the class non-aggregate. * constexpr.c (struct constexpr_ctx): New. (cxx_bind_parameters_in_call): Handle 'this'. (cxx_eval_call_expression): Create new constexpr_ctx. (cxx_eval_component_reference): Check CONSTRUCTOR_NO_IMPLICIT_ZERO. (initialized_type, init_subob_ctx, verify_ctor_sanity): New. (cxx_eval_bare_aggregate): Use them. Build CONSTRUCTOR early. (cxx_eval_vec_init_1): Likewise. (cxx_eval_constant_expression) [PARM_DECL]: Allow 'this'. [TARGET_EXPR]: Build new constexpr_ctx. [PLACEHOLDER_EXPR]: New. (cxx_eval_outermost_constant_expr): Build new constexpr_ctx. Add object parameter. (is_sub_constant_expr): Build new constexpr_ctx. (potential_constant_expression_1): Handle PLACEHOLDER_EXPR. Allow 'this'. * cp-gimplify.c (cp_gimplify_init_expr): Call replace_placeholders. * cp-tree.h (CONSTRUCTOR_NO_IMPLICIT_ZERO): New. * error.c (dump_expr): Handle PLACEHOLDER_EXPR. * init.c (get_nsdmi): Generate PLACEHOLDER_EXPR. * tree.c (lvalue_kind): Handle PLACEHOLDER_EXPR. (build_ctor_subob_ref, replace_placeholders): New. * typeck2.c (store_init_value): Use replace_placeholders. (process_init_constructor_record): Make zero-init before NSDMI explicit. From-SVN: r216750
This commit is contained in:
parent
ddc8de034a
commit
3e605b20a0
|
@ -1,3 +1,34 @@
|
|||
2014-10-24 Jason Merrill <jason@redhat.com>
|
||||
|
||||
Implement N3653 (Member initializers and aggregates) and fix
|
||||
references to 'this' in constexpr constructors.
|
||||
* class.c (check_field_decls): In C++14 an NSDMI does not make the
|
||||
class non-aggregate.
|
||||
* constexpr.c (struct constexpr_ctx): New.
|
||||
(cxx_bind_parameters_in_call): Handle 'this'.
|
||||
(cxx_eval_call_expression): Create new constexpr_ctx.
|
||||
(cxx_eval_component_reference): Check CONSTRUCTOR_NO_IMPLICIT_ZERO.
|
||||
(initialized_type, init_subob_ctx, verify_ctor_sanity): New.
|
||||
(cxx_eval_bare_aggregate): Use them. Build CONSTRUCTOR early.
|
||||
(cxx_eval_vec_init_1): Likewise.
|
||||
(cxx_eval_constant_expression) [PARM_DECL]: Allow 'this'.
|
||||
[TARGET_EXPR]: Build new constexpr_ctx.
|
||||
[PLACEHOLDER_EXPR]: New.
|
||||
(cxx_eval_outermost_constant_expr): Build new constexpr_ctx. Add
|
||||
object parameter.
|
||||
(is_sub_constant_expr): Build new constexpr_ctx.
|
||||
(potential_constant_expression_1): Handle PLACEHOLDER_EXPR.
|
||||
Allow 'this'.
|
||||
* cp-gimplify.c (cp_gimplify_init_expr): Call replace_placeholders.
|
||||
* cp-tree.h (CONSTRUCTOR_NO_IMPLICIT_ZERO): New.
|
||||
* error.c (dump_expr): Handle PLACEHOLDER_EXPR.
|
||||
* init.c (get_nsdmi): Generate PLACEHOLDER_EXPR.
|
||||
* tree.c (lvalue_kind): Handle PLACEHOLDER_EXPR.
|
||||
(build_ctor_subob_ref, replace_placeholders): New.
|
||||
* typeck2.c (store_init_value): Use replace_placeholders.
|
||||
(process_init_constructor_record): Make zero-init before NSDMI
|
||||
explicit.
|
||||
|
||||
2014-10-27 Andrew MacLeod <amacleod@redhat.com>
|
||||
|
||||
* cp-gimplify.c: Adjust include files.
|
||||
|
|
|
@ -3659,8 +3659,8 @@ check_field_decls (tree t, tree *access_decls,
|
|||
|
||||
/* Now that we've removed bit-field widths from DECL_INITIAL,
|
||||
anything left in DECL_INITIAL is an NSDMI that makes the class
|
||||
non-aggregate. */
|
||||
if (DECL_INITIAL (x))
|
||||
non-aggregate in C++11. */
|
||||
if (DECL_INITIAL (x) && cxx_dialect < cxx14)
|
||||
CLASSTYPE_NON_AGGREGATE (t) = true;
|
||||
|
||||
/* If any field is const, the structure type is pseudo-const. */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -495,6 +495,10 @@ cp_gimplify_init_expr (tree *expr_p)
|
|||
TREE_TYPE (from) = void_type_node;
|
||||
}
|
||||
|
||||
if (cxx_dialect >= cxx14 && TREE_CODE (sub) == CONSTRUCTOR)
|
||||
/* Handle aggregate NSDMI. */
|
||||
replace_placeholders (sub, to);
|
||||
|
||||
if (t == sub)
|
||||
break;
|
||||
else
|
||||
|
|
|
@ -98,6 +98,7 @@ c-common.h, not after.
|
|||
DECL_FINAL_P (in FUNCTION_DECL)
|
||||
QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
|
||||
DECLTYPE_FOR_INIT_CAPTURE (in DECLTYPE_TYPE)
|
||||
CONSTRUCTOR_NO_IMPLICIT_ZERO (in CONSTRUCTOR)
|
||||
2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
|
||||
ICS_THIS_FLAG (in _CONV)
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
|
||||
|
@ -3479,6 +3480,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
|
|||
B b{1,2}, not B b({1,2}) or B b = {1,2}. */
|
||||
#define CONSTRUCTOR_IS_DIRECT_INIT(NODE) (TREE_LANG_FLAG_0 (CONSTRUCTOR_CHECK (NODE)))
|
||||
|
||||
/* True if an uninitialized element in NODE should not be treated as
|
||||
implicitly value-initialized. Only used in constexpr evaluation. */
|
||||
#define CONSTRUCTOR_NO_IMPLICIT_ZERO(NODE) \
|
||||
(TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (NODE)))
|
||||
|
||||
#define DIRECT_LIST_INIT_P(NODE) \
|
||||
(BRACE_ENCLOSED_INITIALIZER_P (NODE) && CONSTRUCTOR_IS_DIRECT_INIT (NODE))
|
||||
|
||||
|
@ -6033,6 +6039,8 @@ extern tree bind_template_template_parm (tree, tree);
|
|||
extern tree array_type_nelts_total (tree);
|
||||
extern tree array_type_nelts_top (tree);
|
||||
extern tree break_out_target_exprs (tree);
|
||||
extern tree build_ctor_subob_ref (tree, tree, tree);
|
||||
extern tree replace_placeholders (tree, tree);
|
||||
extern tree get_type_decl (tree);
|
||||
extern tree decl_namespace_context (tree);
|
||||
extern bool decl_anon_ns_mem_p (const_tree);
|
||||
|
@ -6320,9 +6328,9 @@ extern bool potential_constant_expression (tree);
|
|||
extern bool potential_rvalue_constant_expression (tree);
|
||||
extern bool require_potential_constant_expression (tree);
|
||||
extern bool require_potential_rvalue_constant_expression (tree);
|
||||
extern tree cxx_constant_value (tree);
|
||||
extern tree maybe_constant_value (tree);
|
||||
extern tree maybe_constant_init (tree);
|
||||
extern tree cxx_constant_value (tree, tree = NULL_TREE);
|
||||
extern tree maybe_constant_value (tree, tree = NULL_TREE);
|
||||
extern tree maybe_constant_init (tree, tree = NULL_TREE);
|
||||
extern bool is_sub_constant_expr (tree);
|
||||
extern bool reduced_constant_expression_p (tree);
|
||||
extern bool is_instantiation_of_constexpr (tree);
|
||||
|
|
|
@ -2673,6 +2673,10 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
|
|||
pp_cxx_right_paren (pp);
|
||||
break;
|
||||
|
||||
case PLACEHOLDER_EXPR:
|
||||
pp_string (pp, M_("*this"));
|
||||
break;
|
||||
|
||||
/* This list is incomplete, but should suffice for now.
|
||||
It is very important that `sorry' does not call
|
||||
`report_error_function'. That could cause an infinite loop. */
|
||||
|
|
|
@ -540,7 +540,12 @@ get_nsdmi (tree member, bool in_ctor)
|
|||
tree save_ccp = current_class_ptr;
|
||||
tree save_ccr = current_class_ref;
|
||||
if (!in_ctor)
|
||||
inject_this_parameter (DECL_CONTEXT (member), TYPE_UNQUALIFIED);
|
||||
{
|
||||
/* Use a PLACEHOLDER_EXPR when we don't have a 'this' parameter to
|
||||
refer to; constexpr evaluation knows what to do with it. */
|
||||
current_class_ref = build0 (PLACEHOLDER_EXPR, DECL_CONTEXT (member));
|
||||
current_class_ptr = build_address (current_class_ref);
|
||||
}
|
||||
if (DECL_LANG_SPECIFIC (member) && DECL_TEMPLATE_INFO (member))
|
||||
{
|
||||
/* Do deferred instantiation of the NSDMI. */
|
||||
|
@ -560,7 +565,7 @@ get_nsdmi (tree member, bool in_ctor)
|
|||
error ("constructor required before non-static data member "
|
||||
"for %qD has been parsed", member);
|
||||
DECL_INITIAL (member) = error_mark_node;
|
||||
init = NULL_TREE;
|
||||
init = error_mark_node;
|
||||
}
|
||||
/* Strip redundant TARGET_EXPR so we don't need to remap it, and
|
||||
so the aggregate init code below will see a CONSTRUCTOR. */
|
||||
|
@ -1723,7 +1728,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
tree fn = get_callee_fndecl (rval);
|
||||
if (fn && DECL_DECLARED_CONSTEXPR_P (fn))
|
||||
{
|
||||
tree e = maybe_constant_init (rval);
|
||||
tree e = maybe_constant_init (rval, exp);
|
||||
if (TREE_CONSTANT (e))
|
||||
rval = build2 (INIT_EXPR, type, exp, e);
|
||||
}
|
||||
|
|
|
@ -158,6 +158,7 @@ lvalue_kind (const_tree ref)
|
|||
case ARRAY_NOTATION_REF:
|
||||
case PARM_DECL:
|
||||
case RESULT_DECL:
|
||||
case PLACEHOLDER_EXPR:
|
||||
return clk_ordinary;
|
||||
|
||||
/* A scope ref in a template, left as SCOPE_REF to support later
|
||||
|
@ -2450,6 +2451,103 @@ break_out_target_exprs (tree t)
|
|||
return t;
|
||||
}
|
||||
|
||||
/* Build an expression for the subobject of OBJ at CONSTRUCTOR index INDEX,
|
||||
which we expect to have type TYPE. */
|
||||
|
||||
tree
|
||||
build_ctor_subob_ref (tree index, tree type, tree obj)
|
||||
{
|
||||
if (index == NULL_TREE)
|
||||
/* Can't refer to a particular member of a vector. */
|
||||
obj = NULL_TREE;
|
||||
else if (TREE_CODE (index) == INTEGER_CST)
|
||||
obj = cp_build_array_ref (input_location, obj, index, tf_none);
|
||||
else
|
||||
obj = build_class_member_access_expr (obj, index, NULL_TREE,
|
||||
/*reference*/false, tf_none);
|
||||
if (obj)
|
||||
gcc_assert (same_type_ignoring_top_level_qualifiers_p (type,
|
||||
TREE_TYPE (obj)));
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* Like substitute_placeholder_in_expr, but handle C++ tree codes and
|
||||
build up subexpressions as we go deeper. */
|
||||
|
||||
struct replace_placeholders_t
|
||||
{
|
||||
tree obj;
|
||||
hash_set<tree> *pset;
|
||||
};
|
||||
|
||||
static tree
|
||||
replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
|
||||
{
|
||||
tree obj = static_cast<tree>(data_);
|
||||
|
||||
if (TREE_CONSTANT (*t))
|
||||
{
|
||||
*walk_subtrees = false;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
switch (TREE_CODE (*t))
|
||||
{
|
||||
case PLACEHOLDER_EXPR:
|
||||
gcc_assert (same_type_ignoring_top_level_qualifiers_p
|
||||
(TREE_TYPE (*t), TREE_TYPE (obj)));
|
||||
*t = obj;
|
||||
*walk_subtrees = false;
|
||||
break;
|
||||
|
||||
case TARGET_EXPR:
|
||||
/* Don't mess with placeholders in an unrelated object. */
|
||||
*walk_subtrees = false;
|
||||
break;
|
||||
|
||||
case CONSTRUCTOR:
|
||||
{
|
||||
constructor_elt *ce;
|
||||
vec<constructor_elt,va_gc> *v = CONSTRUCTOR_ELTS (*t);
|
||||
for (unsigned i = 0; vec_safe_iterate (v, i, &ce); ++i)
|
||||
{
|
||||
tree *valp = &ce->value;
|
||||
tree type = TREE_TYPE (*valp);
|
||||
tree subob = obj;
|
||||
|
||||
if (TREE_CODE (*valp) == CONSTRUCTOR
|
||||
&& AGGREGATE_TYPE_P (type))
|
||||
{
|
||||
subob = build_ctor_subob_ref (ce->index, type, obj);
|
||||
if (TREE_CODE (*valp) == TARGET_EXPR)
|
||||
valp = &TARGET_EXPR_INITIAL (*valp);
|
||||
}
|
||||
|
||||
cp_walk_tree (valp, replace_placeholders_r,
|
||||
subob, NULL);
|
||||
}
|
||||
*walk_subtrees = false;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
tree
|
||||
replace_placeholders (tree exp, tree obj)
|
||||
{
|
||||
hash_set<tree> pset;
|
||||
tree *tp = &exp;
|
||||
if (TREE_CODE (exp) == TARGET_EXPR)
|
||||
tp = &TARGET_EXPR_INITIAL (exp);
|
||||
cp_walk_tree (tp, replace_placeholders_r, obj, NULL);
|
||||
return exp;
|
||||
}
|
||||
|
||||
/* Similar to `build_nt', but for template definitions of dependent
|
||||
expressions */
|
||||
|
||||
|
|
|
@ -806,15 +806,19 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
|
|||
&& !require_potential_constant_expression (value))
|
||||
value = error_mark_node;
|
||||
else
|
||||
value = cxx_constant_value (value);
|
||||
value = cxx_constant_value (value, decl);
|
||||
}
|
||||
value = maybe_constant_init (value);
|
||||
value = maybe_constant_init (value, decl);
|
||||
const_init = (reduced_constant_expression_p (value)
|
||||
|| error_operand_p (value));
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
|
||||
TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
|
||||
}
|
||||
|
||||
if (cxx_dialect >= cxx14)
|
||||
/* Handle aggregate NSDMI in non-constant initializers, too. */
|
||||
value = replace_placeholders (value, decl);
|
||||
|
||||
/* If the initializer is not a constant, fill in DECL_INITIAL with
|
||||
the bits that are constant, and then return an expression that
|
||||
will perform the dynamic initialization. */
|
||||
|
@ -1292,9 +1296,8 @@ process_init_constructor_record (tree type, tree init,
|
|||
tsubst_flags_t complain)
|
||||
{
|
||||
vec<constructor_elt, va_gc> *v = NULL;
|
||||
int flags = 0;
|
||||
tree field;
|
||||
unsigned HOST_WIDE_INT idx = 0;
|
||||
int skipped = 0;
|
||||
|
||||
gcc_assert (TREE_CODE (type) == RECORD_TYPE);
|
||||
gcc_assert (!CLASSTYPE_VBASECLASSES (type));
|
||||
|
@ -1302,6 +1305,9 @@ process_init_constructor_record (tree type, tree init,
|
|||
|| !BINFO_N_BASE_BINFOS (TYPE_BINFO (type)));
|
||||
gcc_assert (!TYPE_POLYMORPHIC_P (type));
|
||||
|
||||
restart:
|
||||
int flags = 0;
|
||||
unsigned HOST_WIDE_INT idx = 0;
|
||||
/* Generally, we will always have an index for each initializer (which is
|
||||
a FIELD_DECL, put by reshape_init), but compound literals don't go trough
|
||||
reshape_init. So we need to handle both cases. */
|
||||
|
@ -1345,6 +1351,19 @@ process_init_constructor_record (tree type, tree init,
|
|||
next = massage_init_elt (type, ce->value, complain);
|
||||
++idx;
|
||||
}
|
||||
else if (DECL_INITIAL (field))
|
||||
{
|
||||
if (skipped > 0)
|
||||
{
|
||||
/* We're using an NSDMI past a field with implicit
|
||||
zero-init. Go back and make it explicit. */
|
||||
skipped = -1;
|
||||
vec_safe_truncate (v, 0);
|
||||
goto restart;
|
||||
}
|
||||
/* C++14 aggregate NSDMI. */
|
||||
next = get_nsdmi (field, /*ctor*/false);
|
||||
}
|
||||
else if (type_build_ctor_call (TREE_TYPE (field)))
|
||||
{
|
||||
/* If this type needs constructors run for
|
||||
|
@ -1387,13 +1406,17 @@ process_init_constructor_record (tree type, tree init,
|
|||
warning (OPT_Wmissing_field_initializers,
|
||||
"missing initializer for member %qD", field);
|
||||
|
||||
if (!zero_init_p (TREE_TYPE (field)))
|
||||
if (!zero_init_p (TREE_TYPE (field))
|
||||
|| skipped < 0)
|
||||
next = build_zero_init (TREE_TYPE (field), /*nelts=*/NULL_TREE,
|
||||
/*static_storage_p=*/false);
|
||||
else
|
||||
/* The default zero-initialization is fine for us; don't
|
||||
add anything to the CONSTRUCTOR. */
|
||||
continue;
|
||||
{
|
||||
/* The default zero-initialization is fine for us; don't
|
||||
add anything to the CONSTRUCTOR. */
|
||||
skipped = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is a bitfield, now convert to the lowered type. */
|
||||
|
|
|
@ -10,18 +10,18 @@
|
|||
// R() is well-formed because i is initialized before j.
|
||||
|
||||
struct s {
|
||||
constexpr s() : v(v) { } // { dg-message "" }
|
||||
constexpr s() : v(v) { }
|
||||
int v;
|
||||
};
|
||||
|
||||
constexpr s bang; // { dg-message "" }
|
||||
constexpr s bang; // { dg-error "" }
|
||||
|
||||
struct R {
|
||||
int i,j;
|
||||
constexpr R() : i(42),j(i) { } // { dg-bogus "" "" { xfail *-*-* } }
|
||||
constexpr R() : i(42),j(i) { } // { dg-bogus "" }
|
||||
};
|
||||
|
||||
constexpr R r; // { dg-bogus "" "" { xfail *-*-* } }
|
||||
constexpr R r; // { dg-bogus "" }
|
||||
|
||||
// Ill-formed (no diagnostic required)
|
||||
struct T {
|
||||
|
@ -41,10 +41,10 @@ struct U {
|
|||
constexpr int f(int _i) { return _i; }
|
||||
constexpr int g() { return i; }
|
||||
constexpr U(): i(0), j(0) { }
|
||||
constexpr U(const U& t) : i(f(t.i)),j(0) { } // { dg-bogus "" "" { xfail *-*-* } }
|
||||
constexpr U(int _i) : i(_i),j(g()) { } // { dg-bogus "" "" { xfail *-*-* } }
|
||||
constexpr U(const U& t) : i(f(t.i)),j(0) { } // { dg-bogus "" }
|
||||
constexpr U(int _i) : i(_i),j(g()) { } // { dg-bogus "" }
|
||||
};
|
||||
|
||||
constexpr U u1;
|
||||
constexpr U u2(u1); // { dg-bogus "" "" { xfail *-*-* } }
|
||||
constexpr U u3(1); // { dg-bogus "" "" { xfail *-*-* } }
|
||||
constexpr U u2(u1); // { dg-bogus "" }
|
||||
constexpr U u3(1); // { dg-bogus "" }
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct A
|
||||
{
|
||||
void *p;
|
||||
constexpr A(): p(this) {}
|
||||
};
|
||||
|
||||
constexpr A a;
|
||||
constexpr A b = A();
|
||||
|
||||
#define SA(X) static_assert ((X), #X)
|
||||
SA(a.p == &a);
|
||||
SA(b.p == &b);
|
|
@ -0,0 +1,14 @@
|
|||
// { dg-do compile { target c++11 } }
|
||||
// { dg-options "-fno-elide-constructors" }
|
||||
|
||||
struct A
|
||||
{
|
||||
void *p;
|
||||
constexpr A(): p(this) {}
|
||||
};
|
||||
|
||||
constexpr A a;
|
||||
constexpr A b = A(); // { dg-error "" }
|
||||
|
||||
#define SA(X) static_assert ((X), #X)
|
||||
SA(a.p == &a);
|
|
@ -11,6 +11,7 @@ struct A
|
|||
|
||||
struct B
|
||||
{
|
||||
virtual void g();
|
||||
const int d; // { dg-warning "non-static const member" }
|
||||
int &e; // { dg-warning "non-static reference" }
|
||||
int f = 7;
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// { dg-do run { target c++14 } }
|
||||
|
||||
struct S { int a; const char* b; int c; int d = b[a]; void *p = this+1; };
|
||||
constexpr S ss = S(S{ 1, "asdf" });
|
||||
|
||||
#define SA(X) static_assert ((X),#X)
|
||||
|
||||
SA(ss.a==1);
|
||||
SA(ss.b[0] == 'a' && ss.b[1] == 's' && ss.b[2] == 'd' && ss.b[3] == 'f');
|
||||
SA(ss.d == 's');
|
||||
SA(ss.p == &ss+1);
|
||||
|
||||
struct A
|
||||
{
|
||||
struct B {
|
||||
int i;
|
||||
int j = i+1;
|
||||
} b;
|
||||
int a = b.j+1;
|
||||
};
|
||||
|
||||
extern constexpr A a = { };
|
||||
SA(a.b.i == 0 && a.b.j == 1 && a.a == 2);
|
||||
|
||||
int f(const A& ar) { return ar.a; }
|
||||
|
||||
int main()
|
||||
{
|
||||
S ss2 = { 1, "asdf" };
|
||||
if (ss2.a != 1
|
||||
|| __builtin_strcmp(ss2.b,"asdf") != 0
|
||||
|| ss2.c != int()
|
||||
|| ss2.d != 's'
|
||||
|| ss2.p != &ss2+1)
|
||||
__builtin_abort();
|
||||
|
||||
A a = {};
|
||||
int i = f(A{});
|
||||
if (a.a != 2 || i != 2)
|
||||
__builtin_abort();
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// { dg-do compile { target c++14 } }
|
||||
|
||||
struct S { int a; const char* b; int c; int d = b[a]; };
|
||||
|
||||
constexpr int f(const S& s) { return s.a; }
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr int i = f(S{ 1, "asdf" });
|
||||
}
|
|
@ -28,6 +28,7 @@ proc prune_gcc_output { text } {
|
|||
regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global scope):\[^\n\]*" $text "" text
|
||||
regsub -all "(^|\n)\[^\n\]*: (recursively )?required \[^\n\]*" $text "" text
|
||||
regsub -all "(^|\n)\[^\n\]*: . skipping \[0-9\]* instantiation contexts \[^\n\]*" $text "" text
|
||||
regsub -all "(^|\n)\[^\n\]*: in constexpr expansion \[^\n\]*" $text "" text
|
||||
regsub -all "(^|\n) inlined from \[^\n\]*" $text "" text
|
||||
regsub -all "(^|\n)collect2: error: ld returned \[^\n\]*" $text "" text
|
||||
regsub -all "(^|\n)collect: re(compiling|linking)\[^\n\]*" $text "" text
|
||||
|
|
Loading…
Reference in New Issue