mirror of git://gcc.gnu.org/git/gcc.git
call.c (null_ptr_cst_p): Use maybe_constant_value.
* call.c (null_ptr_cst_p): Use maybe_constant_value. (set_up_extended_ref_temp): Support constant initialization. (initialize_reference): Adjust. * class.c (check_bitfield_decl): Use cxx_constant_value. * cvt.c (ocp_convert): Don't use integral_constant_value when converting to class type. * decl.c (finish_case_label): Use maybe_constant_value. (build_init_list_var_init): Support constant initialization. (check_initializer): Likewise. Reorganize. (cp_finish_decl): Likewise. (expand_static_init): Likewise. (compute_array_index_type): Use maybe_constant_value. Add complain parm. (create_array_type_for_decl, grokdeclarator): Pass it. (build_enumerator): Use cxx_constant_value. * decl2.c (grokfield): Use maybe_constant_init. * except.c (check_noexcept_r): Handle constexpr. (build_noexcept_spec): Use maybe_constant_value. * init.c (expand_default_init): Support constant initialization. (build_vec_init): Likewise. (constant_value_1): Adjust. (build_new_1): Adjust. * parser.c (cp_parser_constant_expression): Allow non-integral in C++0x mode. (cp_parser_direct_declarator): Don't fold yet in C++0x mode. (cp_parser_initializer_clause): Toss folded result if non-constant. * pt.c (fold_decl_constant_value): Remove. (convert_nontype_argument): Use maybe_constant_value. Give clearer error about overflow. (tsubst): Move array bounds handling into compute_array_index_type. (value_dependent_expression_p): Handle constant CALL_EXPR. * semantics.c (finish_static_assert): Use maybe_constant_value. (ensure_literal_type_for_constexpr_object): Make sure type is complete. (potential_constant_expression): Use maybe_constant_value. * tree.c (cast_valid_in_integral_constant_expression_p): Any cast is potentially valid in C++0x. * typeck2.c (store_init_value): Handle constant init. (check_narrowing): Use maybe_constant_value. (build_functional_cast): Set TREE_CONSTANT on literal T(). * cp-tree.h (DECL_INTEGRAL_CONSTANT_VAR_P): Remove. (LOOKUP_ALREADY_DIGESTED): New. (compute_array_index_type): Adjust prototype. From-SVN: r166167
This commit is contained in:
parent
c41095db2f
commit
fa2200cbb1
|
|
@ -1,6 +1,53 @@
|
|||
2010-11-01 Gabriel Dos Reis <gdr@cse.tamu.edu>
|
||||
Jason Merrill <jason@redhat.com>
|
||||
|
||||
* call.c (null_ptr_cst_p): Use maybe_constant_value.
|
||||
(set_up_extended_ref_temp): Support constant initialization.
|
||||
(initialize_reference): Adjust.
|
||||
* class.c (check_bitfield_decl): Use cxx_constant_value.
|
||||
* cvt.c (ocp_convert): Don't use integral_constant_value when
|
||||
converting to class type.
|
||||
* decl.c (finish_case_label): Use maybe_constant_value.
|
||||
(build_init_list_var_init): Support constant initialization.
|
||||
(check_initializer): Likewise. Reorganize.
|
||||
(cp_finish_decl): Likewise.
|
||||
(expand_static_init): Likewise.
|
||||
(compute_array_index_type): Use maybe_constant_value.
|
||||
Add complain parm.
|
||||
(create_array_type_for_decl, grokdeclarator): Pass it.
|
||||
(build_enumerator): Use cxx_constant_value.
|
||||
* decl2.c (grokfield): Use maybe_constant_init.
|
||||
* except.c (check_noexcept_r): Handle constexpr.
|
||||
(build_noexcept_spec): Use maybe_constant_value.
|
||||
* init.c (expand_default_init): Support constant initialization.
|
||||
(build_vec_init): Likewise.
|
||||
(constant_value_1): Adjust.
|
||||
(build_new_1): Adjust.
|
||||
* parser.c (cp_parser_constant_expression): Allow non-integral
|
||||
in C++0x mode.
|
||||
(cp_parser_direct_declarator): Don't fold yet in C++0x mode.
|
||||
(cp_parser_initializer_clause): Toss folded result if non-constant.
|
||||
* pt.c (fold_decl_constant_value): Remove.
|
||||
(convert_nontype_argument): Use maybe_constant_value. Give clearer
|
||||
error about overflow.
|
||||
(tsubst): Move array bounds handling into compute_array_index_type.
|
||||
(value_dependent_expression_p): Handle constant CALL_EXPR.
|
||||
(tsubst_decl): Don't set
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P yet.
|
||||
(tsubst_expr) [DECL_EXPR]: Pass it into cp_finish_decl.
|
||||
(instantiate_decl): Here too.
|
||||
* semantics.c (finish_static_assert): Use maybe_constant_value.
|
||||
(ensure_literal_type_for_constexpr_object): Make sure type is complete.
|
||||
(potential_constant_expression): Use maybe_constant_value.
|
||||
* tree.c (cast_valid_in_integral_constant_expression_p): Any cast
|
||||
is potentially valid in C++0x.
|
||||
* typeck2.c (store_init_value): Handle constant init.
|
||||
(check_narrowing): Use maybe_constant_value.
|
||||
(build_functional_cast): Set TREE_CONSTANT on literal T().
|
||||
* cp-tree.h (DECL_INTEGRAL_CONSTANT_VAR_P): Remove.
|
||||
(LOOKUP_ALREADY_DIGESTED): New.
|
||||
(compute_array_index_type): Adjust prototype.
|
||||
|
||||
* semantics.c (constexpr_call): New datatype.
|
||||
(constexpr_call_table): New global table.
|
||||
(constexpr_call_hash): New.
|
||||
|
|
|
|||
|
|
@ -466,15 +466,24 @@ null_ptr_cst_p (tree t)
|
|||
A null pointer constant is an integral constant expression
|
||||
(_expr.const_) rvalue of integer type that evaluates to zero or
|
||||
an rvalue of type std::nullptr_t. */
|
||||
t = integral_constant_value (t);
|
||||
if (t == null_node
|
||||
|| NULLPTR_TYPE_P (TREE_TYPE (t)))
|
||||
if (NULLPTR_TYPE_P (TREE_TYPE (t)))
|
||||
return true;
|
||||
if (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)) && integer_zerop (t))
|
||||
if (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)))
|
||||
{
|
||||
STRIP_NOPS (t);
|
||||
if (!TREE_OVERFLOW (t))
|
||||
return true;
|
||||
if (cxx_dialect >= cxx0x)
|
||||
{
|
||||
t = fold_non_dependent_expr (t);
|
||||
t = maybe_constant_value (t);
|
||||
if (TREE_CONSTANT (t) && integer_zerop (t))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = integral_constant_value (t);
|
||||
STRIP_NOPS (t);
|
||||
if (integer_zerop (t) && !TREE_OVERFLOW (t))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -7907,9 +7916,32 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
|
|||
VAR. */
|
||||
if (TREE_CODE (expr) != TARGET_EXPR)
|
||||
expr = get_target_expr (expr);
|
||||
/* Create the INIT_EXPR that will initialize the temporary
|
||||
variable. */
|
||||
init = build2 (INIT_EXPR, type, var, expr);
|
||||
|
||||
/* If the initializer is constant, put it in DECL_INITIAL so we get
|
||||
static initialization and use in constant expressions. */
|
||||
init = maybe_constant_init (expr);
|
||||
if (TREE_CONSTANT (init))
|
||||
{
|
||||
if (literal_type_p (type) && CP_TYPE_CONST_NON_VOLATILE_P (type))
|
||||
{
|
||||
/* 5.19 says that a constant expression can include an
|
||||
lvalue-rvalue conversion applied to "a glvalue of literal type
|
||||
that refers to a non-volatile temporary object initialized
|
||||
with a constant expression". Rather than try to communicate
|
||||
that this VAR_DECL is a temporary, just mark it constexpr.
|
||||
|
||||
Currently this is only useful for initializer_list temporaries,
|
||||
since reference vars can't appear in constant expressions. */
|
||||
DECL_DECLARED_CONSTEXPR_P (var) = true;
|
||||
TREE_CONSTANT (var) = true;
|
||||
}
|
||||
DECL_INITIAL (var) = init;
|
||||
init = NULL_TREE;
|
||||
}
|
||||
else
|
||||
/* Create the INIT_EXPR that will initialize the temporary
|
||||
variable. */
|
||||
init = build2 (INIT_EXPR, type, var, expr);
|
||||
if (at_function_scope_p ())
|
||||
{
|
||||
add_decl_expr (var);
|
||||
|
|
@ -8067,7 +8099,8 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
|
|||
build_pointer_type (base_conv_type),
|
||||
/*check_access=*/true,
|
||||
/*nonnull=*/true, complain);
|
||||
expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
|
||||
if (init)
|
||||
expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
|
||||
}
|
||||
else
|
||||
/* Take the address of EXPR. */
|
||||
|
|
|
|||
|
|
@ -2802,7 +2802,7 @@ check_bitfield_decl (tree field)
|
|||
STRIP_NOPS (w);
|
||||
|
||||
/* detect invalid field size. */
|
||||
w = integral_constant_value (w);
|
||||
w = cxx_constant_value (w);
|
||||
|
||||
if (TREE_CODE (w) != INTEGER_CST)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2207,23 +2207,6 @@ struct GTY((variable_size)) lang_decl {
|
|||
#define DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P(NODE) \
|
||||
(TREE_LANG_FLAG_2 (VAR_DECL_CHECK (NODE)))
|
||||
|
||||
/* Nonzero for a VAR_DECL that can be used in an integral constant
|
||||
expression.
|
||||
|
||||
[expr.const]
|
||||
|
||||
An integral constant-expression can only involve ... const
|
||||
variables of static or enumeration types initialized with
|
||||
constant expressions ...
|
||||
|
||||
The standard does not require that the expression be non-volatile.
|
||||
G++ implements the proposed correction in DR 457. */
|
||||
#define DECL_INTEGRAL_CONSTANT_VAR_P(NODE) \
|
||||
(TREE_CODE (NODE) == VAR_DECL \
|
||||
&& CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (NODE)) \
|
||||
&& INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (NODE)) \
|
||||
&& DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (NODE))
|
||||
|
||||
/* Nonzero if the DECL was initialized in the class definition itself,
|
||||
rather than outside the class. This is used for both static member
|
||||
VAR_DECLS, and FUNCTION_DECLS that are defined in the class. */
|
||||
|
|
@ -4235,6 +4218,9 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
|
|||
another mechanism. Exiting early also avoids problems with trying
|
||||
to perform argument conversions when the class isn't complete yet. */
|
||||
#define LOOKUP_SPECULATIVE (LOOKUP_LIST_ONLY << 1)
|
||||
/* Used in calls to store_init_value to suppress its usual call to
|
||||
digest_init. */
|
||||
#define LOOKUP_ALREADY_DIGESTED (LOOKUP_SPECULATIVE << 1)
|
||||
|
||||
#define LOOKUP_NAMESPACES_ONLY(F) \
|
||||
(((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
|
||||
|
|
@ -4826,7 +4812,7 @@ extern tree static_fn_type (tree);
|
|||
extern void revert_static_member_fn (tree);
|
||||
extern void fixup_anonymous_aggr (tree);
|
||||
extern int check_static_variable_definition (tree, tree);
|
||||
extern tree compute_array_index_type (tree, tree);
|
||||
extern tree compute_array_index_type (tree, tree, tsubst_flags_t);
|
||||
extern tree check_default_argument (tree, tree);
|
||||
typedef int (*walk_namespaces_fn) (tree, void *);
|
||||
extern int walk_namespaces (walk_namespaces_fn,
|
||||
|
|
@ -5258,6 +5244,7 @@ extern tree ensure_literal_type_for_constexpr_object (tree);
|
|||
extern tree cxx_constant_value (tree);
|
||||
extern tree maybe_constant_value (tree);
|
||||
extern tree maybe_constant_init (tree);
|
||||
extern bool is_sub_constant_expr (tree);
|
||||
extern bool reduced_constant_expression_p (tree);
|
||||
|
||||
enum {
|
||||
|
|
|
|||
|
|
@ -609,7 +609,10 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
|
|||
return error_mark_node;
|
||||
}
|
||||
|
||||
e = integral_constant_value (e);
|
||||
/* FIXME remove when moving to c_fully_fold model. */
|
||||
/* FIXME do we still need this test? */
|
||||
if (!CLASS_TYPE_P (type))
|
||||
e = integral_constant_value (e);
|
||||
if (error_operand_p (e))
|
||||
return error_mark_node;
|
||||
|
||||
|
|
|
|||
250
gcc/cp/decl.c
250
gcc/cp/decl.c
|
|
@ -2936,9 +2936,9 @@ finish_case_label (location_t loc, tree low_value, tree high_value)
|
|||
return error_mark_node;
|
||||
|
||||
if (low_value)
|
||||
low_value = decl_constant_value (low_value);
|
||||
low_value = cxx_constant_value (low_value);
|
||||
if (high_value)
|
||||
high_value = decl_constant_value (high_value);
|
||||
high_value = cxx_constant_value (high_value);
|
||||
|
||||
r = c_add_case_label (loc, switch_stack->cases, cond,
|
||||
SWITCH_STMT_TYPE (switch_stack->switch_stmt),
|
||||
|
|
@ -4530,7 +4530,8 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup)
|
|||
grok_reference_init. */
|
||||
|
||||
static tree
|
||||
build_init_list_var_init (tree decl, tree type, tree init, tree *cleanup)
|
||||
build_init_list_var_init (tree decl, tree type, tree init, tree *array_init,
|
||||
tree *cleanup)
|
||||
{
|
||||
tree aggr_init, array, arrtype;
|
||||
init = perform_implicit_conversion (type, init, tf_warning_or_error);
|
||||
|
|
@ -4538,8 +4539,6 @@ build_init_list_var_init (tree decl, tree type, tree init, tree *cleanup)
|
|||
return error_mark_node;
|
||||
|
||||
aggr_init = TARGET_EXPR_INITIAL (init);
|
||||
init = build2 (INIT_EXPR, type, decl, init);
|
||||
|
||||
array = AGGR_INIT_EXPR_ARG (aggr_init, 1);
|
||||
arrtype = TREE_TYPE (array);
|
||||
STRIP_NOPS (array);
|
||||
|
|
@ -4549,12 +4548,10 @@ build_init_list_var_init (tree decl, tree type, tree init, tree *cleanup)
|
|||
static variable and we don't need to do anything here. */
|
||||
if (decl && TREE_CODE (array) == TARGET_EXPR)
|
||||
{
|
||||
tree subinit;
|
||||
tree var = set_up_extended_ref_temp (decl, array, cleanup, &subinit);
|
||||
tree var = set_up_extended_ref_temp (decl, array, cleanup, array_init);
|
||||
var = build_address (var);
|
||||
var = convert (arrtype, var);
|
||||
AGGR_INIT_EXPR_ARG (aggr_init, 1) = var;
|
||||
init = build2 (COMPOUND_EXPR, TREE_TYPE (init), subinit, init);
|
||||
}
|
||||
return init;
|
||||
}
|
||||
|
|
@ -5250,6 +5247,7 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
|
|||
{
|
||||
tree type = TREE_TYPE (decl);
|
||||
tree init_code = NULL;
|
||||
tree extra_init = NULL_TREE;
|
||||
tree core_type;
|
||||
|
||||
/* Things that are going to be initialized need to have complete
|
||||
|
|
@ -5304,16 +5302,21 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
|
|||
gcc_assert (init != NULL_TREE);
|
||||
init = NULL_TREE;
|
||||
}
|
||||
else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
|
||||
else if (!init && DECL_REALLY_EXTERN (decl))
|
||||
;
|
||||
else if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
init = grok_reference_init (decl, type, init, cleanup);
|
||||
else if (init)
|
||||
else if (init || TYPE_NEEDS_CONSTRUCTING (type))
|
||||
{
|
||||
if (!init)
|
||||
check_for_uninitialized_const_var (decl);
|
||||
/* Do not reshape constructors of vectors (they don't need to be
|
||||
reshaped. */
|
||||
if (BRACE_ENCLOSED_INITIALIZER_P (init))
|
||||
else if (BRACE_ENCLOSED_INITIALIZER_P (init))
|
||||
{
|
||||
if (is_std_init_list (type))
|
||||
return build_init_list_var_init (decl, type, init, cleanup);
|
||||
init = build_init_list_var_init (decl, type, init,
|
||||
&extra_init, cleanup);
|
||||
else if (TYPE_NON_AGGREGATE_CLASS (type))
|
||||
{
|
||||
/* Don't reshape if the class has constructors. */
|
||||
|
|
@ -5340,9 +5343,46 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
|
|||
|
||||
if (TYPE_NEEDS_CONSTRUCTING (type)
|
||||
|| (CLASS_TYPE_P (type)
|
||||
&& !BRACE_ENCLOSED_INITIALIZER_P (init)))
|
||||
return build_aggr_init_full_exprs (decl, init, flags);
|
||||
else if (TREE_CODE (init) != TREE_VEC)
|
||||
&& !(init && BRACE_ENCLOSED_INITIALIZER_P (init))))
|
||||
{
|
||||
init_code = build_aggr_init_full_exprs (decl, init, flags);
|
||||
|
||||
/* If this is a constexpr initializer, expand_default_init will
|
||||
have returned an INIT_EXPR rather than a CALL_EXPR. In that
|
||||
case, pull the initializer back out and pass it down into
|
||||
store_init_value. */
|
||||
while (TREE_CODE (init_code) == EXPR_STMT
|
||||
|| TREE_CODE (init_code) == CONVERT_EXPR)
|
||||
init_code = TREE_OPERAND (init_code, 0);
|
||||
if (TREE_CODE (init_code) == INIT_EXPR)
|
||||
{
|
||||
init = TREE_OPERAND (init_code, 1);
|
||||
init_code = NULL_TREE;
|
||||
/* Don't call digest_init; it's unnecessary and will complain
|
||||
about aggregate initialization of non-aggregate classes. */
|
||||
flags |= LOOKUP_ALREADY_DIGESTED;
|
||||
}
|
||||
else if (DECL_DECLARED_CONSTEXPR_P (decl))
|
||||
{
|
||||
/* Declared constexpr, but no suitable initializer; massage
|
||||
init appropriately so we can pass it into store_init_value
|
||||
for the error. */
|
||||
if (init && BRACE_ENCLOSED_INITIALIZER_P (init))
|
||||
init = finish_compound_literal (type, init);
|
||||
else if (CLASS_TYPE_P (type)
|
||||
&& (!init || TREE_CODE (init) == TREE_LIST))
|
||||
{
|
||||
init = build_functional_cast (type, init, tf_none);
|
||||
if (init != error_mark_node)
|
||||
TARGET_EXPR_DIRECT_INIT_P (init) = true;
|
||||
}
|
||||
init_code = NULL_TREE;
|
||||
}
|
||||
else
|
||||
init = NULL_TREE;
|
||||
}
|
||||
|
||||
if (init && TREE_CODE (init) != TREE_VEC)
|
||||
{
|
||||
init_code = store_init_value (decl, init, flags);
|
||||
if (pedantic && TREE_CODE (type) == ARRAY_TYPE
|
||||
|
|
@ -5354,28 +5394,39 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
|
|||
init = NULL;
|
||||
}
|
||||
}
|
||||
else if (DECL_EXTERNAL (decl))
|
||||
;
|
||||
else if (TYPE_P (type) && TYPE_NEEDS_CONSTRUCTING (type))
|
||||
else
|
||||
{
|
||||
check_for_uninitialized_const_var (decl);
|
||||
return build_aggr_init_full_exprs (decl, init, flags);
|
||||
}
|
||||
else if (MAYBE_CLASS_TYPE_P (core_type = strip_array_types (type)))
|
||||
{
|
||||
if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type)
|
||||
|| CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))
|
||||
if (CLASS_TYPE_P (core_type = strip_array_types (type))
|
||||
&& (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type)
|
||||
|| CLASSTYPE_REF_FIELDS_NEED_INIT (core_type)))
|
||||
diagnose_uninitialized_cst_or_ref_member (core_type, /*using_new=*/false,
|
||||
/*complain=*/true);
|
||||
|
||||
check_for_uninitialized_const_var (decl);
|
||||
}
|
||||
else
|
||||
check_for_uninitialized_const_var (decl);
|
||||
|
||||
if (init && init != error_mark_node)
|
||||
init_code = build2 (INIT_EXPR, type, decl, init);
|
||||
|
||||
if (extra_init)
|
||||
init_code = add_stmt_to_compound (extra_init, init_code);
|
||||
|
||||
if (init_code && DECL_IN_AGGR_P (decl))
|
||||
{
|
||||
static int explained = 0;
|
||||
|
||||
if (cxx_dialect < cxx0x)
|
||||
error ("initializer invalid for static member with constructor");
|
||||
else
|
||||
error ("non-constant in-class initialization invalid for static "
|
||||
"member %qD", decl);
|
||||
if (!explained)
|
||||
{
|
||||
error ("(an out of class initialization is required)");
|
||||
explained = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return init_code;
|
||||
}
|
||||
|
||||
|
|
@ -5746,7 +5797,22 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
|
|||
DECL_INITIAL (decl) = NULL_TREE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (init && TREE_CODE (decl) == VAR_DECL)
|
||||
{
|
||||
DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
|
||||
/* FIXME we rely on TREE_CONSTANT below; basing that on
|
||||
init_const_expr_p is probably wrong for C++0x. */
|
||||
if (init_const_expr_p)
|
||||
{
|
||||
/* Set these flags now for C++98 templates. We'll update the
|
||||
flags in store_init_value for instantiations and C++0x. */
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
|
||||
if (decl_maybe_constant_var_p (decl))
|
||||
TREE_CONSTANT (decl) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (processing_template_decl)
|
||||
{
|
||||
bool type_dependent_p;
|
||||
|
|
@ -5763,22 +5829,16 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
|
|||
DECL_INITIAL (decl) = NULL_TREE;
|
||||
}
|
||||
|
||||
if (init && init_const_expr_p && TREE_CODE (decl) == VAR_DECL)
|
||||
{
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
|
||||
if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
|
||||
TREE_CONSTANT (decl) = 1;
|
||||
}
|
||||
|
||||
/* Generally, initializers in templates are expanded when the
|
||||
template is instantiated. But, if DECL is an integral
|
||||
constant static data member, then it can be used in future
|
||||
integral constant expressions, and its value must be
|
||||
available. */
|
||||
template is instantiated. But, if DECL is a variable constant
|
||||
then it can be used in future constant expressions, so its value
|
||||
must be available. */
|
||||
if (!(init
|
||||
&& DECL_CLASS_SCOPE_P (decl)
|
||||
&& DECL_INTEGRAL_CONSTANT_VAR_P (decl)
|
||||
/* We just set TREE_CONSTANT appropriately; see above. */
|
||||
&& TREE_CONSTANT (decl)
|
||||
&& !type_dependent_p
|
||||
/* FIXME non-value-dependent constant expression */
|
||||
&& !value_dependent_init_p (init)))
|
||||
{
|
||||
if (init)
|
||||
|
|
@ -5892,16 +5952,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
|
|||
error ("Java object %qD not allocated with %<new%>", decl);
|
||||
init = NULL_TREE;
|
||||
}
|
||||
if (init)
|
||||
{
|
||||
DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
|
||||
if (init_const_expr_p)
|
||||
{
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
|
||||
if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
|
||||
TREE_CONSTANT (decl) = 1;
|
||||
}
|
||||
}
|
||||
init = check_initializer (decl, init, flags, &cleanup);
|
||||
/* Thread-local storage cannot be dynamically initialized. */
|
||||
if (DECL_THREAD_LOCAL_P (decl) && init)
|
||||
|
|
@ -6407,9 +6457,8 @@ expand_static_init (tree decl, tree init)
|
|||
gcc_assert (TREE_CODE (decl) == VAR_DECL);
|
||||
gcc_assert (TREE_STATIC (decl));
|
||||
|
||||
/* Some variables require no initialization. */
|
||||
/* Some variables require no dynamic initialization. */
|
||||
if (!init
|
||||
&& !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
|
||||
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
|
||||
return;
|
||||
|
||||
|
|
@ -7417,36 +7466,67 @@ check_static_variable_definition (tree decl, tree type)
|
|||
name of the thing being declared. */
|
||||
|
||||
tree
|
||||
compute_array_index_type (tree name, tree size)
|
||||
compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
|
||||
{
|
||||
tree type;
|
||||
tree itype;
|
||||
tree osize = size;
|
||||
tree abi_1_itype = NULL_TREE;
|
||||
|
||||
if (error_operand_p (size))
|
||||
return error_mark_node;
|
||||
|
||||
type = TREE_TYPE (size);
|
||||
/* The array bound must be an integer type. */
|
||||
if (!dependent_type_p (type) && !INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type))
|
||||
/* type_dependent_expression_p? */
|
||||
if (!dependent_type_p (type))
|
||||
{
|
||||
if (name)
|
||||
error ("size of array %qD has non-integral type %qT", name, type);
|
||||
mark_rvalue_use (size);
|
||||
|
||||
if (cxx_dialect < cxx0x && TREE_CODE (size) == NOP_EXPR
|
||||
&& TREE_SIDE_EFFECTS (size))
|
||||
/* In C++98, we mark a non-constant array bound with a magic
|
||||
NOP_EXPR with TREE_SIDE_EFFECTS; don't fold in that case. */;
|
||||
else
|
||||
error ("size of array has non-integral type %qT", type);
|
||||
size = integer_one_node;
|
||||
type = TREE_TYPE (size);
|
||||
{
|
||||
size = fold_non_dependent_expr (size);
|
||||
|
||||
if (CLASS_TYPE_P (type)
|
||||
&& CLASSTYPE_LITERAL_P (type))
|
||||
{
|
||||
size = build_expr_type_conversion (WANT_INT, size, true);
|
||||
if (size == error_mark_node)
|
||||
return error_mark_node;
|
||||
type = TREE_TYPE (size);
|
||||
}
|
||||
|
||||
size = maybe_constant_value (size);
|
||||
}
|
||||
|
||||
if (error_operand_p (size))
|
||||
return error_mark_node;
|
||||
|
||||
/* The array bound must be an integer type. */
|
||||
if (!INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type))
|
||||
{
|
||||
if (!(complain & tf_error))
|
||||
return error_mark_node;
|
||||
if (name)
|
||||
error ("size of array %qD has non-integral type %qT", name, type);
|
||||
else
|
||||
error ("size of array has non-integral type %qT", type);
|
||||
size = integer_one_node;
|
||||
type = TREE_TYPE (size);
|
||||
}
|
||||
}
|
||||
|
||||
/* A type is dependent if it is...an array type constructed from any
|
||||
dependent type or whose size is specified by a constant expression
|
||||
that is value-dependent. */
|
||||
/* We can only call value_dependent_expression_p on integral constant
|
||||
expressions; the parser adds a dummy NOP_EXPR with TREE_SIDE_EFFECTS
|
||||
set if this isn't one. */
|
||||
expressions; treat non-constant expressions as dependent, too. */
|
||||
if (processing_template_decl
|
||||
&& (dependent_type_p (type)
|
||||
|| TREE_SIDE_EFFECTS (size) || value_dependent_expression_p (size)))
|
||||
|| !TREE_CONSTANT (size) || value_dependent_expression_p (size)))
|
||||
{
|
||||
/* We cannot do any checking for a SIZE that isn't known to be
|
||||
constant. Just build the index type and mark that it requires
|
||||
|
|
@ -7467,17 +7547,7 @@ compute_array_index_type (tree name, tree size)
|
|||
would have, but with TYPE_CANONICAL set to the "right"
|
||||
value that the current ABI would provide. */
|
||||
abi_1_itype = build_index_type (build_min (MINUS_EXPR, sizetype,
|
||||
size, integer_one_node));
|
||||
|
||||
/* The size might be the result of a cast. */
|
||||
STRIP_TYPE_NOPS (size);
|
||||
|
||||
size = mark_rvalue_use (size);
|
||||
|
||||
/* It might be a const variable or enumeration constant. */
|
||||
size = integral_constant_value (size);
|
||||
if (error_operand_p (size))
|
||||
return error_mark_node;
|
||||
osize, integer_one_node));
|
||||
|
||||
/* Normally, the array-bound will be a constant. */
|
||||
if (TREE_CODE (size) == INTEGER_CST)
|
||||
|
|
@ -7489,24 +7559,37 @@ compute_array_index_type (tree name, tree size)
|
|||
/* An array must have a positive number of elements. */
|
||||
if (INT_CST_LT (size, integer_zero_node))
|
||||
{
|
||||
if (!(complain & tf_error))
|
||||
return error_mark_node;
|
||||
if (name)
|
||||
error ("size of array %qD is negative", name);
|
||||
else
|
||||
error ("size of array is negative");
|
||||
size = integer_one_node;
|
||||
}
|
||||
/* As an extension we allow zero-sized arrays. We always allow
|
||||
them in system headers because glibc uses them. */
|
||||
else if (integer_zerop (size) && !in_system_header)
|
||||
/* As an extension we allow zero-sized arrays. */
|
||||
else if (integer_zerop (size))
|
||||
{
|
||||
if (name)
|
||||
if (!(complain & tf_error))
|
||||
/* We must fail if performing argument deduction (as
|
||||
indicated by the state of complain), so that
|
||||
another substitution can be found. */
|
||||
return error_mark_node;
|
||||
else if (in_system_header)
|
||||
/* Allow them in system headers because glibc uses them. */;
|
||||
else if (name)
|
||||
pedwarn (input_location, OPT_pedantic, "ISO C++ forbids zero-size array %qD", name);
|
||||
else
|
||||
pedwarn (input_location, OPT_pedantic, "ISO C++ forbids zero-size array");
|
||||
}
|
||||
}
|
||||
else if (TREE_CONSTANT (size))
|
||||
else if (TREE_CONSTANT (size)
|
||||
/* We don't allow VLAs at non-function scopes, or during
|
||||
tentative template substitution. */
|
||||
|| !at_function_scope_p () || !(complain & tf_error))
|
||||
{
|
||||
if (!(complain & tf_error))
|
||||
return error_mark_node;
|
||||
/* `(int) &fn' is not a valid array bound. */
|
||||
if (name)
|
||||
error ("size of array %qD is not an integral constant-expression",
|
||||
|
|
@ -7562,6 +7645,8 @@ compute_array_index_type (tree name, tree size)
|
|||
else if (TREE_CODE (itype) == INTEGER_CST
|
||||
&& TREE_OVERFLOW (itype))
|
||||
{
|
||||
if (!(complain & tf_error))
|
||||
return error_mark_node;
|
||||
error ("overflow in array dimension");
|
||||
TREE_OVERFLOW (itype) = 0;
|
||||
}
|
||||
|
|
@ -7673,7 +7758,7 @@ create_array_type_for_decl (tree name, tree type, tree size)
|
|||
|
||||
/* Figure out the index type for the array. */
|
||||
if (size)
|
||||
itype = compute_array_index_type (name, size);
|
||||
itype = compute_array_index_type (name, size, tf_warning_or_error);
|
||||
|
||||
/* [dcl.array]
|
||||
T is called the array element type; this type shall not be [...] an
|
||||
|
|
@ -9411,7 +9496,8 @@ grokdeclarator (const cp_declarator *declarator,
|
|||
if (!staticp && TREE_CODE (type) == ARRAY_TYPE
|
||||
&& TYPE_DOMAIN (type) == NULL_TREE)
|
||||
{
|
||||
tree itype = compute_array_index_type (dname, integer_zero_node);
|
||||
tree itype = compute_array_index_type (dname, integer_zero_node,
|
||||
tf_warning_or_error);
|
||||
type = build_cplus_array_type (TREE_TYPE (type), itype);
|
||||
}
|
||||
|
||||
|
|
@ -11732,7 +11818,7 @@ build_enumerator (tree name, tree value, tree enumtype, location_t loc)
|
|||
/* Validate and default VALUE. */
|
||||
if (value != NULL_TREE)
|
||||
{
|
||||
value = integral_constant_value (value);
|
||||
value = cxx_constant_value (value);
|
||||
|
||||
if (TREE_CODE (value) == INTEGER_CST)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -923,8 +923,7 @@ grokfield (const cp_declarator *declarator,
|
|||
{
|
||||
if (TREE_CODE (init) == CONSTRUCTOR)
|
||||
init = digest_init (TREE_TYPE (value), init);
|
||||
else
|
||||
init = integral_constant_value (init);
|
||||
init = maybe_constant_init (init);
|
||||
|
||||
if (init != error_mark_node && !TREE_CONSTANT (init))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1054,15 +1054,20 @@ check_noexcept_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
|
|||
|
||||
STRIP_NOPS (fn);
|
||||
if (TREE_CODE (fn) == ADDR_EXPR)
|
||||
fn = TREE_OPERAND (fn, 0);
|
||||
if (TREE_CODE (fn) == FUNCTION_DECL)
|
||||
{
|
||||
/* We do use TREE_NOTHROW for ABI internals like __dynamic_cast,
|
||||
and for C library functions known not to throw. */
|
||||
fn = TREE_OPERAND (fn, 0);
|
||||
if (TREE_CODE (fn) == FUNCTION_DECL
|
||||
&& DECL_EXTERN_C_P (fn)
|
||||
if (DECL_EXTERN_C_P (fn)
|
||||
&& (DECL_ARTIFICIAL (fn)
|
||||
|| nothrow_libfn_p (fn)))
|
||||
return TREE_NOTHROW (fn) ? NULL_TREE : fn;
|
||||
/* A call to a constexpr function is noexcept if the call
|
||||
is a constant expression. */
|
||||
if (DECL_DECLARED_CONSTEXPR_P (fn)
|
||||
&& is_sub_constant_expr (t))
|
||||
return NULL_TREE;
|
||||
}
|
||||
if (!TYPE_NOTHROW_P (type))
|
||||
return fn;
|
||||
|
|
@ -1195,9 +1200,15 @@ type_throw_all_p (const_tree type)
|
|||
tree
|
||||
build_noexcept_spec (tree expr, int complain)
|
||||
{
|
||||
expr = perform_implicit_conversion_flags (boolean_type_node, expr,
|
||||
complain,
|
||||
LOOKUP_NORMAL);
|
||||
/* This isn't part of the signature, so don't bother trying to evaluate
|
||||
it until instantiation. */
|
||||
if (!processing_template_decl)
|
||||
{
|
||||
expr = cxx_constant_value (expr);
|
||||
expr = perform_implicit_conversion_flags (boolean_type_node, expr,
|
||||
complain,
|
||||
LOOKUP_NORMAL);
|
||||
}
|
||||
if (expr == boolean_true_node)
|
||||
return noexcept_true_spec;
|
||||
else if (expr == boolean_false_node)
|
||||
|
|
|
|||
127
gcc/cp/init.c
127
gcc/cp/init.c
|
|
@ -1440,8 +1440,20 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
|
|||
if (parms != NULL)
|
||||
release_tree_vector (parms);
|
||||
|
||||
if (exp == true_exp && TREE_CODE (rval) == CALL_EXPR)
|
||||
{
|
||||
tree fn = get_callee_fndecl (rval);
|
||||
if (DECL_DECLARED_CONSTEXPR_P (fn))
|
||||
{
|
||||
tree e = maybe_constant_value (rval);
|
||||
if (TREE_CONSTANT (e))
|
||||
rval = build2 (INIT_EXPR, type, exp, e);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME put back convert_to_void? */
|
||||
if (TREE_SIDE_EFFECTS (rval))
|
||||
finish_expr_stmt (convert_to_void (rval, ICV_CAST, complain));
|
||||
finish_expr_stmt (rval);
|
||||
}
|
||||
|
||||
/* This function is responsible for initializing EXP with INIT
|
||||
|
|
@ -1708,36 +1720,18 @@ constant_value_1 (tree decl, bool integral_p)
|
|||
{
|
||||
while (TREE_CODE (decl) == CONST_DECL
|
||||
|| (integral_p
|
||||
? DECL_INTEGRAL_CONSTANT_VAR_P (decl)
|
||||
? decl_constant_var_p (decl)
|
||||
: (TREE_CODE (decl) == VAR_DECL
|
||||
&& CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))))
|
||||
{
|
||||
tree init;
|
||||
/* Static data members in template classes may have
|
||||
non-dependent initializers. References to such non-static
|
||||
data members are not value-dependent, so we must retrieve the
|
||||
initializer here. The DECL_INITIAL will have the right type,
|
||||
but will not have been folded because that would prevent us
|
||||
from performing all appropriate semantic checks at
|
||||
instantiation time. */
|
||||
if (DECL_CLASS_SCOPE_P (decl)
|
||||
&& CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
|
||||
&& uses_template_parms (CLASSTYPE_TI_ARGS
|
||||
(DECL_CONTEXT (decl))))
|
||||
{
|
||||
++processing_template_decl;
|
||||
init = fold_non_dependent_expr (DECL_INITIAL (decl));
|
||||
--processing_template_decl;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If DECL is a static data member in a template
|
||||
specialization, we must instantiate it here. The
|
||||
initializer for the static data member is not processed
|
||||
until needed; we need it now. */
|
||||
mark_used (decl);
|
||||
init = DECL_INITIAL (decl);
|
||||
}
|
||||
/* If DECL is a static data member in a template
|
||||
specialization, we must instantiate it here. The
|
||||
initializer for the static data member is not processed
|
||||
until needed; we need it now. */
|
||||
mark_used (decl);
|
||||
mark_rvalue_use (decl);
|
||||
init = DECL_INITIAL (decl);
|
||||
if (init == error_mark_node)
|
||||
{
|
||||
if (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
|
||||
|
|
@ -1758,8 +1752,9 @@ constant_value_1 (tree decl, bool integral_p)
|
|||
init = TREE_VALUE (init);
|
||||
if (!init
|
||||
|| !TREE_TYPE (init)
|
||||
|| uses_template_parms (init)
|
||||
|| (integral_p
|
||||
? !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (init))
|
||||
? false
|
||||
: (!TREE_CONSTANT (init)
|
||||
/* Do not return an aggregate constant (of which
|
||||
string literals are a special case), as we do not
|
||||
|
|
@ -2302,7 +2297,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
|
|||
tree arraytype, domain;
|
||||
vecinit = VEC_index (tree, *init, 0);
|
||||
if (TREE_CONSTANT (nelts))
|
||||
domain = compute_array_index_type (NULL_TREE, nelts);
|
||||
domain = compute_array_index_type (NULL_TREE, nelts, complain);
|
||||
else
|
||||
{
|
||||
domain = NULL_TREE;
|
||||
|
|
@ -2878,6 +2873,8 @@ build_vec_init (tree base, tree maxindex, tree init,
|
|||
tree try_block = NULL_TREE;
|
||||
int num_initialized_elts = 0;
|
||||
bool is_global;
|
||||
tree const_init = NULL_TREE;
|
||||
tree obase = base;
|
||||
bool xvalue = false;
|
||||
|
||||
if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
|
||||
|
|
@ -2986,26 +2983,75 @@ build_vec_init (tree base, tree maxindex, tree init,
|
|||
try_block = begin_try_block ();
|
||||
}
|
||||
|
||||
/* Maybe pull out constant value when from_array? */
|
||||
|
||||
if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
|
||||
{
|
||||
/* Do non-default initialization of non-trivial arrays resulting from
|
||||
brace-enclosed initializers. */
|
||||
unsigned HOST_WIDE_INT idx;
|
||||
tree elt;
|
||||
tree field, elt;
|
||||
/* Should we try to create a constant initializer? */
|
||||
bool try_const = (literal_type_p (inner_elt_type)
|
||||
|| TYPE_HAS_CONSTEXPR_CTOR (inner_elt_type));
|
||||
bool saw_non_const = false;
|
||||
bool saw_const = false;
|
||||
/* If we're initializing a static array, we want to do static
|
||||
initialization of any elements with constant initializers even if
|
||||
some are non-constant. */
|
||||
bool do_static_init = (DECL_P (obase) && TREE_STATIC (obase));
|
||||
VEC(constructor_elt,gc) *new_vec;
|
||||
from_array = 0;
|
||||
|
||||
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), idx, elt)
|
||||
if (try_const)
|
||||
new_vec = VEC_alloc (constructor_elt, gc, CONSTRUCTOR_NELTS (init));
|
||||
else
|
||||
new_vec = NULL;
|
||||
|
||||
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, field, elt)
|
||||
{
|
||||
tree baseref = build1 (INDIRECT_REF, type, base);
|
||||
tree one_init;
|
||||
|
||||
num_initialized_elts++;
|
||||
|
||||
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
|
||||
if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
|
||||
finish_expr_stmt (build_aggr_init (baseref, elt, 0, complain));
|
||||
one_init = build_aggr_init (baseref, elt, 0, complain);
|
||||
else
|
||||
finish_expr_stmt (cp_build_modify_expr (baseref, NOP_EXPR,
|
||||
elt, complain));
|
||||
one_init = cp_build_modify_expr (baseref, NOP_EXPR,
|
||||
elt, complain);
|
||||
|
||||
if (try_const)
|
||||
{
|
||||
tree e = one_init;
|
||||
if (TREE_CODE (e) == EXPR_STMT)
|
||||
e = TREE_OPERAND (e, 0);
|
||||
if (TREE_CODE (e) == CONVERT_EXPR
|
||||
&& VOID_TYPE_P (TREE_TYPE (e)))
|
||||
e = TREE_OPERAND (e, 0);
|
||||
e = maybe_constant_init (e);
|
||||
if (reduced_constant_expression_p (e))
|
||||
{
|
||||
CONSTRUCTOR_APPEND_ELT (new_vec, field, e);
|
||||
if (do_static_init)
|
||||
one_init = NULL_TREE;
|
||||
else
|
||||
one_init = build2 (INIT_EXPR, type, baseref, e);
|
||||
saw_const = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (do_static_init)
|
||||
CONSTRUCTOR_APPEND_ELT (new_vec, field,
|
||||
build_zero_init (TREE_TYPE (e),
|
||||
NULL_TREE, true));
|
||||
saw_non_const = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (one_init)
|
||||
finish_expr_stmt (one_init);
|
||||
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
|
||||
|
||||
finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0,
|
||||
|
|
@ -3014,6 +3060,16 @@ build_vec_init (tree base, tree maxindex, tree init,
|
|||
complain));
|
||||
}
|
||||
|
||||
if (try_const)
|
||||
{
|
||||
if (!saw_non_const)
|
||||
const_init = build_constructor (atype, new_vec);
|
||||
else if (do_static_init && saw_const)
|
||||
DECL_INITIAL (obase) = build_constructor (atype, new_vec);
|
||||
else
|
||||
VEC_free (constructor_elt, gc, new_vec);
|
||||
}
|
||||
|
||||
/* Clear out INIT so that we don't get confused below. */
|
||||
init = NULL_TREE;
|
||||
}
|
||||
|
|
@ -3161,6 +3217,9 @@ build_vec_init (tree base, tree maxindex, tree init,
|
|||
}
|
||||
|
||||
current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
|
||||
|
||||
if (const_init)
|
||||
return build2 (INIT_EXPR, atype, obase, const_init);
|
||||
return stmt_expr;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7176,7 +7176,8 @@ cp_parser_constant_expression (cp_parser* parser,
|
|||
saved_non_integral_constant_expression_p = parser->non_integral_constant_expression_p;
|
||||
/* We are now parsing a constant-expression. */
|
||||
parser->integral_constant_expression_p = true;
|
||||
parser->allow_non_integral_constant_expression_p = allow_non_constant_p;
|
||||
parser->allow_non_integral_constant_expression_p
|
||||
= (allow_non_constant_p || cxx_dialect >= cxx0x);
|
||||
parser->non_integral_constant_expression_p = false;
|
||||
/* Although the grammar says "conditional-expression", we parse an
|
||||
"assignment-expression", which also permits "throw-expression"
|
||||
|
|
@ -7195,7 +7196,8 @@ cp_parser_constant_expression (cp_parser* parser,
|
|||
= saved_allow_non_integral_constant_expression_p;
|
||||
if (allow_non_constant_p)
|
||||
*non_constant_p = parser->non_integral_constant_expression_p;
|
||||
else if (parser->non_integral_constant_expression_p)
|
||||
else if (parser->non_integral_constant_expression_p
|
||||
&& cxx_dialect < cxx0x)
|
||||
expression = error_mark_node;
|
||||
parser->non_integral_constant_expression_p
|
||||
= saved_non_integral_constant_expression_p;
|
||||
|
|
@ -14975,8 +14977,8 @@ cp_parser_direct_declarator (cp_parser* parser,
|
|||
= cp_parser_constant_expression (parser,
|
||||
/*allow_non_constant=*/true,
|
||||
&non_constant_p);
|
||||
if (!non_constant_p)
|
||||
bounds = fold_non_dependent_expr (bounds);
|
||||
if (!non_constant_p || cxx_dialect >= cxx0x)
|
||||
/* OK */;
|
||||
/* Normally, the array bound must be an integral constant
|
||||
expression. However, as an extension, we allow VLAs
|
||||
in function scopes as long as they aren't part of a
|
||||
|
|
@ -16408,7 +16410,15 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
|
|||
/*allow_non_constant_p=*/true,
|
||||
non_constant_p);
|
||||
if (!*non_constant_p)
|
||||
initializer = fold_non_dependent_expr (initializer);
|
||||
{
|
||||
/* We only want to fold if this is really a constant
|
||||
expression. FIXME Actually, we don't want to fold here, but in
|
||||
cp_finish_decl. */
|
||||
tree folded = fold_non_dependent_expr (initializer);
|
||||
folded = maybe_constant_value (folded);
|
||||
if (TREE_CONSTANT (folded))
|
||||
initializer = folded;
|
||||
}
|
||||
}
|
||||
else
|
||||
initializer = cp_parser_braced_list (parser, non_constant_p);
|
||||
|
|
|
|||
150
gcc/cp/pt.c
150
gcc/cp/pt.c
|
|
@ -4845,29 +4845,6 @@ fold_non_dependent_expr (tree expr)
|
|||
return fold_non_dependent_expr_sfinae (expr, tf_error);
|
||||
}
|
||||
|
||||
/* EXPR is an expression which is used in a constant-expression context.
|
||||
For instance, it could be a VAR_DECL with a constant initializer.
|
||||
Extract the innermost constant expression.
|
||||
|
||||
This is basically a more powerful version of
|
||||
integral_constant_value, which can be used also in templates where
|
||||
initializers can maintain a syntactic rather than semantic form
|
||||
(even if they are non-dependent, for access-checking purposes). */
|
||||
|
||||
static tree
|
||||
fold_decl_constant_value (tree expr)
|
||||
{
|
||||
tree const_expr = expr;
|
||||
do
|
||||
{
|
||||
expr = fold_non_dependent_expr (const_expr);
|
||||
const_expr = integral_constant_value (expr);
|
||||
}
|
||||
while (expr != const_expr);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
/* Subroutine of convert_nontype_argument. Converts EXPR to TYPE, which
|
||||
must be a function or a pointer-to-function type, as specified
|
||||
in [temp.arg.nontype]: disambiguate EXPR if it is an overload set,
|
||||
|
|
@ -5069,23 +5046,23 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
|
|||
if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))
|
||||
{
|
||||
tree t = build_integral_nontype_arg_conv (type, expr, complain);
|
||||
t = fold_decl_constant_value (t);
|
||||
t = maybe_constant_value (t);
|
||||
if (t != error_mark_node)
|
||||
expr = t;
|
||||
|
||||
if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (expr)))
|
||||
return error_mark_node;
|
||||
|
||||
/* Conversion was allowed: fold it to a bare integer constant. */
|
||||
expr = fold (expr);
|
||||
|
||||
/* Notice that there are constant expressions like '4 % 0' which
|
||||
do not fold into integer constants. */
|
||||
if (TREE_CODE (expr) != INTEGER_CST)
|
||||
{
|
||||
if (complain & tf_error)
|
||||
error ("%qE is not a valid template argument for type %qT "
|
||||
"because it is a non-constant expression", expr, type);
|
||||
{
|
||||
error ("%qE is not a valid template argument for type %qT "
|
||||
"because it is a non-constant expression", expr, type);
|
||||
cxx_constant_value (expr);
|
||||
}
|
||||
return NULL_TREE;
|
||||
}
|
||||
}
|
||||
|
|
@ -9637,8 +9614,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
|
|||
RETURN (error_mark_node);
|
||||
}
|
||||
type = complete_type (type);
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r)
|
||||
= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t);
|
||||
/* Wait until cp_finish_decl to set this again, to handle
|
||||
circular dependency (template/instantiate6.C). */
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r) = 0;
|
||||
type = check_var_type (DECL_NAME (r), type);
|
||||
|
||||
if (DECL_HAS_VALUE_EXPR_P (t))
|
||||
|
|
@ -10125,9 +10103,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
&& !TREE_TYPE (max))
|
||||
TREE_TYPE (max) = TREE_TYPE (TREE_OPERAND (max, 0));
|
||||
|
||||
max = mark_rvalue_use (max);
|
||||
max = fold_decl_constant_value (max);
|
||||
|
||||
/* If we're in a partial instantiation, preserve the magic NOP_EXPR
|
||||
with TREE_SIDE_EFFECTS that indicates this is not an integral
|
||||
constant expression. */
|
||||
|
|
@ -10138,38 +10113,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
TREE_SIDE_EFFECTS (max) = 1;
|
||||
}
|
||||
|
||||
if (TREE_CODE (max) != INTEGER_CST
|
||||
&& !at_function_scope_p ()
|
||||
&& !TREE_SIDE_EFFECTS (max)
|
||||
&& !value_dependent_expression_p (max))
|
||||
{
|
||||
if (complain & tf_error)
|
||||
error ("array bound is not an integer constant");
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* [temp.deduct]
|
||||
|
||||
Type deduction may fail for any of the following
|
||||
reasons:
|
||||
|
||||
Attempting to create an array with a size that is
|
||||
zero or negative. */
|
||||
if (integer_zerop (max) && !(complain & tf_error))
|
||||
/* We must fail if performing argument deduction (as
|
||||
indicated by the state of complain), so that
|
||||
another substitution can be found. */
|
||||
return error_mark_node;
|
||||
else if (TREE_CODE (max) == INTEGER_CST
|
||||
&& INT_CST_LT (max, integer_zero_node))
|
||||
{
|
||||
if (complain & tf_error)
|
||||
error ("creating array with negative size (%qE)", max);
|
||||
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
return compute_array_index_type (NULL_TREE, max);
|
||||
return compute_array_index_type (NULL_TREE, max, complain);
|
||||
}
|
||||
|
||||
case TEMPLATE_TYPE_PARM:
|
||||
|
|
@ -11658,10 +11602,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
|
|||
|
||||
case DECL_EXPR:
|
||||
{
|
||||
tree decl;
|
||||
tree decl, pattern_decl;
|
||||
tree init;
|
||||
|
||||
decl = DECL_EXPR_DECL (t);
|
||||
pattern_decl = decl = DECL_EXPR_DECL (t);
|
||||
if (TREE_CODE (decl) == LABEL_DECL)
|
||||
finish_label_decl (DECL_NAME (decl));
|
||||
else if (TREE_CODE (decl) == USING_DECL)
|
||||
|
|
@ -11698,6 +11642,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
|
|||
finish_anon_union (decl);
|
||||
else
|
||||
{
|
||||
int const_init = false;
|
||||
maybe_push_decl (decl);
|
||||
if (TREE_CODE (decl) == VAR_DECL
|
||||
&& DECL_PRETTY_FUNCTION_P (decl))
|
||||
|
|
@ -11730,7 +11675,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
|
|||
init = t;
|
||||
}
|
||||
|
||||
cp_finish_decl (decl, init, false, NULL_TREE, 0);
|
||||
if (TREE_CODE (decl) == VAR_DECL)
|
||||
const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P
|
||||
(pattern_decl));
|
||||
cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16894,6 +16842,7 @@ instantiate_decl (tree d, int defer_ok,
|
|||
{
|
||||
tree ns;
|
||||
tree init;
|
||||
bool const_init = false;
|
||||
|
||||
ns = decl_namespace_context (d);
|
||||
push_nested_namespace (ns);
|
||||
|
|
@ -16902,7 +16851,11 @@ instantiate_decl (tree d, int defer_ok,
|
|||
args,
|
||||
tf_warning_or_error, NULL_TREE,
|
||||
/*integral_constant_expression_p=*/false);
|
||||
cp_finish_decl (d, init, /*init_const_expr_p=*/false,
|
||||
/* Make sure the initializer is still constant, in case of
|
||||
circular dependency (template/instantiate6.C). */
|
||||
const_init
|
||||
= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern);
|
||||
cp_finish_decl (d, init, /*init_const_expr_p=*/const_init,
|
||||
/*asmspec_tree=*/NULL_TREE,
|
||||
LOOKUP_ONLYCONVERTING);
|
||||
pop_nested_class ();
|
||||
|
|
@ -16973,6 +16926,7 @@ instantiate_decl (tree d, int defer_ok,
|
|||
if (TREE_CODE (d) == VAR_DECL)
|
||||
{
|
||||
tree init;
|
||||
bool const_init = false;
|
||||
|
||||
/* Clear out DECL_RTL; whatever was there before may not be right
|
||||
since we've reset the type of the declaration. */
|
||||
|
|
@ -16980,7 +16934,8 @@ instantiate_decl (tree d, int defer_ok,
|
|||
DECL_IN_AGGR_P (d) = 0;
|
||||
|
||||
/* The initializer is placed in DECL_INITIAL by
|
||||
regenerate_decl_from_template. Pull it out so that
|
||||
regenerate_decl_from_template so we don't need to
|
||||
push/pop_access_scope again here. Pull it out so that
|
||||
cp_finish_decl can process it. */
|
||||
init = DECL_INITIAL (d);
|
||||
DECL_INITIAL (d) = NULL_TREE;
|
||||
|
|
@ -16993,7 +16948,8 @@ instantiate_decl (tree d, int defer_ok,
|
|||
|
||||
/* Enter the scope of D so that access-checking works correctly. */
|
||||
push_nested_class (DECL_CONTEXT (d));
|
||||
cp_finish_decl (d, init, false, NULL_TREE, 0);
|
||||
const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern);
|
||||
cp_finish_decl (d, init, const_init, NULL_TREE, 0);
|
||||
pop_nested_class ();
|
||||
}
|
||||
else if (TREE_CODE (d) == FUNCTION_DECL)
|
||||
|
|
@ -17633,6 +17589,23 @@ dependent_scope_p (tree scope)
|
|||
[temp.dep.constexpr]. EXPRESSION is already known to be a constant
|
||||
expression. */
|
||||
|
||||
/* FIXME this predicate is not appropriate for general expressions; the
|
||||
predicates we want instead are "valid constant expression, value
|
||||
dependent or not?", "really constant expression, not value dependent?"
|
||||
and "instantiation-dependent?". Try to integrate with
|
||||
potential_constant_expression?
|
||||
|
||||
fold_non_dependent_expr: fold if constant and not type-dependent and not value-dependent.
|
||||
(what about instantiation-dependent constant-expressions?)
|
||||
is_late_template_attribute: defer if instantiation-dependent.
|
||||
compute_array_index_type: proceed if constant and not t- or v-dependent
|
||||
if instantiation-dependent, need to remember full expression
|
||||
uses_template_parms: FIXME - need to audit callers
|
||||
tsubst_decl [function_decl]: Why is this using value_dependent_expression_p?
|
||||
dependent_type_p [array_type]: dependent if index type is dependent
|
||||
(or non-constant?)
|
||||
static_assert - instantiation-dependent */
|
||||
|
||||
bool
|
||||
value_dependent_expression_p (tree expression)
|
||||
{
|
||||
|
|
@ -17689,7 +17662,8 @@ value_dependent_expression_p (tree expression)
|
|||
/* If there are no operands, it must be an expression such
|
||||
as "int()". This should not happen for aggregate types
|
||||
because it would form non-constant expressions. */
|
||||
gcc_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type));
|
||||
gcc_assert (cxx_dialect >= cxx0x
|
||||
|| INTEGRAL_OR_ENUMERATION_TYPE_P (type));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -17733,12 +17707,6 @@ value_dependent_expression_p (tree expression)
|
|||
return (value_dependent_expression_p (TREE_OPERAND (expression, 0))
|
||||
|| value_dependent_expression_p (TREE_OPERAND (expression, 1)));
|
||||
|
||||
case CALL_EXPR:
|
||||
/* A CALL_EXPR may appear in a constant expression if it is a
|
||||
call to a builtin function, e.g., __builtin_constant_p. All
|
||||
such calls are value-dependent. */
|
||||
return true;
|
||||
|
||||
case NONTYPE_ARGUMENT_PACK:
|
||||
/* A NONTYPE_ARGUMENT_PACK is value-dependent if any packed argument
|
||||
is value-dependent. */
|
||||
|
|
@ -17771,6 +17739,30 @@ value_dependent_expression_p (tree expression)
|
|||
|| has_value_dependent_address (op));
|
||||
}
|
||||
|
||||
case CALL_EXPR:
|
||||
{
|
||||
tree fn = get_callee_fndecl (expression);
|
||||
int i, nargs;
|
||||
if (!fn && value_dependent_expression_p (CALL_EXPR_FN (expression)))
|
||||
return true;
|
||||
nargs = call_expr_nargs (expression);
|
||||
for (i = 0; i < nargs; ++i)
|
||||
{
|
||||
tree op = CALL_EXPR_ARG (expression, i);
|
||||
/* In a call to a constexpr member function, look through the
|
||||
implicit ADDR_EXPR on the object argument so that it doesn't
|
||||
cause the call to be considered value-dependent. We also
|
||||
look through it in potential_constant_expression. */
|
||||
if (i == 0 && fn && DECL_DECLARED_CONSTEXPR_P (fn)
|
||||
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
|
||||
&& TREE_CODE (op) == ADDR_EXPR)
|
||||
op = TREE_OPERAND (op, 0);
|
||||
if (value_dependent_expression_p (op))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
/* A constant expression is value-dependent if any subexpression is
|
||||
value-dependent. */
|
||||
|
|
|
|||
|
|
@ -328,6 +328,8 @@ build_typeid (tree exp)
|
|||
if (processing_template_decl)
|
||||
return build_min (TYPEID_EXPR, const_type_info_type_node, exp);
|
||||
|
||||
/* FIXME when integrating with c_fully_fold, mark
|
||||
resolves_to_fixed_type_p case as a non-constant expression. */
|
||||
if (TREE_CODE (exp) == INDIRECT_REF
|
||||
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
|
||||
&& TYPE_POLYMORPHIC_P (TREE_TYPE (exp))
|
||||
|
|
|
|||
|
|
@ -4618,6 +4618,7 @@ finish_static_assert (tree condition, tree message, location_t location,
|
|||
/* Fold the expression and convert it to a boolean value. */
|
||||
condition = fold_non_dependent_expr (condition);
|
||||
condition = cp_convert (boolean_type_node, condition);
|
||||
condition = maybe_constant_value (condition);
|
||||
|
||||
if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
|
||||
/* Do nothing; the condition is satisfied. */
|
||||
|
|
@ -4632,7 +4633,10 @@ finish_static_assert (tree condition, tree message, location_t location,
|
|||
/* Report the error. */
|
||||
error ("static assertion failed: %E", message);
|
||||
else if (condition && condition != error_mark_node)
|
||||
error ("non-constant condition for static assertion");
|
||||
{
|
||||
error ("non-constant condition for static assertion");
|
||||
cxx_constant_value (condition);
|
||||
}
|
||||
input_location = saved_loc;
|
||||
}
|
||||
}
|
||||
|
|
@ -5273,7 +5277,9 @@ ensure_literal_type_for_constexpr_object (tree decl)
|
|||
{
|
||||
tree type = TREE_TYPE (decl);
|
||||
if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl)
|
||||
&& !processing_template_decl && !literal_type_p (type))
|
||||
&& !processing_template_decl
|
||||
/* The call to complete_type is just for initializer_list. */
|
||||
&& !literal_type_p (complete_type (type)))
|
||||
{
|
||||
error ("the type %qT of constexpr variable %qD is not literal",
|
||||
type, decl);
|
||||
|
|
@ -6837,6 +6843,17 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant)
|
|||
return r;
|
||||
}
|
||||
|
||||
/* Returns true if T is a valid subexpression of a constant expression,
|
||||
even if it isn't itself a constant expression. */
|
||||
|
||||
bool
|
||||
is_sub_constant_expr (tree t)
|
||||
{
|
||||
bool non_constant_p = false;
|
||||
cxx_eval_constant_expression (NULL, t, true, false, &non_constant_p);
|
||||
return !non_constant_p;
|
||||
}
|
||||
|
||||
/* If T represents a constant expression returns its reduced value.
|
||||
Otherwise return error_mark_node. If T is dependent, then
|
||||
return NULL. */
|
||||
|
|
@ -7257,7 +7274,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
|
|||
case TRUNC_MOD_EXPR:
|
||||
case CEIL_MOD_EXPR:
|
||||
case ROUND_MOD_EXPR:
|
||||
if (integer_zerop (decl_constant_value (TREE_OPERAND (t, 1))))
|
||||
if (integer_zerop (maybe_constant_value (TREE_OPERAND (t, 1))))
|
||||
return false;
|
||||
else
|
||||
goto binary;
|
||||
|
|
|
|||
|
|
@ -3235,6 +3235,7 @@ bool
|
|||
cast_valid_in_integral_constant_expression_p (tree type)
|
||||
{
|
||||
return (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
|
||||
|| cxx_dialect >= cxx0x
|
||||
|| dependent_type_p (type)
|
||||
|| type == error_mark_node);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1930,6 +1930,9 @@ decay_conversion (tree exp)
|
|||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* FIXME remove? at least need to remember that this isn't really a
|
||||
constant expression if EXP isn't decl_constant_var_p, like with
|
||||
C_MAYBE_CONST_EXPR. */
|
||||
exp = decl_constant_value (exp);
|
||||
if (error_operand_p (exp))
|
||||
return error_mark_node;
|
||||
|
|
|
|||
|
|
@ -714,9 +714,6 @@ store_init_value (tree decl, tree init, int flags)
|
|||
|
||||
if (MAYBE_CLASS_TYPE_P (type))
|
||||
{
|
||||
gcc_assert (!type_has_nontrivial_copy_init (type)
|
||||
|| TREE_CODE (init) == CONSTRUCTOR);
|
||||
|
||||
if (TREE_CODE (init) == TREE_LIST)
|
||||
{
|
||||
error ("constructor syntax used, but no constructor declared "
|
||||
|
|
@ -743,8 +740,32 @@ store_init_value (tree decl, tree init, int flags)
|
|||
|
||||
/* End of special C++ code. */
|
||||
|
||||
/* Digest the specified initializer into an expression. */
|
||||
value = digest_init_flags (type, init, flags);
|
||||
if (flags & LOOKUP_ALREADY_DIGESTED)
|
||||
value = init;
|
||||
else
|
||||
/* Digest the specified initializer into an expression. */
|
||||
value = digest_init_flags (type, init, flags);
|
||||
|
||||
/* In C++0x constant expression is a semantic, not syntactic, property.
|
||||
In C++98, make sure that what we thought was a constant expression at
|
||||
template definition time is still constant. */
|
||||
if ((cxx_dialect >= cxx0x
|
||||
|| DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
|
||||
&& (decl_maybe_constant_var_p (decl)
|
||||
|| TREE_STATIC (decl)))
|
||||
{
|
||||
bool const_init;
|
||||
value = fold_non_dependent_expr (value);
|
||||
value = maybe_constant_init (value);
|
||||
if (DECL_DECLARED_CONSTEXPR_P (decl))
|
||||
/* Diagnose a non-constant initializer for constexpr. */
|
||||
value = cxx_constant_value (value);
|
||||
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 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. */
|
||||
|
|
@ -769,8 +790,7 @@ check_narrowing (tree type, tree init)
|
|||
bool ok = true;
|
||||
REAL_VALUE_TYPE d;
|
||||
|
||||
if (DECL_P (init))
|
||||
init = decl_constant_value (init);
|
||||
init = maybe_constant_value (init);
|
||||
|
||||
if (TREE_CODE (type) == INTEGER_TYPE
|
||||
&& TREE_CODE (ftype) == REAL_TYPE)
|
||||
|
|
@ -1632,7 +1652,11 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
|
|||
&& !TYPE_HAS_USER_CONSTRUCTOR (type))
|
||||
{
|
||||
exp = build_value_init (type, complain);
|
||||
return get_target_expr (exp);
|
||||
exp = get_target_expr (exp);
|
||||
/* FIXME this is wrong */
|
||||
if (literal_type_p (type))
|
||||
TREE_CONSTANT (exp) = true;
|
||||
return exp;
|
||||
}
|
||||
|
||||
/* Call the constructor. */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,82 @@
|
|||
2010-11-01 Jason Merrill <jason@redhat.com>
|
||||
Benjamin Kosnik <bkoz@redhat.com>
|
||||
|
||||
* g++.dg/cpp0x/constexpr-array-ptr.C: New.
|
||||
* g++.dg/cpp0x/constexpr-array-ptr2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-array-ptr3.C: New.
|
||||
* g++.dg/cpp0x/constexpr-array-ptr4.C: New.
|
||||
* g++.dg/cpp0x/constexpr-array-ptr5.C: New.
|
||||
* g++.dg/cpp0x/constexpr-array-ptr6.C: New.
|
||||
* g++.dg/cpp0x/constexpr-array.C: New.
|
||||
* g++.dg/cpp0x/constexpr-base.C: New.
|
||||
* g++.dg/cpp0x/constexpr-complex.C: New.
|
||||
* g++.dg/cpp0x/constexpr-data1.C: New.
|
||||
* g++.dg/cpp0x/constexpr-data2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-deref.C: New.
|
||||
* g++.dg/cpp0x/constexpr-diag1.C: New.
|
||||
* g++.dg/cpp0x/constexpr-eh-spec.C: New.
|
||||
* g++.dg/cpp0x/constexpr-ellipsis.C: New.
|
||||
* g++.dg/cpp0x/constexpr-ellipsis2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-empty.C: New.
|
||||
* g++.dg/cpp0x/constexpr-empty2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-empty3.C: New.
|
||||
* g++.dg/cpp0x/constexpr-empty4.C: New.
|
||||
* g++.dg/cpp0x/constexpr-empty5.C: New.
|
||||
* g++.dg/cpp0x/constexpr-ex1.C: New.
|
||||
* g++.dg/cpp0x/constexpr-ex2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-ex3.C: New.
|
||||
* g++.dg/cpp0x/constexpr-ex4.C: New.
|
||||
* g++.dg/cpp0x/constexpr-explicit-inst.C: New.
|
||||
* g++.dg/cpp0x/constexpr-fnptr.C: New.
|
||||
* g++.dg/cpp0x/constexpr-function1.C: New.
|
||||
* g++.dg/cpp0x/constexpr-function2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-function3.C: New.
|
||||
* g++.dg/cpp0x/constexpr-ice.C: New.
|
||||
* g++.dg/cpp0x/constexpr-initlist.C: New.
|
||||
* g++.dg/cpp0x/constexpr-neg1.C: New.
|
||||
* g++.dg/cpp0x/constexpr-noexcept.C: New.
|
||||
* g++.dg/cpp0x/constexpr-noexcept2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-noexcept3.C: New.
|
||||
* g++.dg/cpp0x/constexpr-noexcept4.C: New.
|
||||
* g++.dg/cpp0x/constexpr-non-const-arg.C: New.
|
||||
* g++.dg/cpp0x/constexpr-nonlit.C: New.
|
||||
* g++.dg/cpp0x/constexpr-nonlit2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-nullptr.C: New.
|
||||
* g++.dg/cpp0x/constexpr-object1.C: New.
|
||||
* g++.dg/cpp0x/constexpr-object2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-overflow.C: New.
|
||||
* g++.dg/cpp0x/constexpr-pedantic.C: New.
|
||||
* g++.dg/cpp0x/constexpr-pos1.C: New.
|
||||
* g++.dg/cpp0x/constexpr-potential1.C: New.
|
||||
* g++.dg/cpp0x/constexpr-ptrmem.C: New.
|
||||
* g++.dg/cpp0x/constexpr-pure.C: New.
|
||||
* g++.dg/cpp0x/constexpr-static.C: New.
|
||||
* g++.dg/cpp0x/constexpr-static2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-static3.C: New.
|
||||
* g++.dg/cpp0x/constexpr-static4.C: New.
|
||||
* g++.dg/cpp0x/constexpr-static5.C: New.
|
||||
* g++.dg/cpp0x/constexpr-static6.C: New.
|
||||
* g++.dg/cpp0x/constexpr-string.C: New.
|
||||
* g++.dg/cpp0x/constexpr-switch.C: New.
|
||||
* g++.dg/cpp0x/constexpr-targ.C: New.
|
||||
* g++.dg/cpp0x/constexpr-throw.C: New.
|
||||
* g++.dg/cpp0x/constexpr-typeid.C: New.
|
||||
* g++.dg/cpp0x/constexpr-union.C: New.
|
||||
* g++.dg/cpp0x/constexpr-value.C: New.
|
||||
* g++.dg/cpp0x/constexpr-value2.C: New.
|
||||
* g++.dg/cpp0x/constexpr-variadic.C: New.
|
||||
* g++.dg/cpp0x/initlist5.C: Use constexpr.
|
||||
* g++.dg/cpp0x/static_assert3.C: Add expected error.
|
||||
* g++.dg/other/fold1.C: Likewise.
|
||||
* g++.dg/parse/crash36.C: Likewise.
|
||||
* g++.dg/parse/constant4.C: Adjust expected error.
|
||||
* g++.dg/template/arg5.C: Likewise.
|
||||
* g++.dg/template/non-dependent10.C: Likewise.
|
||||
* g++.dg/template/qualified-id3.C: Likewise.
|
||||
* g++.dg/warn/overflow-warn-1.C: Likewise.
|
||||
* g++.dg/warn/overflow-warn-3.C: Likewise.
|
||||
* g++.dg/warn/overflow-warn-4.C: Likewise.
|
||||
* g++.old-deja/g++.pt/crash10.C: Likewise.
|
||||
|
||||
* g++.dg/cpp0x/constexpr-ctor2.C: New.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template<class T>
|
||||
constexpr T do_get(T* x, int n) {
|
||||
return x[n - 1];
|
||||
}
|
||||
|
||||
template<class T, int N>
|
||||
constexpr T get(T (&x)[N]) {
|
||||
return do_get(x, N);
|
||||
}
|
||||
|
||||
constexpr int arr_i[] = {1};
|
||||
constexpr auto var = get(arr_i); // #2
|
||||
static_assert(var == arr_i[0], "Error");
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template<class T>
|
||||
struct IsNegative {
|
||||
int dummy; // Workaround for empty class problem
|
||||
constexpr IsNegative() : dummy(0) {}
|
||||
constexpr bool operator()(const T& x) {
|
||||
return x < T(0);
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, int N, class Pred>
|
||||
constexpr bool has_neg(T (&x)[N], Pred p) {
|
||||
return p(x[0]) || p(x[1]);
|
||||
}
|
||||
|
||||
constexpr int a[] = {1, -2};
|
||||
|
||||
constexpr auto answer = has_neg(a, IsNegative<int>{}); // #1
|
||||
|
||||
static_assert(answer, "Error");
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
constexpr bool is_negative(int x) {
|
||||
return x < 0;
|
||||
};
|
||||
|
||||
constexpr bool do_has_neg(const int* x, bool(*p)(int)) {
|
||||
return p(x[0]) || p(x[1]); // Line 6
|
||||
}
|
||||
|
||||
constexpr bool has_neg(const int (&x)[2], bool(*p)(int)) {
|
||||
return do_has_neg(x, p); // Line 10
|
||||
}
|
||||
|
||||
constexpr int a[] = {1, -2};
|
||||
|
||||
constexpr auto answer = has_neg(a, is_negative); // Line 15
|
||||
|
||||
static_assert(answer, "Error");
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
constexpr const int do_last(const int* x, int n) {
|
||||
return x[n - 1];
|
||||
}
|
||||
|
||||
struct IsNegative {
|
||||
constexpr bool operator()(const int& x) {
|
||||
return x < 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<int N, class Pred>
|
||||
constexpr bool has_neg(const int (&x)[N], Pred p) {
|
||||
return p(do_last(x, N)); // Line 13
|
||||
}
|
||||
|
||||
constexpr int a[] = {1, -2};
|
||||
|
||||
constexpr auto answer = has_neg(a, IsNegative{}); // Line 18
|
||||
|
||||
static_assert(answer, "Error");
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template<class T>
|
||||
constexpr T do_last(T* x, int n) {
|
||||
return x[n - 1]; //
|
||||
}
|
||||
|
||||
template<class T, int N>
|
||||
constexpr T last(T (&x)[N]) {
|
||||
return do_last(x, N);
|
||||
}
|
||||
|
||||
constexpr bool is_negative(int x) { return x < 0; }
|
||||
|
||||
template<class T>
|
||||
struct IsNegative {
|
||||
constexpr bool operator()(const T& x) {
|
||||
return x < T(0);
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, int N, class Pred>
|
||||
constexpr bool has_neg(T (&x)[N], Pred p) {
|
||||
return p(last(x)); // Line 22
|
||||
}
|
||||
|
||||
constexpr int a[] = {1, -2};
|
||||
|
||||
constexpr auto answer1 = has_neg(a, IsNegative<int>{}); // Line 27
|
||||
constexpr auto answer2 = has_neg(a, is_negative);
|
||||
|
||||
static_assert(answer2 == answer1, "Error");
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
|
||||
typedef decltype(sizeof(char)) size_type;
|
||||
|
||||
template<class T, size_type N>
|
||||
constexpr size_type size(T (&)[N]) { return N; }
|
||||
|
||||
double array_double[] = { 1.0, 2.0, 3.0 };
|
||||
|
||||
constexpr auto sz_d = size(array_double);
|
||||
|
||||
static_assert(sz_d == 3, "Array size failure");
|
||||
|
||||
void f(bool (¶m)[2]) {
|
||||
static_assert(size(param) == 2, "Array size failure"); // Line 13
|
||||
short data[] = {-1, 2, -45, 6, 88, 99, -345};
|
||||
static_assert(size(data) == 7, "Array size failure");
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// { dg-options -std=c++0x }
|
||||
// { dg-final { scan-assembler-not "static_initialization" } }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
constexpr A(): i(0) { }
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
A a[4];
|
||||
};
|
||||
|
||||
extern const B b{};
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// Test base/member class and static_assert with constexpr
|
||||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A {
|
||||
int i;
|
||||
constexpr A(int _i): i(_i) { }
|
||||
};
|
||||
struct B: A {
|
||||
A a;
|
||||
int j;
|
||||
constexpr B(int _ib, int _ia, int _j): A(_ib), a(_ia), j(_j) { }
|
||||
};
|
||||
|
||||
constexpr B b (12, 24, 36);
|
||||
|
||||
#define SA(X) static_assert (X, #X)
|
||||
SA(b.i==12 && b.a.i==24 && b.j==36);
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// Make sure C99 complex works with constexpr
|
||||
// { dg-options -std=c++0x }
|
||||
|
||||
struct complex
|
||||
{
|
||||
typedef float value_type;
|
||||
typedef __complex__ float _ComplexT;
|
||||
|
||||
constexpr complex(_ComplexT __z) : _M_value(__z) { }
|
||||
|
||||
constexpr complex(float __r = 0.0f, float __i = 0.0f)
|
||||
: _M_value(__r + __i * 1.0fi) { }
|
||||
|
||||
private:
|
||||
_ComplexT _M_value;
|
||||
};
|
||||
constexpr complex c1;
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// { dg-do "compile" }
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
// From N2235
|
||||
|
||||
// 1
|
||||
struct A2
|
||||
{
|
||||
static const int eights = 888;
|
||||
static constexpr int nines = 999;
|
||||
};
|
||||
|
||||
A2 a;
|
||||
|
||||
// 2
|
||||
struct pixel
|
||||
{
|
||||
int x, y;
|
||||
};
|
||||
constexpr pixel ur = { 1294, 1024 }; // OK
|
||||
|
||||
// p4
|
||||
struct Length
|
||||
{
|
||||
explicit constexpr Length(int i = 0) : val(i) { }
|
||||
private:
|
||||
int val;
|
||||
};
|
||||
|
||||
constexpr int myabs(int x)
|
||||
{ return x < 0 ? -x : x; } // OK
|
||||
|
||||
Length l(myabs(-97)); // OK
|
||||
|
||||
// p6
|
||||
class debug_flag
|
||||
{
|
||||
public:
|
||||
explicit debug_flag(bool);
|
||||
constexpr bool is_on(); // { dg-error "enclosing class .* not a literal type" }
|
||||
private:
|
||||
bool flag;
|
||||
};
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// { dg-do "compile" }
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
template<typename _Tp, _Tp v>
|
||||
struct A3
|
||||
{
|
||||
typedef _Tp value_type;
|
||||
typedef A3<value_type,v> type;
|
||||
|
||||
static constexpr value_type value = v;
|
||||
|
||||
constexpr operator value_type() { return value; }
|
||||
};
|
||||
|
||||
// Partial specialization.
|
||||
template<typename _Tp, _Tp v>
|
||||
struct A3<_Tp*, v>
|
||||
{
|
||||
typedef _Tp* value_type;
|
||||
typedef A3<value_type,v> type;
|
||||
|
||||
static constexpr value_type value = v;
|
||||
|
||||
constexpr operator value_type() { return value; }
|
||||
};
|
||||
|
||||
// Explicit specialization.
|
||||
template<>
|
||||
struct A3<unsigned short, 0>
|
||||
{
|
||||
typedef unsigned short value_type;
|
||||
typedef A3<value_type, 0> type;
|
||||
|
||||
static constexpr value_type value = 0;
|
||||
|
||||
constexpr operator value_type() { return value; }
|
||||
};
|
||||
|
||||
// Explicitly instantiate.
|
||||
template struct A3<int, 415>;
|
||||
|
||||
// Extern explicitly instantiate.
|
||||
extern template struct A3<int, 510>;
|
||||
|
||||
// Use.
|
||||
A3<int, 1111> a31;
|
||||
// FIXME should this be an error?
|
||||
A3<char, 9999> a32; // { dg-warning "overflow" }
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A
|
||||
{
|
||||
const int *p[2];
|
||||
};
|
||||
|
||||
constexpr const int * f(const int *p) { return p; }
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr int i = 42;
|
||||
constexpr int j = *&i; // OK
|
||||
constexpr int k = *A{{&i}}.p[0]; // OK
|
||||
constexpr int l = *f(&i); // OK
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Test that we explain why a template instantiation isn't constexpr
|
||||
// { dg-options -std=c++0x }
|
||||
// { dg-prune-output "not a constexpr function" }
|
||||
|
||||
template <class T>
|
||||
struct A
|
||||
{
|
||||
T t;
|
||||
constexpr int f() { return 42; }
|
||||
};
|
||||
|
||||
struct B { B(); operator int(); };
|
||||
|
||||
constexpr A<int> ai = { 42 };
|
||||
constexpr int i = ai.f();
|
||||
|
||||
constexpr int b = A<B>().f(); // { dg-error "enclosing class" }
|
||||
|
||||
template <class T>
|
||||
constexpr int f (T t) { return 42; }
|
||||
constexpr int x = f(B()); // { dg-error "parameter" }
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// { dg-options -std=c++0x }
|
||||
template<class T> class my_limits {
|
||||
public:
|
||||
static constexpr T min() throw() { return T(); }
|
||||
static constexpr T max() noexcept { return T(); }
|
||||
};
|
||||
|
||||
constexpr double var_min = my_limits<double>::min(); // #1 OK
|
||||
constexpr double var_max = my_limits<double>::max(); // #2 Error
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// { dg-options -std=c++0x }
|
||||
constexpr int ellipsis(...) { return 1; }
|
||||
|
||||
constexpr int ellipsis_c = ellipsis(); // OK
|
||||
constexpr int ellipsis_c2 = ellipsis(42); // Internal error
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A
|
||||
{
|
||||
A();
|
||||
A(const A&);
|
||||
bool empty();
|
||||
};
|
||||
|
||||
constexpr int ellipsis(...) { return 1; }
|
||||
|
||||
static_assert(ellipsis(A().empty()), "Error"); // { dg-error "non-constant condition|empty" }
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct Empty {};
|
||||
|
||||
constexpr bool f(Empty) { return true; }
|
||||
|
||||
constexpr bool x(f(Empty{}));
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct IsLiteral {};
|
||||
|
||||
constexpr IsLiteral bar(IsLiteral x) { return x; }
|
||||
|
||||
constexpr auto xy = bar(IsLiteral()); // #1 Error, but should be OK
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct IsLiteral {};
|
||||
|
||||
constexpr auto ab = IsLiteral();
|
||||
|
||||
constexpr IsLiteral bar(IsLiteral x) { return x; }
|
||||
|
||||
constexpr auto xy = bar(ab);
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
typedef decltype(sizeof(char)) size_type;
|
||||
|
||||
template<class T, size_type N, class Pred>
|
||||
constexpr size_type do_find_if_or_stop(T (&x)[N], size_type i, Pred p);
|
||||
|
||||
template<class T, size_type N, class Pred>
|
||||
constexpr size_type do_find_if(T (&x)[N], size_type i, Pred p) {
|
||||
return p(x[i]) ? i : do_find_if_or_stop(x, i + 1, p); // line 8
|
||||
}
|
||||
|
||||
template<class T, size_type N, class Pred>
|
||||
constexpr size_type do_find_if_or_stop(T (&x)[N], size_type i, Pred p) {
|
||||
return i == N ? N : do_find_if(x, i, p);
|
||||
} // Line 14
|
||||
|
||||
template<class T, size_type N, class Pred>
|
||||
constexpr size_type find_if(T (&x)[N], Pred p) {
|
||||
return do_find_if(x, 0, p); // Line 18
|
||||
}
|
||||
|
||||
constexpr long items_long[] = {1, 2, 3, 4, -5, 6, -7, 8};
|
||||
|
||||
template<class T>
|
||||
struct IsNegative {
|
||||
constexpr bool operator()(const T& x) {
|
||||
return x < T(0);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr auto pos1 = find_if(items_long, IsNegative<long>{}); // Line 30
|
||||
|
||||
static_assert(pos1 == 4, "find_if failure");
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A { };
|
||||
struct B: A { };
|
||||
|
||||
constexpr B b { };
|
||||
constexpr A a = b;
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
// { dg-do "compile" }
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
// From N2235
|
||||
|
||||
// 4.1 constant-expression functions
|
||||
// 1 examples
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 2 defined before first use
|
||||
// NOTE: this is only needed in contexts that require a constant-expression
|
||||
struct S {
|
||||
constexpr int twice();
|
||||
constexpr int t(); // { dg-message "used but never defined" }
|
||||
private:
|
||||
static constexpr int val; // constexpr variable
|
||||
};
|
||||
constexpr int S::val = 7;
|
||||
constexpr int S::twice() { return val + val; }
|
||||
constexpr S s = { };
|
||||
int x1 = s.twice(); // ok
|
||||
int x2 = s.t(); // error: S::t() not defined
|
||||
constexpr int x2a = s.t(); // { dg-error "S::t" } error: S::t() not defined
|
||||
constexpr int ff(); // ok
|
||||
constexpr int gg(); // ok
|
||||
int x3 = ff(); // error: ff() not defined
|
||||
constexpr int x3a = ff(); // { dg-error "ff" } error: ff() not defined
|
||||
constexpr int ff() { return 1; } // too late
|
||||
constexpr int gg() { return 2; }
|
||||
int x4 = gg(); // ok
|
||||
|
||||
|
||||
// 4.2 const-expression data
|
||||
|
||||
// 2
|
||||
// storage not allocated untill address taken
|
||||
constexpr double x = 9484.748;
|
||||
const double* p = &x; // the &x forces x into memory
|
||||
|
||||
// 4.3 constant-expression constructors
|
||||
|
||||
// 1
|
||||
struct complex {
|
||||
constexpr complex(double r, double i) : re(r), im(i) { }
|
||||
constexpr double real() { return re; }
|
||||
constexpr double imag() { return im; }
|
||||
private:
|
||||
double re;
|
||||
double im;
|
||||
};
|
||||
constexpr complex I(0, 1); // OK -- literal complex
|
||||
|
||||
|
||||
// 2 invoked with non-const args
|
||||
double x5 = 1.0;
|
||||
constexpr complex unit(x5, 0); // { dg-error "x5|argument" } error: x5 non-constant
|
||||
const complex one(x5, 0); // OK, ‘‘ordinary const’’ -- dynamic
|
||||
// initialization
|
||||
constexpr double xx = I.real(); // OK
|
||||
complex z(2, 4); // OK -- ordinary variable
|
||||
|
||||
// 3
|
||||
constexpr complex v[] = {
|
||||
complex(0, 0), complex(1, 1), complex(2, 2)
|
||||
};
|
||||
constexpr double x6 = v[2].real(); // OK
|
||||
|
||||
// 4
|
||||
constexpr int i = 98;
|
||||
typedef __INTPTR_TYPE__ intptr_t;
|
||||
constexpr intptr_t ip = (intptr_t) &i; // { dg-error "constant" }
|
||||
|
||||
// 4.3.2 copy-constructor
|
||||
constexpr complex operator+(complex z, complex w)
|
||||
{
|
||||
return complex(z.real() + w.real(), z.imag() + w.imag()); // fine
|
||||
}
|
||||
constexpr complex I2 = I + I; // OK
|
||||
struct resource {
|
||||
int id;
|
||||
constexpr resource(int i) : id(i) { } // fine
|
||||
resource(const resource& r) : id(r.id) // oops, not constexpr
|
||||
{
|
||||
//cout << id << " copied" << endl;
|
||||
}
|
||||
};
|
||||
constexpr resource f(resource d)
|
||||
{ return d; } // { dg-error "not .constexpr" }
|
||||
constexpr resource d = f(9); // { dg-error "resource" }
|
||||
|
||||
// 4.4 floating-point constant expressions
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// { dg-do "compile" }
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
// From N2235
|
||||
|
||||
// 4.5.3 constant expressions
|
||||
|
||||
// p 4
|
||||
struct A {
|
||||
constexpr A(int i) : val(i) { }
|
||||
constexpr operator int() { return val; }
|
||||
constexpr operator long() { return -1; }
|
||||
private:
|
||||
int val;
|
||||
};
|
||||
|
||||
template<int I> struct X { static const int i = I; };
|
||||
constexpr A a = 42;
|
||||
|
||||
X<a> x; // OK: unique conversion to int
|
||||
int ar[X<a>::i]; // also OK
|
||||
int ary[a]; // { dg-error "ambiguous|conversion|array" } ambiguous conversion
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
|
||||
#define SA(X) static_assert (X, #X)
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
constexpr A(int _i) { i = _i; } // { dg-error "empty body|uninitialized member" }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct B
|
||||
{
|
||||
T t;
|
||||
constexpr B(T _t): t(_t) { }
|
||||
};
|
||||
|
||||
B<int> b(1);
|
||||
SA(b.t==1); // { dg-error "non-constant condition|'b'" }
|
||||
constexpr B<int> b2(1);
|
||||
SA(b2.t==1);
|
||||
|
||||
template <class T>
|
||||
constexpr T f(T a, T b)
|
||||
{
|
||||
typedef T myT;
|
||||
return a + b;
|
||||
}
|
||||
|
||||
SA(f(1,2)==3);
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
|
||||
struct A
|
||||
{
|
||||
constexpr A(int) { }
|
||||
constexpr operator int() { return 1; };
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct B
|
||||
{
|
||||
static constexpr A a = A(1);
|
||||
int ar[a];
|
||||
};
|
||||
|
||||
B<int> b;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template<class T> constexpr inline T bar(T x) { return x; }
|
||||
|
||||
template short bar(short x); // #EI
|
||||
|
||||
constexpr auto yz = bar(0); // OK
|
||||
constexpr auto ab = bar(short()); // #1 Error, but should be OK
|
||||
constexpr auto mn = bar(short{}); // #2 Error, but should be OK
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
constexpr bool is_negative(int x) { return x < 0; }
|
||||
|
||||
constexpr bool check(int x, bool (*p)(int)) { return p(x); } // #1
|
||||
|
||||
static_assert(check(-2, is_negative), "Error");
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// { dg-do "compile" }
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
// From N2235
|
||||
|
||||
constexpr int veryabs(int x) { return x < 0 ? -x : x; }
|
||||
|
||||
constexpr long long_max() { return 2147483647; }
|
||||
|
||||
constexpr int verysquare(int x) { return x * x; }
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// { dg-do "compile" }
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
// From N2235
|
||||
|
||||
// Mess with the builtin by redeclaring.
|
||||
constexpr int abs(int x) { return x < 0 ? -x : x; }
|
||||
|
||||
extern "C"
|
||||
{
|
||||
constexpr float
|
||||
squaref(float x) { return x * x; }
|
||||
}
|
||||
|
||||
// implicitly inline, already: warn?
|
||||
inline constexpr double
|
||||
squared(double x) { return x * x; }
|
||||
|
||||
constexpr int squarei(int x) { return x * x; }
|
||||
extern const int side;
|
||||
constexpr int area = squarei(side); // { dg-error "side|argument" }
|
||||
// error: squarei(side) is not a constant expression
|
||||
|
||||
int next(constexpr int x) // { dg-error "parameter" }
|
||||
{ return x + 1; }
|
||||
|
||||
constexpr void f(int x) // { dg-error "return type .void" }
|
||||
{ /* ... */ }
|
||||
|
||||
constexpr int prev(int x)
|
||||
{ return --x; } // { dg-error "--" }
|
||||
|
||||
constexpr int g(int x, int n) // error: body not just ‘‘return expr’’
|
||||
{
|
||||
int r = 1;
|
||||
while (--n > 0) r *= x;
|
||||
return r;
|
||||
} // { dg-error "not a return-statement" }
|
||||
|
||||
constexpr int
|
||||
bar(int x, int y) { return x + y + x * y; } // { dg-error "previously" }
|
||||
|
||||
int bar(int x, int y) // { dg-error "redefinition" }
|
||||
{ return x * 2 + 3 * y; }
|
||||
|
||||
constexpr int twice(int x); // { dg-message "never defined" }
|
||||
enum { bufsz = twice(256) }; // { dg-error "" } twice() isn’t (yet) defined
|
||||
|
||||
constexpr int fac(int x)
|
||||
{ return x > 2 ? x * fac(x - 1) : 1; } // OK
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// { dg-do "compile" }
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
// From N2235
|
||||
|
||||
// function template 1
|
||||
template<typename T>
|
||||
constexpr int bytesize(T t)
|
||||
{ return sizeof (t); } // OK
|
||||
|
||||
char buf[bytesize(0)]; // OK -- not C99 VLA
|
||||
|
||||
|
||||
// function template 2
|
||||
template<typename _Tp>
|
||||
constexpr _Tp
|
||||
square(_Tp x) { return x; }
|
||||
|
||||
// Explicit specialization
|
||||
template<>
|
||||
constexpr unsigned long
|
||||
square(unsigned long x) { return x * x; }
|
||||
|
||||
// Explicit instantiation
|
||||
template int square(int);
|
||||
|
||||
class A { };
|
||||
template A square(A);
|
||||
|
||||
template long square(long);
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// We used to crash on this instead of giving a decent error.
|
||||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A { int i; };
|
||||
|
||||
struct B {
|
||||
const A *a;
|
||||
constexpr B(const A& a): a(&a) { }
|
||||
};
|
||||
|
||||
constexpr B b{A{42}}; // { dg-error "constant|expansion" }
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// { dg-options -std=c++0x }
|
||||
// { dg-do run }
|
||||
|
||||
namespace xstd {
|
||||
|
||||
typedef decltype(sizeof(char)) size_t;
|
||||
|
||||
template<class E>
|
||||
class initializer_list {
|
||||
private:
|
||||
size_t sz;
|
||||
const E* start;
|
||||
|
||||
public:
|
||||
typedef E value_type;
|
||||
typedef const E& reference;
|
||||
typedef const E& const_reference;
|
||||
typedef size_t size_type;
|
||||
typedef const E* iterator;
|
||||
typedef const E* const_iterator;
|
||||
|
||||
constexpr initializer_list() : sz(), start(nullptr) {}
|
||||
|
||||
template<size_t N>
|
||||
constexpr initializer_list(const E(&array)[N]) : sz(N), start(array) {}
|
||||
|
||||
constexpr size_t size() { return sz; }
|
||||
|
||||
constexpr const E* begin() { return start; }
|
||||
|
||||
constexpr const E* end() { return start + sz; }
|
||||
};
|
||||
|
||||
template<class E, size_t N>
|
||||
constexpr initializer_list<E> make_list(const E(&array)[N]) {
|
||||
return initializer_list<E>(array);
|
||||
}
|
||||
|
||||
template<class E>
|
||||
E min(initializer_list<E> list)
|
||||
{
|
||||
// static_assert(list.size() > 0, "Invalid list");
|
||||
auto it = list.begin();
|
||||
E result = *it;
|
||||
for (++it; it != list.end(); ++it) {
|
||||
if (*it < result) {
|
||||
result = *it;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
constexpr int global_i[] = {2, 4, -5, 6, 10};
|
||||
constexpr xstd::initializer_list<int> list(global_i);
|
||||
#define SA(X) static_assert(X, #X)
|
||||
SA(list.size() == 5);
|
||||
SA(list.begin()[2] == -5);
|
||||
SA(list.end()[-1] == 10);
|
||||
|
||||
int main() {
|
||||
if (xstd::min(xstd::make_list(global_i)) != -5)
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// Negative examples from N3092 (FCD)
|
||||
// { dg-options -std=c++0x }
|
||||
|
||||
// OK: declaration
|
||||
constexpr int square(int x); // { dg-message "never defined" }
|
||||
|
||||
// error: pixel is a type
|
||||
constexpr struct pixel {
|
||||
int x;
|
||||
int y;
|
||||
// OK: declaration
|
||||
constexpr pixel(int);
|
||||
}; // { dg-error "constexpr" }
|
||||
constexpr pixel::pixel(int a)
|
||||
// OK: definition
|
||||
: x(square(a)), y(square(a)) // { dg-error "square" }
|
||||
{ }
|
||||
|
||||
// error: square not defined, so small(2) not constant (5.19), so constexpr
|
||||
// not satisfied
|
||||
constexpr pixel small(2); // { dg-error "" }
|
||||
|
||||
// error: not for parameters
|
||||
int next(constexpr int x) { // { dg-error "parameter" }
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
// error: not a definition
|
||||
extern constexpr int memsz; // { dg-error "definition" }
|
||||
|
||||
// error: return type is void
|
||||
constexpr void f(int x) // { dg-error "void" }
|
||||
{ /* ... */ }
|
||||
// error: use of decrement
|
||||
constexpr int prev(int x)
|
||||
{ return --x; } // { dg-error "-- x" }
|
||||
|
||||
// error: body not just return expr
|
||||
constexpr int g(int x, int n) {
|
||||
int r = 1;
|
||||
while (--n > 0) r *= x;
|
||||
return r;
|
||||
} // { dg-error "body of constexpr function" }
|
||||
|
||||
class debug_flag {
|
||||
public:
|
||||
explicit debug_flag(bool);
|
||||
constexpr bool is_on(); // { dg-error "not a literal type" } debug_flag not literal type
|
||||
private:
|
||||
bool flag;
|
||||
};
|
||||
// OK
|
||||
constexpr int bar(int x, int y) // { dg-error "previously defined here" }
|
||||
{ return x + y + x*y; }
|
||||
// ...
|
||||
// error: redefinition of bar
|
||||
int bar(int x, int y) // { dg-error "redefinition" }
|
||||
{ return x * 2 + 3 * y; }
|
||||
|
||||
struct pixel2 { // { dg-message "no user-provided default constructor" }
|
||||
int x, y;
|
||||
};
|
||||
constexpr pixel2 ur = { 1294, 1024 };// OK
|
||||
constexpr pixel2 origin; // { dg-error "uninitialized const" }
|
||||
|
||||
constexpr const int* addr(const int& ir) { return &ir; } // OK
|
||||
|
||||
// error, initializer for constexpr variable not a constant
|
||||
extern constexpr const int* tp = addr(5); // { dg-error "" }
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template<class T>
|
||||
struct is_funny {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
constexpr T value(T t) noexcept(is_funny<T>::value) { return t; } // Line 7
|
||||
|
||||
constexpr bool ok = noexcept(value(42));
|
||||
|
||||
static_assert(ok, "Assertion failure");
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template<class T>
|
||||
constexpr T value(T t) { return t; }
|
||||
|
||||
template<class T>
|
||||
struct is_funny {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
void eval() noexcept(value(is_funny<T>::value)) {}
|
||||
|
||||
constexpr bool ok = noexcept(eval<int>()); // line 12
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
constexpr int f(int i) { return i; }
|
||||
#define SA(X) static_assert (X, #X)
|
||||
SA(noexcept(f(42)));
|
||||
int j;
|
||||
SA(!noexcept(f(j)));
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// { dg-options -std=c++0x }
|
||||
// A call is noexcept if it is a valid subexpression of a constant
|
||||
// expression, even if it is not itself a constant expression.
|
||||
|
||||
#define SA(X) static_assert(X,#X)
|
||||
|
||||
constexpr const int* f(const int *p) { return p; }
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr int i = 42;
|
||||
SA(noexcept(*f(&i)));
|
||||
SA(noexcept(f(&i)));
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Example from issue 1125 drafting; D() and v were well-formed with the
|
||||
// wording approved in Rapperswil, now seems they should be ill-formed.
|
||||
// { dg-options "-std=c++0x -pedantic-errors" }
|
||||
|
||||
struct B {
|
||||
constexpr B(int x) : i(0) { } // "x" is unused
|
||||
int i;
|
||||
};
|
||||
|
||||
int global; // not constant
|
||||
|
||||
struct D : B {
|
||||
constexpr D() : B(global) { } // { dg-error "global|argument" }
|
||||
};
|
||||
|
||||
struct A2 {
|
||||
constexpr A2(bool b, int x) : m(b ? 42 : x) { }
|
||||
int m;
|
||||
};
|
||||
|
||||
// ok, constructor call initializes m with the value 42 after substitution
|
||||
constexpr int v = A2(true, global).m; // { dg-error "global" }
|
||||
// error: initializer for m is "x", which is non-constant
|
||||
constexpr int w = A2(false, global).m; // { dg-error "global" }
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// FIXME this is currently invalid, but seems like it should be OK
|
||||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A { A() { } };
|
||||
|
||||
template<class T>
|
||||
constexpr bool ignore(T&&) { return true; }
|
||||
|
||||
static_assert(ignore(10), "Error"); // OK
|
||||
|
||||
A s;
|
||||
|
||||
static_assert(ignore(s), "Error"); // Currently an error
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A
|
||||
{
|
||||
~A();
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct W {
|
||||
T t;
|
||||
template<class U>
|
||||
constexpr W(U&& u) : t(u) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr W<T> make_w(T& w) { return W<T>(w); }
|
||||
|
||||
A a;
|
||||
constexpr auto w = make_w(a); // { dg-error "" }
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
constexpr int zero() { return 0; }
|
||||
|
||||
void* ptr1 = zero(); // #1
|
||||
constexpr void* ptr2 = zero(); // #2
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// { dg-do "compile" }
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
// From N2235
|
||||
|
||||
// 4.5.2 semantics
|
||||
|
||||
// p 1 constexpr specifier
|
||||
// objects, static const data
|
||||
struct A1 { }; // { dg-message "no user-provided default constructor" }
|
||||
|
||||
constexpr int i1 = 1024;
|
||||
constexpr A1 a1 = A1();
|
||||
|
||||
// error: not a definition
|
||||
extern constexpr int i2; // { dg-error "definition" }
|
||||
|
||||
// error: missing initializer
|
||||
constexpr A1 a2; // { dg-error "uninitialized const" }
|
||||
|
||||
// error: duplicate cv
|
||||
const constexpr A1 a3 = A1(); // { dg-error "both .const. and .constexpr. cannot" }
|
||||
|
||||
volatile constexpr A1 a4 = A1(); // { dg-error "both .volatile. and .constexpr. cannot" }
|
||||
|
||||
// error: on type declaration
|
||||
constexpr struct pixel
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
}; // { dg-error "cannot be used for type declarations" }
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// { dg-do "compile" }
|
||||
// { dg-options "-std=gnu++0x" }
|
||||
|
||||
constexpr int verysquare(int x) { return x * x; }
|
||||
|
||||
const double mass = 9.8;
|
||||
constexpr double energy = mass * verysquare(56.6); // { dg-error "mass" "" { xfail *-*-* } }
|
||||
|
||||
int arr[(int)mass]; // { dg-error "mass" "" { xfail *-*-* } }
|
||||
|
||||
float array[verysquare(9)]; // OK -- not C99 VLA
|
||||
|
||||
extern const int medium;
|
||||
const int high = verysquare(medium); // OK -- dynamic initialization
|
||||
|
||||
enum { Max = verysquare(7) }; // OK
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// { dg-options "-std=c++0x -w" }
|
||||
|
||||
#include <limits.h>
|
||||
extern constexpr int max_s = INT_MAX + 1; // { dg-error "" }
|
||||
extern constexpr unsigned max_u = UINT_MAX + 1u; // OK
|
||||
extern constexpr int abs_s = -INT_MIN; // { dg-error "" } overflows on 2's complement machines
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// The FCD doesn't allow typedefs and static_assert in constexpr functions,
|
||||
// but it should.
|
||||
// { dg-options "-std=c++0x -pedantic" }
|
||||
|
||||
template <class T>
|
||||
constexpr T f(T t)
|
||||
{
|
||||
typedef T T2; // { dg-warning "constexpr" "" { xfail *-*-* } }
|
||||
static_assert (T2(0) == T(0), ""); // { dg-warning "constexpr" "" { xfail *-*-* } }
|
||||
return t;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr int i = f(42);
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// Positive examples from N3092 (FCD)
|
||||
// { dg-options -std=c++0x }
|
||||
|
||||
#define SA(X) static_assert(X, #X)
|
||||
|
||||
constexpr int bufsz = 1024; // OK: definition
|
||||
SA (bufsz == 1024);
|
||||
|
||||
constexpr int square(int x); // OK: declaration
|
||||
|
||||
struct pixel {
|
||||
int x;
|
||||
int y;
|
||||
// OK: declaration
|
||||
constexpr pixel(int);
|
||||
};
|
||||
constexpr pixel::pixel(int a) // OK: definition
|
||||
: x(square(a)), y(square(a))
|
||||
{ }
|
||||
|
||||
constexpr int square(int x) // OK: definition
|
||||
{ return x * x; }
|
||||
|
||||
constexpr pixel large(4); // OK: square defined
|
||||
SA(large.x == 16 && large.y==16);
|
||||
|
||||
constexpr long long_max() // OK
|
||||
{ return 2147483647; }
|
||||
|
||||
SA(long_max() == 2147483647);
|
||||
|
||||
constexpr int abs(int x) // OK
|
||||
{ return x < 0 ? -x : x; }
|
||||
|
||||
SA(abs(-1) == 1);
|
||||
SA(abs(24) == 24);
|
||||
|
||||
struct Length {
|
||||
explicit constexpr Length(int i = 0) : val(i) { }
|
||||
private:
|
||||
int val;
|
||||
};
|
||||
|
||||
constexpr Length l1;
|
||||
constexpr Length l2(12);
|
||||
|
||||
struct pixel2 {
|
||||
int x, y;
|
||||
};
|
||||
constexpr pixel2 ur = { 1294, 1024 };// OK
|
||||
|
||||
SA(ur.x == 1294 && ur.y == 1024);
|
||||
|
||||
constexpr const int* addr(const int& ir) { return &ir; } // OK
|
||||
static const int x = 5;
|
||||
extern constexpr const int* xp = addr(x); // OK: (const int*)&(const int&)x
|
||||
// is an address contant expression
|
||||
SA(xp == &x);
|
||||
extern constexpr int x2 = *addr(5);
|
||||
SA(x2 == 5);
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-options -std=c++0x }
|
||||
// We decided in Rapperswil that it's OK if any value of decide can produce
|
||||
// a constant expression.
|
||||
|
||||
constexpr int may_throw(bool decide) {
|
||||
return decide ? 42 : throw -1;
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct C { // literal type
|
||||
int m;
|
||||
int n;
|
||||
constexpr C(int m) : m(m), n(-m) {}
|
||||
constexpr bool is_neg() { return m < 0; }
|
||||
};
|
||||
|
||||
constexpr bool check1(const C& c, int C:: *pm) { return c.*pm < 0; } // #1
|
||||
|
||||
constexpr bool check2(const C* pc, bool (C::*pm)() const) { return
|
||||
(pc->*pm)(); } // #2
|
||||
|
||||
constexpr C c(-1);
|
||||
|
||||
static_assert(!check1(c, &C::n), "Error");
|
||||
static_assert(check1(c, &C::m), "Error");
|
||||
|
||||
static_assert(check2(&c, &C::is_neg), "Error");
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A
|
||||
{
|
||||
virtual void f() = 0;
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
void f() { }
|
||||
};
|
||||
|
||||
B b;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Test for constant initialization of non-literal class (e.g. mutex)
|
||||
// { dg-options "-std=c++0x -save-temps" }
|
||||
// { dg-do run }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
constexpr A(int _i): i(_i) { }
|
||||
A(const A&); // non-trivial copy ctor makes A non-literal
|
||||
};
|
||||
|
||||
A a(42); // constexpr constructor allows constant initialization
|
||||
A ar[3] = { { 1 }, { 2 }, { 3 } };
|
||||
// { dg-final { scan-assembler-not "static_initialization" } }
|
||||
// { dg-final cleanup-saved-temps }
|
||||
|
||||
int main()
|
||||
{
|
||||
if (a.i != 42
|
||||
|| ar[0].i != 1
|
||||
|| ar[1].i != 2
|
||||
|| ar[2].i != 3)
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// { dg-options -std=c++0x }
|
||||
struct IsLiteral {};
|
||||
|
||||
struct ShouldBeLiteral {
|
||||
constexpr ShouldBeLiteral(int){}
|
||||
};
|
||||
|
||||
struct StaticDataMember {
|
||||
static constexpr IsLiteral one = IsLiteral(); // #1
|
||||
static constexpr ShouldBeLiteral two= ShouldBeLiteral(-1); // #2
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Test for constant initialization of class with vtable
|
||||
// { dg-options "-std=c++0x -save-temps" }
|
||||
// { dg-final { scan-assembler-not "static_initialization" } }
|
||||
// { dg-final cleanup-saved-temps }
|
||||
// { dg-do run }
|
||||
|
||||
int r = 1;
|
||||
// implicit default constructor for A and B is constexpr
|
||||
struct A { virtual void f() {} };
|
||||
struct B: A { virtual void f() { r = 0; } };
|
||||
|
||||
B b;
|
||||
|
||||
int main()
|
||||
{
|
||||
b.f();
|
||||
return r;
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// { dg-options -std=c++0x }
|
||||
// { dg-do run }
|
||||
|
||||
extern "C" void abort ();
|
||||
extern int ar[2];
|
||||
|
||||
int f()
|
||||
{
|
||||
if (ar[0] != 42 || ar[1] != 0)
|
||||
abort ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int i = f();
|
||||
|
||||
int ar[2] = { 42, i };
|
||||
|
||||
int main()
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template <class T>
|
||||
struct A
|
||||
{
|
||||
constexpr static T t;
|
||||
};
|
||||
template <class T>
|
||||
constexpr T A<T>::t = T(); // { dg-error "not literal" }
|
||||
|
||||
struct B
|
||||
{
|
||||
~B();
|
||||
};
|
||||
|
||||
B b = A<B>::t;
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct B
|
||||
{
|
||||
constexpr operator int() { return 4; }
|
||||
};
|
||||
|
||||
template <int I>
|
||||
struct C;
|
||||
|
||||
template<>
|
||||
struct C<4> { typedef int TP; };
|
||||
|
||||
template <class T>
|
||||
struct A
|
||||
{
|
||||
constexpr static B t = B();
|
||||
C<t>::TP tp;
|
||||
};
|
||||
|
||||
A<B> a;
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
constexpr char c1 = "hi"[1];
|
||||
constexpr char c2 = "hi"[2];
|
||||
constexpr char c3 = "hi"[3]; // { dg-error "out of bound" }
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template<class T>
|
||||
constexpr T value(T t = T()) { return t; }
|
||||
|
||||
enum us_enum { us_item = value<short>() }; // OK
|
||||
|
||||
void func(us_enum n) {
|
||||
switch (n) {
|
||||
case value(us_item): ; // #1 Error
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A
|
||||
{
|
||||
constexpr operator double() { return 1.0; }
|
||||
};
|
||||
|
||||
template <int I>
|
||||
struct B
|
||||
{ };
|
||||
|
||||
constexpr A a { };
|
||||
B<a> b; // { dg-error "template argument|invalid type" }
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
constexpr int may_throw(bool decide) {
|
||||
return decide ? 42 : throw -1; // { dg-error "throw" }
|
||||
}
|
||||
|
||||
constexpr int x = may_throw(false); // { dg-error "may_throw" }
|
||||
constexpr int y = may_throw(true);
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
struct A { virtual void f(); };
|
||||
|
||||
extern constexpr const std::type_info* p1 = &typeid(int);
|
||||
extern constexpr const std::type_info* p2 = &typeid(A);
|
||||
// typeid-expression whose operand is of a polymorphic class type
|
||||
extern constexpr const std::type_info* p3 = &typeid((A())); // { dg-error "" "" { xfail *-*-* } }
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Test that we don't have to deal with type punning
|
||||
// FIXME Mike Miller thinks it should work
|
||||
// { dg-options -std=c++0x }
|
||||
|
||||
union U
|
||||
{
|
||||
float f;
|
||||
unsigned char ca[sizeof(float)];
|
||||
};
|
||||
|
||||
constexpr U u = { 1.0 };
|
||||
constexpr float f = u.f;
|
||||
constexpr unsigned char c = u.ca[0]; // { dg-error "U::ca" }
|
||||
|
||||
constexpr double d = 1.0;
|
||||
constexpr unsigned char c2 = (unsigned char&)d; // { dg-error "char. glvalue" }
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
struct HopefullyLiteral {
|
||||
HopefullyLiteral() = default; // Should be a constexpr c'tor as of 12.1/6 and 8.4.2/4
|
||||
};
|
||||
|
||||
constexpr HopefullyLiteral var1{}; // OK
|
||||
constexpr HopefullyLiteral var2 = HopefullyLiteral{}; // #1
|
||||
constexpr HopefullyLiteral var3 = HopefullyLiteral(); // #2
|
||||
constexpr HopefullyLiteral var4 = HopefullyLiteral(var3); // #3
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template<class T>
|
||||
constexpr T value_init() { return T(); }
|
||||
|
||||
template<class T>
|
||||
constexpr inline T bar(T x) { return x; }
|
||||
|
||||
union EmptyUnion {};
|
||||
union Union1 { int i; };
|
||||
union Union3 { double d; int i; char* c; };
|
||||
|
||||
constexpr auto u1 = value_init<EmptyUnion>();
|
||||
constexpr auto u2 = value_init<Union1>();
|
||||
constexpr auto u3 = value_init<Union3>();
|
||||
constexpr auto u4 = bar(EmptyUnion{});
|
||||
constexpr auto u5 = bar(Union1{});
|
||||
constexpr auto u6 = bar(Union3{});
|
||||
constexpr auto u7 = bar(u1);
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// { dg-options -std=c++0x }
|
||||
template<class... T>
|
||||
constexpr bool variadics(T&&...) { return true; }
|
||||
|
||||
struct IsLiteral {};
|
||||
|
||||
constexpr bool variadic_var = variadics(0, true, 1.2, IsLiteral{}); // Error, so below
|
||||
|
||||
int main() {}
|
||||
|
|
@ -23,5 +23,5 @@ int k {}; // initialize to 0
|
|||
// PR c++/36963
|
||||
double d = 1.1;
|
||||
float fa[] = { d, 1.1 }; // { dg-error "narrowing conversion of 'd'" }
|
||||
const double d2 = 1.1;
|
||||
constexpr double d2 = 1.1;
|
||||
float fa2[] = { d2, 1.1 };
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
static_assert(7 / 0, "X"); // { dg-error "non-constant condition" }
|
||||
// { dg-warning "division by zero" "" { target *-*-* } 2 }
|
||||
// { dg-error "7 / 0.. is not a constant expression" "" { target *-*-* } 2 }
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@
|
|||
struct A
|
||||
{
|
||||
static const int i = i; // { dg-error "not declared" }
|
||||
int x[i];
|
||||
int x[i]; // { dg-error "constant-expression" }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ void Foo ()
|
|||
|
||||
static const unsigned J = X<T>::J;
|
||||
|
||||
Y<J> j; // { dg-error "non-constant" "" }
|
||||
Y<J> j; // { dg-error "constant" "" }
|
||||
}
|
||||
|
||||
struct A
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ template <typename... T> struct A // { dg-warning "variadic templates" }
|
|||
static const int i = sizeof (++t); // { dg-error "was not declared in this scope" }
|
||||
};
|
||||
|
||||
int x[A <int>::i];
|
||||
int x[A <int>::i]; // { dg-error "constant-expression" }
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@ template<bool> struct A;
|
|||
|
||||
template<int> void foo()
|
||||
{
|
||||
A<__builtin_constant_p(.)> a; // { dg-error "template argument" }
|
||||
A<__builtin_constant_p(.)> a; // { dg-error "template argument|invalid" }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ struct X
|
|||
template <class T>
|
||||
struct Foo
|
||||
{
|
||||
X<&S::f> x; // { dg-error "convert|no type" }
|
||||
X<&S::f> x; // { dg-error "convert|no matches" }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
template <const int N> struct A { };
|
||||
template <class T> struct B {
|
||||
static const int c;
|
||||
typedef A<B<T>::c> C; // { dg-error "non-constant" }
|
||||
typedef A<B<T>::c> C; // { dg-error "constant expression" }
|
||||
};
|
||||
template <class T> const int B<T>::c = sizeof (T);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ enum e {
|
|||
in the standard). */
|
||||
E2 = 2 || 1 / 0, /* { dg-bogus "warning: division by zero" "" { xfail *-*-* } 14 } */
|
||||
E3 = 1 / 0, /* { dg-warning "division by zero" } */
|
||||
/* { dg-error "enumerator value for 'E3' is not an integer constant" "enum error" { target *-*-* } 15 } */
|
||||
/* { dg-error "enumerator value for 'E3' is not an integer constant|not a constant expression" "enum error" { target *-*-* } 15 } */
|
||||
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
|
||||
whole expression violates the constraints. */
|
||||
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ enum e {
|
|||
in the standard). */
|
||||
E2 = 2 || 1 / 0, /* { dg-bogus "warning: division by zero" "" { xfail *-*-* } 14 } */
|
||||
E3 = 1 / 0, /* { dg-warning "division by zero" } */
|
||||
/* { dg-error "enumerator value for 'E3' is not an integer constant" "enum error" { target *-*-* } 15 } */
|
||||
/* { dg-error "enumerator value for 'E3' is not an integer constant|not a constant expression" "enum error" { target *-*-* } 15 } */
|
||||
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
|
||||
whole expression violates the constraints. */
|
||||
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ enum e {
|
|||
in the standard). */
|
||||
E2 = 2 || 1 / 0, /* { dg-bogus "warning: division by zero" "" { xfail *-*-* } 14 } */
|
||||
E3 = 1 / 0, /* { dg-warning "division by zero" } */
|
||||
/* { dg-error "enumerator value for 'E3' is not an integer constant" "enum error" { target *-*-* } 15 } */
|
||||
/* { dg-error "enumerator value for 'E3' is not an integer constant|not a constant expression" "enum error" { target *-*-* } 15 } */
|
||||
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
|
||||
whole expression violates the constraints. */
|
||||
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ template<int M, int N>
|
|||
class GCD {
|
||||
public:
|
||||
enum { val = (N == 0) ? M : GCD<N, M % N>::val }; // { dg-warning "division" "division" }
|
||||
// { dg-error "not a valid" "valid" { target *-*-* } 6 }
|
||||
// { dg-error "constant expression" "valid" { target *-*-* } 6 }
|
||||
};
|
||||
|
||||
int main() {
|
||||
|
|
|
|||
|
|
@ -51,3 +51,6 @@ test04()
|
|||
// { dg-error "instantiated from here" "" { target *-*-* } 46 }
|
||||
// { dg-error "denominator cannot be zero" "" { target *-*-* } 153 }
|
||||
// { dg-error "out of range" "" { target *-*-* } 154 }
|
||||
// { dg-error "constant expression" "" { target *-*-* } 59 }
|
||||
// { dg-error "not a member" "" { target *-*-* } 162 }
|
||||
// { dg-error "not a valid template argument" "" { target *-*-* } 164 }
|
||||
|
|
|
|||
Loading…
Reference in New Issue