summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/pt.c28
-rw-r--r--gcc/cp/tree.c131
-rw-r--r--gcc/testsuite/g++.dg/abi/mangle40.C2
-rw-r--r--gcc/testsuite/g++.dg/ext/alias-canon2.C3
-rw-r--r--gcc/testsuite/g++.dg/ext/alias-mangle.C2
-rw-r--r--gcc/testsuite/g++.dg/ext/attrib50.C11
8 files changed, 136 insertions, 53 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a463f66c18e..717aaa68178 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,13 @@
2015-04-23 Jason Merrill <jason@redhat.com>
+ 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++/65646
* pt.c (check_explicit_specialization): Don't
SET_DECL_TEMPLATE_SPECIALIZATION for a variable with no template
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..1c4cc57f1ad 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 = TYPE_ATTRIBUTES (result); 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<constructor_elt, va_gc> *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-canon2.C b/gcc/testsuite/g++.dg/ext/alias-canon2.C
index 4833db852d3..3806cb45399 100644
--- a/gcc/testsuite/g++.dg/ext/alias-canon2.C
+++ b/gcc/testsuite/g++.dg/ext/alias-canon2.C
@@ -31,6 +31,3 @@ out_long (ui64 longVal)
}
}
}
-
-void f(ui32 *) { }
-void f(ui32a *) { }
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<typename> struct A
A();
};
-A<X> a;
+A<X> 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 <typename T> struct B;
+template <typename T> struct B<T &> {
+ typedef T type;
+};
+struct A {
+ typedef int TA __attribute__((__may_alias__));
+};
+void d() { B<int &> b; }
+int main() { B<A::TA &> b; } // { dg-warning "attributes" }