diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/call.c | 113 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 2 | ||||
-rw-r--r-- | gcc/cp/cvt.c | 9 | ||||
-rw-r--r-- | gcc/cp/pt.c | 97 |
5 files changed, 141 insertions, 87 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4e966a2..14eaa98 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,12 @@ 2017-06-09 Jason Merrill <jason@redhat.com> + Missing bits from N4268, constant evaluation for all non-type args. + * call.c (build_converted_constant_expr): Rename from + build_integral_nontype_arg_conv, handle all types. + * pt.c (convert_nontype_argument): In C++17 call it for all types. + Move NOP stripping inside pointer case, don't strip ADDR_EXPR. + * cvt.c (strip_fnptr_conv): Also strip conversions to the same type. + Overhaul pointer-to-member conversion and template argument handling. * call.c (standard_conversion): Avoid creating ck_pmem when the class type is the same. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index a4b6a95..ef99683 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4005,15 +4005,16 @@ build_user_type_conversion (tree totype, tree expr, int flags, /* Subroutine of convert_nontype_argument. - EXPR is an argument for a template non-type parameter of integral or - enumeration type. Do any necessary conversions (that are permitted for - non-type arguments) to convert it to the parameter type. + EXPR is an expression used in a context that requires a converted + constant-expression, such as a template non-type parameter. Do any + necessary conversions (that are permitted for converted + constant-expressions) to convert it to the desired type. If conversion is successful, returns the converted expression; otherwise, returns error_mark_node. */ tree -build_integral_nontype_arg_conv (tree type, tree expr, tsubst_flags_t complain) +build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain) { conversion *conv; void *p; @@ -4023,8 +4024,6 @@ build_integral_nontype_arg_conv (tree type, tree expr, tsubst_flags_t complain) if (error_operand_p (expr)) return error_mark_node; - gcc_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type)); - /* Get the high-water mark for the CONVERSION_OBSTACK. */ p = conversion_obstack_alloc (0); @@ -4032,36 +4031,86 @@ build_integral_nontype_arg_conv (tree type, tree expr, tsubst_flags_t complain) /*c_cast_p=*/false, LOOKUP_IMPLICIT, complain); - /* for a non-type template-parameter of integral or - enumeration type, integral promotions (4.5) and integral - conversions (4.7) are applied. */ - /* It should be sufficient to check the outermost conversion step, since - there are no qualification conversions to integer type. */ - if (conv) - switch (conv->kind) - { - /* A conversion function is OK. If it isn't constexpr, we'll - complain later that the argument isn't constant. */ - case ck_user: - /* The lvalue-to-rvalue conversion is OK. */ - case ck_rvalue: - case ck_identity: - break; + /* A converted constant expression of type T is an expression, implicitly + converted to type T, where the converted expression is a constant + expression and the implicit conversion sequence contains only + + * user-defined conversions, + * lvalue-to-rvalue conversions (7.1), + * array-to-pointer conversions (7.2), + * function-to-pointer conversions (7.3), + * qualification conversions (7.5), + * integral promotions (7.6), + * integral conversions (7.8) other than narrowing conversions (11.6.4), + * null pointer conversions (7.11) from std::nullptr_t, + * null member pointer conversions (7.12) from std::nullptr_t, and + * function pointer conversions (7.13), + + and where the reference binding (if any) binds directly. */ + + for (conversion *c = conv; + conv && c->kind != ck_identity; + c = next_conversion (c)) + { + switch (c->kind) + { + /* A conversion function is OK. If it isn't constexpr, we'll + complain later that the argument isn't constant. */ + case ck_user: + /* The lvalue-to-rvalue conversion is OK. */ + case ck_rvalue: + /* Array-to-pointer and function-to-pointer. */ + case ck_lvalue: + /* Function pointer conversions. */ + case ck_fnptr: + /* Qualification conversions. */ + case ck_qual: + break; - case ck_std: - t = next_conversion (conv)->type; - if (INTEGRAL_OR_ENUMERATION_TYPE_P (t)) + case ck_ref_bind: + if (c->need_temporary_p) + { + if (complain & tf_error) + error_at (loc, "initializing %qH with %qI in converted " + "constant expression does not bind directly", + type, next_conversion (c)->type); + conv = NULL; + } break; - if (complain & tf_error) - error_at (loc, "conversion from %qH to %qI not considered for " - "non-type template argument", t, type); - /* fall through. */ + case ck_base: + case ck_pmem: + case ck_ptr: + case ck_std: + t = next_conversion (c)->type; + if (INTEGRAL_OR_ENUMERATION_TYPE_P (t) + && INTEGRAL_OR_ENUMERATION_TYPE_P (type)) + /* Integral promotion or conversion. */ + break; + if (NULLPTR_TYPE_P (t)) + /* Conversion from nullptr to pointer or pointer-to-member. */ + break; - default: - conv = NULL; - break; - } + if (complain & tf_error) + error_at (loc, "conversion from %qH to %qI in a " + "converted constant expression", t, type); + /* fall through. */ + + default: + conv = NULL; + break; + } + } + + /* Avoid confusing convert_nontype_argument by introducing + a redundant conversion to the same reference type. */ + if (conv && conv->kind == ck_ref_bind + && REFERENCE_REF_P (expr)) + { + tree ref = TREE_OPERAND (expr, 0); + if (same_type_p (type, TREE_TYPE (ref))) + return ref; + } if (conv) expr = convert_like (conv, expr, complain); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 07da0cd..6d4d937 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5907,7 +5907,7 @@ extern bool reference_related_p (tree, tree); extern int remaining_arguments (tree); extern tree perform_implicit_conversion (tree, tree, tsubst_flags_t); extern tree perform_implicit_conversion_flags (tree, tree, tsubst_flags_t, int); -extern tree build_integral_nontype_arg_conv (tree, tree, tsubst_flags_t); +extern tree build_converted_constant_expr (tree, tree, tsubst_flags_t); extern tree perform_direct_initialization_if_possible (tree, tree, bool, tsubst_flags_t); extern tree in_charge_arg_for_name (tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 3460e13..631ff49 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -2020,8 +2020,8 @@ fnptr_conv_p (tree to, tree from) || can_convert_tx_safety (t, f)); } -/* Return FN with any NOP_EXPRs that represent function pointer - conversions stripped. */ +/* Return FN with any NOP_EXPRs stripped that represent function pointer + conversions or conversions to the same type. */ tree strip_fnptr_conv (tree fn) @@ -2029,7 +2029,10 @@ strip_fnptr_conv (tree fn) while (TREE_CODE (fn) == NOP_EXPR) { tree op = TREE_OPERAND (fn, 0); - if (fnptr_conv_p (TREE_TYPE (fn), TREE_TYPE (op))) + tree ft = TREE_TYPE (fn); + tree ot = TREE_TYPE (op); + if (same_type_p (ft, ot) + || fnptr_conv_p (ft, ot)) fn = op; else break; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b537cb8..4d4484f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6430,6 +6430,8 @@ static tree convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) { tree expr_type; + location_t loc = EXPR_LOC_OR_LOC (expr, input_location); + tree orig_expr = expr; /* Detect immediately string literals as invalid non-type argument. This special-case is not needed for correctness (we would easily @@ -6503,18 +6505,17 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) argument for a parameter of pointer to member type, we just want to leave it in that form rather than lower it to a CONSTRUCTOR. */; - else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type)) - /* Constant value checking is done later with type conversion. */; - else if (cxx_dialect >= cxx1z) + else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type) + || cxx_dialect >= cxx1z) { - if (TREE_CODE (type) != REFERENCE_TYPE) - expr = maybe_constant_value (expr); - else if (REFERENCE_REF_P (expr)) - { - expr = TREE_OPERAND (expr, 0); - expr = maybe_constant_value (expr); - expr = convert_from_reference (expr); - } + /* C++17: A template-argument for a non-type template-parameter shall + be a converted constant expression (8.20) of the type of the + template-parameter. */ + expr = build_converted_constant_expr (type, expr, complain); + if (expr == error_mark_node) + return error_mark_node; + expr = maybe_constant_value (expr); + expr = convert_from_reference (expr); } else if (TYPE_PTR_OR_PTRMEM_P (type)) { @@ -6558,26 +6559,6 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) } } - /* We could also generate a NOP_EXPR(ADDR_EXPR()) when the - parameter is a pointer to object, through decay and - qualification conversion. Let's strip everything. */ - else if (TREE_CODE (expr) == NOP_EXPR && TYPE_PTROBV_P (type)) - { - tree probe = expr; - STRIP_NOPS (probe); - if (TREE_CODE (probe) == ADDR_EXPR - && TYPE_PTR_P (TREE_TYPE (probe))) - { - /* Skip the ADDR_EXPR only if it is part of the decay for - an array. Otherwise, it is part of the original argument - in the source code. */ - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (probe, 0))) == ARRAY_TYPE) - probe = TREE_OPERAND (probe, 0); - expr = probe; - expr_type = TREE_TYPE (expr); - } - } - /* [temp.arg.nontype]/5, bullet 1 For a non-type template-parameter of integral or enumeration type, @@ -6585,10 +6566,13 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) (_conv.integral_) are applied. */ if (INTEGRAL_OR_ENUMERATION_TYPE_P (type)) { - tree t = build_integral_nontype_arg_conv (type, expr, complain); - t = maybe_constant_value (t); - if (t != error_mark_node) - expr = t; + if (cxx_dialect < cxx11) + { + tree t = build_converted_constant_expr (type, expr, complain); + 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; @@ -6606,8 +6590,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) return NULL_TREE; expr = cxx_constant_value (expr); if (errorcount > errs || warningcount + werrorcount > warns) - inform (EXPR_LOC_OR_LOC (expr, input_location), - "in template argument for type %qT ", type); + inform (loc, "in template argument for type %qT ", type); if (expr == error_mark_node) return NULL_TREE; /* else cxx_constant_value complained but gave us @@ -6629,6 +6612,23 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) conversion (_conv.array_) are applied. */ else if (TYPE_PTROBV_P (type)) { + tree decayed = expr; + + /* Look through any NOP_EXPRs around an ADDR_EXPR, whether they come from + decay_conversion or an explicit cast. If it's a problematic cast, + we'll complain about it below. */ + if (TREE_CODE (expr) == NOP_EXPR) + { + tree probe = expr; + STRIP_NOPS (probe); + if (TREE_CODE (probe) == ADDR_EXPR + && TYPE_PTR_P (TREE_TYPE (probe))) + { + expr = probe; + expr_type = TREE_TYPE (expr); + } + } + /* [temp.arg.nontype]/1 (TC1 version, DR 49): A template-argument for a non-type, non-template template-parameter @@ -6648,15 +6648,14 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) ; else if (cxx_dialect >= cxx11 && integer_zerop (expr)) /* Null pointer values are OK in C++11. */; - else if (TREE_CODE (expr) != ADDR_EXPR - && TREE_CODE (expr_type) != ARRAY_TYPE) + else if (TREE_CODE (expr) != ADDR_EXPR) { if (VAR_P (expr)) { if (complain & tf_error) error ("%qD is not a valid template argument " "because %qD is a variable, not the address of " - "a variable", expr, expr); + "a variable", orig_expr, expr); return NULL_TREE; } if (POINTER_TYPE_P (expr_type)) @@ -6664,7 +6663,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) if (complain & tf_error) error ("%qE is not a valid template argument for %qT " "because it is not the address of a variable", - expr, type); + orig_expr, type); return NULL_TREE; } /* Other values, like integer constants, might be valid @@ -6673,15 +6672,13 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) } else { - tree decl; + tree decl = TREE_OPERAND (expr, 0); - decl = ((TREE_CODE (expr) == ADDR_EXPR) - ? TREE_OPERAND (expr, 0) : expr); if (!VAR_P (decl)) { if (complain & tf_error) error ("%qE is not a valid template argument of type %qT " - "because %qE is not a variable", expr, type, decl); + "because %qE is not a variable", orig_expr, type, decl); return NULL_TREE; } else if (cxx_dialect < cxx11 && !DECL_EXTERNAL_LINKAGE_P (decl)) @@ -6689,7 +6686,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) if (complain & tf_error) error ("%qE is not a valid template argument of type %qT " "because %qD does not have external linkage", - expr, type, decl); + orig_expr, type, decl); return NULL_TREE; } else if ((cxx_dialect >= cxx11 && cxx_dialect < cxx1z) @@ -6697,7 +6694,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) { if (complain & tf_error) error ("%qE is not a valid template argument of type %qT " - "because %qD has no linkage", expr, type, decl); + "because %qD has no linkage", orig_expr, type, decl); return NULL_TREE; } /* C++17: For a non-type template-parameter of reference or pointer @@ -6734,9 +6731,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) } } - expr = decay_conversion (expr, complain); - if (expr == error_mark_node) - return error_mark_node; + expr = decayed; expr = perform_qualification_conversions (type, expr); if (expr == error_mark_node) @@ -23858,7 +23853,7 @@ value_dependent_expression_p (tree expression) { tree t = TREE_OPERAND (expression, i); - /* In some cases, some of the operands may be missing.l + /* In some cases, some of the operands may be missing. (For example, in the case of PREDECREMENT_EXPR, the amount to increment by may be missing.) That doesn't make the expression dependent. */ |