diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/mangle.c | 56 | ||||
-rw-r--r-- | gcc/cp/pt.c | 24 |
2 files changed, 76 insertions, 4 deletions
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index ab2d8ec..43ff2e8 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2850,6 +2850,60 @@ write_member_name (tree member) write_expression (member); } +/* EXPR is a base COMPONENT_REF; write the minimized base conversion path for + converting to BASE, or just the conversion of EXPR if BASE is null. + + "Given a fully explicit base path P := C_n -> ... -> C_0, the minimized base + path Min(P) is defined as follows: let C_i be the last element for which the + conversion to C_0 is unambiguous; if that element is C_n, the minimized path + is C_n -> C_0; otherwise, the minimized path is Min(C_n -> ... -> C_i) -> + C_0." + + We mangle the conversion to C_i if it's different from C_n. */ + +static bool +write_base_ref (tree expr, tree base = NULL_TREE) +{ + if (TREE_CODE (expr) != COMPONENT_REF) + return false; + + tree field = TREE_OPERAND (expr, 1); + + if (TREE_CODE (field) != FIELD_DECL || !DECL_FIELD_IS_BASE (field)) + return false; + + tree object = TREE_OPERAND (expr, 0); + + tree binfo = NULL_TREE; + if (base) + { + tree cur = TREE_TYPE (object); + binfo = lookup_base (cur, base, ba_unique, NULL, tf_none); + } + else + /* We're at the end of the base conversion chain, so it can't be + ambiguous. */ + base = TREE_TYPE (field); + + if (binfo == error_mark_node) + { + /* cur->base is ambiguous, so make the conversion to + last explicit, expressed as a cast (last&)object. */ + tree last = TREE_TYPE (expr); + write_string (OVL_OP_INFO (false, CAST_EXPR)->mangled_name); + write_type (build_reference_type (last)); + write_expression (object); + } + else if (write_base_ref (object, base)) + /* cur->base is unambiguous, but we had another base conversion + underneath and wrote it out. */; + else + /* No more base conversions, just write out the object. */ + write_expression (object); + + return true; +} + /* <expression> ::= <unary operator-name> <expression> ::= <binary operator-name> <expression> <expression> ::= <expr-primary> @@ -3268,6 +3322,8 @@ write_expression (tree expr) ob = TREE_OPERAND (ob, 0); write_expression (ob); } + else if (write_base_ref (expr)) + return; else if (!is_dummy_object (ob)) { write_string ("dt"); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5f43e9c..cfe5dcd 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6907,7 +6907,9 @@ template_parm_object_p (const_tree t) } /* Subroutine of convert_nontype_argument, to check whether EXPR, as an - argument for TYPE, points to an unsuitable object. */ + argument for TYPE, points to an unsuitable object. + + Also adjust the type of the index in C++20 array subobject references. */ static bool invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain) @@ -6935,6 +6937,19 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain) { tree decl = TREE_OPERAND (expr, 0); + if (cxx_dialect >= cxx20) + while (TREE_CODE (decl) == COMPONENT_REF + || TREE_CODE (decl) == ARRAY_REF) + { + tree &op = TREE_OPERAND (decl, 1); + if (TREE_CODE (decl) == ARRAY_REF + && TREE_CODE (op) == INTEGER_CST) + /* Canonicalize array offsets to ptrdiff_t; how they were + written doesn't matter for subobject identity. */ + op = fold_convert (ptrdiff_type_node, op); + decl = TREE_OPERAND (decl, 0); + } + if (!VAR_P (decl)) { if (complain & tf_error) @@ -6976,9 +6991,10 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain) decl); return true; } - else if (!same_type_ignoring_top_level_qualifiers_p - (strip_array_types (TREE_TYPE (type)), - strip_array_types (TREE_TYPE (decl)))) + else if (cxx_dialect < cxx20 + && !(same_type_ignoring_top_level_qualifiers_p + (strip_array_types (TREE_TYPE (type)), + strip_array_types (TREE_TYPE (decl))))) { if (complain & tf_error) error ("the address of the %qT subobject of %qD is not a " |