aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/tree.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2012-07-05 15:39:01 -0400
committerJason Merrill <jason@gcc.gnu.org>2012-07-05 15:39:01 -0400
commit49bb4bbe90dff8b1cc71e08693ed24e00b0f648e (patch)
treeeac4bef2b1fb114469b47e65ace6322e35ef5692 /gcc/cp/tree.c
parent40264d66fbdd7b44119f7b9c07f12fb31c8baedd (diff)
downloadgcc-49bb4bbe90dff8b1cc71e08693ed24e00b0f648e.zip
gcc-49bb4bbe90dff8b1cc71e08693ed24e00b0f648e.tar.gz
gcc-49bb4bbe90dff8b1cc71e08693ed24e00b0f648e.tar.bz2
re PR c++/50852 (ICE: internal compiler error: in tsubst, at cp/pt.c:11030)
PR c++/50852 PR c++/53039 * tree.c (strip_typedefs_expr): New. * cp-tree.h: Declare it. * pt.c (convert_template_argument, unify): Use it. * parser.c (cp_parser_template_declaration_after_export): Don't call fixup_template_parms. From-SVN: r189298
Diffstat (limited to 'gcc/cp/tree.c')
-rw-r--r--gcc/cp/tree.c192
1 files changed, 191 insertions, 1 deletions
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index a03f845..15effe4 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1094,7 +1094,7 @@ 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 looses template parameter names. */
+ and loses template parameter names. */
tree
strip_typedefs (tree t)
@@ -1184,6 +1184,16 @@ strip_typedefs (tree t)
TYPENAME_TYPE_FULLNAME (t),
typename_type, tf_none);
break;
+ case DECLTYPE_TYPE:
+ result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t));
+ if (result == DECLTYPE_TYPE_EXPR (t))
+ return t;
+ else
+ result = (finish_decltype_type
+ (result,
+ DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
+ tf_none));
+ break;
default:
break;
}
@@ -1205,6 +1215,186 @@ strip_typedefs (tree t)
return cp_build_qualified_type (result, cp_type_quals (t));
}
+/* Like strip_typedefs above, but works on expressions, so that in
+
+ template<class T> struct A
+ {
+ typedef T TT;
+ B<sizeof(TT)> b;
+ };
+
+ sizeof(TT) is replaced by sizeof(T). */
+
+tree
+strip_typedefs_expr (tree t)
+{
+ unsigned i,n;
+ tree r, type, *ops;
+ enum tree_code code;
+
+ if (t == NULL_TREE || t == error_mark_node)
+ return t;
+
+ if (DECL_P (t) || CONSTANT_CLASS_P (t))
+ return 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);
+
+ code = TREE_CODE (t);
+ switch (code)
+ {
+ case IDENTIFIER_NODE:
+ case TEMPLATE_PARM_INDEX:
+ case OVERLOAD:
+ case BASELINK:
+ case ARGUMENT_PACK_SELECT:
+ return t;
+
+ case TRAIT_EXPR:
+ {
+ tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t));
+ tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t));
+ if (type1 == TRAIT_EXPR_TYPE1 (t)
+ && type2 == TRAIT_EXPR_TYPE2 (t))
+ return t;
+ r = copy_node (t);
+ TRAIT_EXPR_TYPE1 (t) = type1;
+ TRAIT_EXPR_TYPE2 (t) = type2;
+ return r;
+ }
+
+ case TREE_LIST:
+ {
+ VEC(tree,gc) *vec = make_tree_vector ();
+ bool changed = false;
+ tree it;
+ for (it = t; it; it = TREE_CHAIN (it))
+ {
+ tree val = strip_typedefs_expr (TREE_VALUE (t));
+ VEC_safe_push (tree, gc, vec, val);
+ if (val != TREE_VALUE (t))
+ changed = true;
+ gcc_assert (TREE_PURPOSE (it) == NULL_TREE);
+ }
+ if (changed)
+ {
+ r = NULL_TREE;
+ FOR_EACH_VEC_ELT_REVERSE (tree, vec, i, it)
+ r = tree_cons (NULL_TREE, it, r);
+ }
+ else
+ r = t;
+ release_tree_vector (vec);
+ return r;
+ }
+
+ case TREE_VEC:
+ {
+ bool changed = false;
+ VEC(tree,gc)* vec = make_tree_vector ();
+ n = TREE_VEC_LENGTH (t);
+ VEC_reserve (tree, gc, vec, n);
+ for (i = 0; i < n; ++i)
+ {
+ tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i));
+ VEC_quick_push (tree, vec, op);
+ if (op != TREE_VEC_ELT (t, i))
+ changed = true;
+ }
+ if (changed)
+ {
+ r = copy_node (t);
+ for (i = 0; i < n; ++i)
+ TREE_VEC_ELT (r, i) = VEC_index (tree, vec, i);
+ }
+ else
+ r = t;
+ release_tree_vector (vec);
+ return r;
+ }
+
+ case CONSTRUCTOR:
+ {
+ bool changed = false;
+ VEC(constructor_elt,gc) *vec
+ = VEC_copy (constructor_elt, gc, CONSTRUCTOR_ELTS (t));
+ n = CONSTRUCTOR_NELTS (t);
+ type = strip_typedefs (TREE_TYPE (t));
+ for (i = 0; i < n; ++i)
+ {
+ constructor_elt *e = VEC_index (constructor_elt, vec, i);
+ tree op = strip_typedefs_expr (e->value);
+ if (op != e->value)
+ {
+ changed = true;
+ e->value = op;
+ }
+ gcc_checking_assert (e->index == strip_typedefs_expr (e->index));
+ }
+
+ if (!changed && type == TREE_TYPE (t))
+ {
+ VEC_free (constructor_elt, gc, vec);
+ return t;
+ }
+ else
+ {
+ r = copy_node (t);
+ TREE_TYPE (r) = type;
+ CONSTRUCTOR_ELTS (r) = vec;
+ return r;
+ }
+ }
+
+ case LAMBDA_EXPR:
+ gcc_unreachable ();
+
+ default:
+ break;
+ }
+
+ gcc_assert (EXPR_P (t));
+
+ n = TREE_OPERAND_LENGTH (t);
+ ops = XALLOCAVEC (tree, n);
+ type = TREE_TYPE (t);
+
+ switch (code)
+ {
+ CASE_CONVERT:
+ case IMPLICIT_CONV_EXPR:
+ case DYNAMIC_CAST_EXPR:
+ case STATIC_CAST_EXPR:
+ case CONST_CAST_EXPR:
+ case REINTERPRET_CAST_EXPR:
+ case CAST_EXPR:
+ case NEW_EXPR:
+ type = strip_typedefs (type);
+ /* fallthrough */
+
+ default:
+ for (i = 0; i < n; ++i)
+ ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i));
+ break;
+ }
+
+ /* If nothing changed, return t. */
+ for (i = 0; i < n; ++i)
+ if (ops[i] != TREE_OPERAND (t, i))
+ break;
+ if (i == n && type == TREE_TYPE (t))
+ return t;
+
+ r = copy_node (t);
+ TREE_TYPE (r) = type;
+ for (i = 0; i < n; ++i)
+ TREE_OPERAND (r, i) = ops[i];
+ return r;
+}
+
/* Makes a copy of BINFO and TYPE, which is to be inherited into a
graph dominated by T. If BINFO is NULL, TYPE is a dependent base,
and we do a shallow copy. If BINFO is non-NULL, we do a deep copy.