From b71983a5baee2fd3b87233477eee7db4b5172bee Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 28 Apr 2015 10:43:54 -0400 Subject: [PATCH] re PR c++/50800 (Internal compiler error in finish_member_declarations, possibly related to may_alias attribute) PR c++/50800 * tree.c (strip_typedefs): Add remove_attributes parm. (strip_typedefs_expr): Likewise. (apply_identity_attributes): New subroutine of strip_typedefs. * pt.c (canonicalize_type_argument): Let strip_typedefs handle attrs. (convert_nontype_argument, unify): Likewise. * cp-tree.h: Adjust. From-SVN: r222530 --- gcc/cp/ChangeLog | 8 ++ gcc/cp/cp-tree.h | 4 +- gcc/cp/pt.c | 28 ++--- gcc/cp/tree.c | 131 ++++++++++++++++++------ gcc/testsuite/g++.dg/abi/mangle40.C | 2 +- gcc/testsuite/g++.dg/ext/alias-mangle.C | 2 +- gcc/testsuite/g++.dg/ext/attrib50.C | 11 ++ 7 files changed, 136 insertions(+), 50 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/attrib50.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b7c4720c41c..73d55b9b52f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,13 @@ 2015-04-28 Jason Merrill + PR c++/50800 + * tree.c (strip_typedefs): Add remove_attributes parm. + (strip_typedefs_expr): Likewise. + (apply_identity_attributes): New subroutine of strip_typedefs. + * pt.c (canonicalize_type_argument): Let strip_typedefs handle attrs. + (convert_nontype_argument, unify): Likewise. + * cp-tree.h: Adjust. + PR c++/65734 * class.c (fixup_attribute_variants): Respect TYPE_USER_ALIGN. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2a904a5f4f4..df03d1a1465 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6066,8 +6066,8 @@ extern bool class_tmpl_impl_spec_p (const_tree); extern int zero_init_p (const_tree); extern bool check_abi_tag_redeclaration (const_tree, const_tree, const_tree); extern bool check_abi_tag_args (tree, tree); -extern tree strip_typedefs (tree); -extern tree strip_typedefs_expr (tree); +extern tree strip_typedefs (tree, bool * = NULL); +extern tree strip_typedefs_expr (tree, bool * = NULL); extern tree copy_binfo (tree, tree, tree, tree *, int); extern int member_p (const_tree); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f9a5c3b70c5..ea0d3bc61b4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6493,20 +6493,14 @@ template_template_parm_bindings_ok_p (tree tparms, tree targs) static tree canonicalize_type_argument (tree arg, tsubst_flags_t complain) { - tree mv; if (!arg || arg == error_mark_node || arg == TYPE_CANONICAL (arg)) return arg; - mv = TYPE_MAIN_VARIANT (arg); - arg = strip_typedefs (arg); - if (TYPE_ALIGN (arg) != TYPE_ALIGN (mv) - || TYPE_ATTRIBUTES (arg) != TYPE_ATTRIBUTES (mv)) - { - if (complain & tf_warning) - warning (0, "ignoring attributes on template argument %qT", arg); - arg = build_aligned_type (arg, TYPE_ALIGN (mv)); - arg = cp_build_type_attribute_variant (arg, TYPE_ATTRIBUTES (mv)); - } - return arg; + bool removed_attributes = false; + tree canon = strip_typedefs (arg, &removed_attributes); + if (removed_attributes + && (complain & tf_warning)) + warning (0, "ignoring attributes on template argument %qT", arg); + return canon; } /* Convert the indicated template ARG as necessary to match the @@ -6743,7 +6737,10 @@ convert_template_argument (tree parm, argument specification is valid. */ val = convert_nontype_argument (t, orig_arg, complain); else - val = strip_typedefs_expr (orig_arg); + { + bool removed_attr = false; + val = strip_typedefs_expr (orig_arg, &removed_attr); + } if (val == NULL_TREE) val = error_mark_node; @@ -18202,7 +18199,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, && !TEMPLATE_PARM_PARAMETER_PACK (parm)) return unify_parameter_pack_mismatch (explain_p, parm, arg); - arg = strip_typedefs_expr (arg); + { + bool removed_attr = false; + arg = strip_typedefs_expr (arg, &removed_attr); + } TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg; return unify_success (explain_p); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 9a4779f4a3c..d00f0d7eab1 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-expr.h" #include "gimplify.h" #include "wide-int.h" +#include "attribs.h" static tree bot_manip (tree *, int *, void *); static tree bot_replace (tree *, int *, void *); @@ -1175,6 +1176,52 @@ cv_unqualified (tree type) return cp_build_qualified_type (type, quals); } +/* Subroutine of strip_typedefs. We want to apply to RESULT the attributes + from ATTRIBS that affect type identity, and no others. If any are not + applied, set *remove_attributes to true. */ + +static tree +apply_identity_attributes (tree result, tree attribs, bool *remove_attributes) +{ + tree first_ident = NULL_TREE; + tree new_attribs = NULL_TREE; + tree *p = &new_attribs; + + for (tree a = attribs; a; a = TREE_CHAIN (a)) + { + const attribute_spec *as + = lookup_attribute_spec (get_attribute_name (a)); + if (as && as->affects_type_identity) + { + if (!first_ident) + first_ident = a; + else if (first_ident == error_mark_node) + { + *p = tree_cons (TREE_PURPOSE (a), TREE_VALUE (a), NULL_TREE); + p = &TREE_CHAIN (*p); + } + } + else if (first_ident) + { + for (tree a2 = first_ident; a2; a2 = TREE_CHAIN (a2)) + { + *p = tree_cons (TREE_PURPOSE (a2), TREE_VALUE (a2), NULL_TREE); + p = &TREE_CHAIN (*p); + } + first_ident = error_mark_node; + } + } + if (first_ident != error_mark_node) + new_attribs = first_ident; + + if (first_ident == attribs) + /* All attributes affected type identity. */; + else + *remove_attributes = true; + + return cp_build_type_attribute_variant (result, new_attribs); +} + /* Builds a qualified variant of T that is not a typedef variant. E.g. consider the following declarations: typedef const int ConstInt; @@ -1193,10 +1240,14 @@ cv_unqualified (tree type) * If T is a type that needs structural equality its TYPE_CANONICAL (T) will be NULL. * TYPE_CANONICAL (T) desn't carry type attributes - and loses template parameter names. */ + and loses template parameter names. + + If REMOVE_ATTRIBUTES is non-null, also strip attributes that don't + affect type identity, and set the referent to true if any were + stripped. */ tree -strip_typedefs (tree t) +strip_typedefs (tree t, bool *remove_attributes) { tree result = NULL, type = NULL, t0 = NULL; @@ -1210,7 +1261,7 @@ strip_typedefs (tree t) for (; t; t = TREE_CHAIN (t)) { gcc_assert (!TREE_PURPOSE (t)); - tree elt = strip_typedefs (TREE_VALUE (t)); + tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes); if (elt != TREE_VALUE (t)) changed = true; vec_safe_push (vec, elt); @@ -1235,28 +1286,28 @@ strip_typedefs (tree t) switch (TREE_CODE (t)) { case POINTER_TYPE: - type = strip_typedefs (TREE_TYPE (t)); + type = strip_typedefs (TREE_TYPE (t), remove_attributes); result = build_pointer_type (type); break; case REFERENCE_TYPE: - type = strip_typedefs (TREE_TYPE (t)); + type = strip_typedefs (TREE_TYPE (t), remove_attributes); result = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t)); break; case OFFSET_TYPE: - t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t)); - type = strip_typedefs (TREE_TYPE (t)); + t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), remove_attributes); + type = strip_typedefs (TREE_TYPE (t), remove_attributes); result = build_offset_type (t0, type); break; case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (t)) { - t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t)); + t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t), remove_attributes); result = build_ptrmemfunc_type (t0); } break; case ARRAY_TYPE: - type = strip_typedefs (TREE_TYPE (t)); - t0 = strip_typedefs (TYPE_DOMAIN (t));; + type = strip_typedefs (TREE_TYPE (t), remove_attributes); + t0 = strip_typedefs (TYPE_DOMAIN (t), remove_attributes); result = build_cplus_array_type (type, t0); break; case FUNCTION_TYPE: @@ -1269,7 +1320,8 @@ strip_typedefs (tree t) { if (arg_node == void_list_node) break; - arg_type = strip_typedefs (TREE_VALUE (arg_node)); + arg_type = strip_typedefs (TREE_VALUE (arg_node), + remove_attributes); gcc_assert (arg_type); arg_types = @@ -1284,7 +1336,7 @@ strip_typedefs (tree t) if (arg_node) arg_types = chainon (arg_types, void_list_node); - type = strip_typedefs (TREE_TYPE (t)); + type = strip_typedefs (TREE_TYPE (t), remove_attributes); if (TREE_CODE (t) == METHOD_TYPE) { tree class_type = TREE_TYPE (TREE_VALUE (arg_types)); @@ -1325,9 +1377,9 @@ strip_typedefs (tree t) tree arg = TREE_VEC_ELT (args, i); tree strip_arg; if (TYPE_P (arg)) - strip_arg = strip_typedefs (arg); + strip_arg = strip_typedefs (arg, remove_attributes); else - strip_arg = strip_typedefs_expr (arg); + strip_arg = strip_typedefs_expr (arg, remove_attributes); TREE_VEC_ELT (new_args, i) = strip_arg; if (strip_arg != arg) changed = true; @@ -1343,12 +1395,14 @@ strip_typedefs (tree t) else ggc_free (new_args); } - result = make_typename_type (strip_typedefs (TYPE_CONTEXT (t)), + result = make_typename_type (strip_typedefs (TYPE_CONTEXT (t), + remove_attributes), fullname, typename_type, tf_none); } break; case DECLTYPE_TYPE: - result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t)); + result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t), + remove_attributes); if (result == DECLTYPE_TYPE_EXPR (t)) return t; else @@ -1367,14 +1421,25 @@ strip_typedefs (tree t) || TYPE_ALIGN (t) != TYPE_ALIGN (result)) { gcc_assert (TYPE_USER_ALIGN (t)); - if (TYPE_ALIGN (t) == TYPE_ALIGN (result)) - result = build_variant_type_copy (result); + if (remove_attributes) + *remove_attributes = true; else - result = build_aligned_type (result, TYPE_ALIGN (t)); - TYPE_USER_ALIGN (result) = true; + { + if (TYPE_ALIGN (t) == TYPE_ALIGN (result)) + result = build_variant_type_copy (result); + else + result = build_aligned_type (result, TYPE_ALIGN (t)); + TYPE_USER_ALIGN (result) = true; + } } if (TYPE_ATTRIBUTES (t)) - result = cp_build_type_attribute_variant (result, TYPE_ATTRIBUTES (t)); + { + if (remove_attributes) + result = apply_identity_attributes (result, TYPE_ATTRIBUTES (t), + remove_attributes); + else + result = cp_build_type_attribute_variant (result, TYPE_ATTRIBUTES (t)); + } return cp_build_qualified_type (result, cp_type_quals (t)); } @@ -1389,7 +1454,7 @@ strip_typedefs (tree t) sizeof(TT) is replaced by sizeof(T). */ tree -strip_typedefs_expr (tree t) +strip_typedefs_expr (tree t, bool *remove_attributes) { unsigned i,n; tree r, type, *ops; @@ -1404,7 +1469,7 @@ strip_typedefs_expr (tree t) /* Some expressions have type operands, so let's handle types here rather than check TYPE_P in multiple places below. */ if (TYPE_P (t)) - return strip_typedefs (t); + return strip_typedefs (t, remove_attributes); code = TREE_CODE (t); switch (code) @@ -1418,8 +1483,8 @@ strip_typedefs_expr (tree t) case TRAIT_EXPR: { - tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t)); - tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t)); + tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t), remove_attributes); + tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t), remove_attributes); if (type1 == TRAIT_EXPR_TYPE1 (t) && type2 == TRAIT_EXPR_TYPE2 (t)) return t; @@ -1436,7 +1501,7 @@ strip_typedefs_expr (tree t) tree it; for (it = t; it; it = TREE_CHAIN (it)) { - tree val = strip_typedefs_expr (TREE_VALUE (t)); + tree val = strip_typedefs_expr (TREE_VALUE (t), remove_attributes); vec_safe_push (vec, val); if (val != TREE_VALUE (t)) changed = true; @@ -1462,7 +1527,8 @@ strip_typedefs_expr (tree t) vec_safe_reserve (vec, n); for (i = 0; i < n; ++i) { - tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i)); + tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i), + remove_attributes); vec->quick_push (op); if (op != TREE_VEC_ELT (t, i)) changed = true; @@ -1487,17 +1553,18 @@ strip_typedefs_expr (tree t) vec *vec = vec_safe_copy (CONSTRUCTOR_ELTS (t)); n = CONSTRUCTOR_NELTS (t); - type = strip_typedefs (TREE_TYPE (t)); + type = strip_typedefs (TREE_TYPE (t), remove_attributes); for (i = 0; i < n; ++i) { constructor_elt *e = &(*vec)[i]; - tree op = strip_typedefs_expr (e->value); + tree op = strip_typedefs_expr (e->value, remove_attributes); if (op != e->value) { changed = true; e->value = op; } - gcc_checking_assert (e->index == strip_typedefs_expr (e->index)); + gcc_checking_assert + (e->index == strip_typedefs_expr (e->index, remove_attributes)); } if (!changed && type == TREE_TYPE (t)) @@ -1538,12 +1605,12 @@ strip_typedefs_expr (tree t) case REINTERPRET_CAST_EXPR: case CAST_EXPR: case NEW_EXPR: - type = strip_typedefs (type); + type = strip_typedefs (type, remove_attributes); /* fallthrough */ default: for (i = 0; i < n; ++i) - ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i)); + ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i), remove_attributes); break; } diff --git a/gcc/testsuite/g++.dg/abi/mangle40.C b/gcc/testsuite/g++.dg/abi/mangle40.C index 2b8300bff6f..a7032a0b24c 100644 --- a/gcc/testsuite/g++.dg/abi/mangle40.C +++ b/gcc/testsuite/g++.dg/abi/mangle40.C @@ -24,5 +24,5 @@ void f (T t) { } // { dg-warning "mangled name" } int main() { - f (A<__m128>::t); + f (A<__v4sf>::t); } diff --git a/gcc/testsuite/g++.dg/ext/alias-mangle.C b/gcc/testsuite/g++.dg/ext/alias-mangle.C index a7706e996d0..d804c1a8805 100644 --- a/gcc/testsuite/g++.dg/ext/alias-mangle.C +++ b/gcc/testsuite/g++.dg/ext/alias-mangle.C @@ -8,4 +8,4 @@ template struct A A(); }; -A a; +A a; // { dg-warning "ignoring attributes on template argument" } diff --git a/gcc/testsuite/g++.dg/ext/attrib50.C b/gcc/testsuite/g++.dg/ext/attrib50.C new file mode 100644 index 00000000000..9ff9918fb80 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib50.C @@ -0,0 +1,11 @@ +// PR c++/50800 + +template struct B; +template struct B { + typedef T type; +}; +struct A { + typedef int TA __attribute__((__may_alias__)); +}; +void d() { B b; } +int main() { B b; } // { dg-warning "attributes" } -- 2.30.2