aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2010-08-06 15:35:01 -0400
committerJason Merrill <jason@gcc.gnu.org>2010-08-06 15:35:01 -0400
commit309714d4388913de9f47100d4fc77c028aee807d (patch)
tree0df2634b2632db2fc4a2ad794b8a5d160a7d78e9 /gcc
parent0c32fb95f0dc38547c4b3a50536a79cb2dc88f90 (diff)
downloadgcc-309714d4388913de9f47100d4fc77c028aee807d.zip
gcc-309714d4388913de9f47100d4fc77c028aee807d.tar.gz
gcc-309714d4388913de9f47100d4fc77c028aee807d.tar.bz2
typeck.c (complete_type_or_maybe_complain): Split out from...
* typeck.c (complete_type_or_maybe_complain): Split out from... (complete_type_or_else): Here. (build_class_member_access_expr): Call it. (finish_class_member_access_expr): Likewise. * call.c (build_special_member_call): Likewise. * cvt.c (build_expr_type_conversion): Likewise. * init.c (build_new): Likewise. * typeck2.c (build_functional_cast): Likewise. * cp-tree.h: Declare it. * init.c (build_value_init): Add complain parm. (build_value_init_noctor): Likewise. (perform_member_init): Pass it. (expand_aggr_init_1): Likewise. (build_new_1): Likewise. (build_vec_init): Likewise. * pt.c (tsubst_expr): Likewise. * typeck2.c (build_functional_cast): Likewise. * cp-tree.h: Adjust. * tree.c (build_target_expr_with_type): Handle error_mark_node. From-SVN: r162953
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog21
-rw-r--r--gcc/cp/call.c2
-rw-r--r--gcc/cp/cp-tree.h5
-rw-r--r--gcc/cp/cvt.c2
-rw-r--r--gcc/cp/init.c44
-rw-r--r--gcc/cp/pt.c3
-rw-r--r--gcc/cp/tree.c3
-rw-r--r--gcc/cp/typeck.c15
-rw-r--r--gcc/cp/typeck2.c4
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/sfinae3.C56
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/sfinae4.C23
12 files changed, 156 insertions, 27 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c9cb173..b4eea19 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,26 @@
2010-08-06 Jason Merrill <jason@redhat.com>
+ * typeck.c (complete_type_or_maybe_complain): Split out from...
+ (complete_type_or_else): Here.
+ (build_class_member_access_expr): Call it.
+ (finish_class_member_access_expr): Likewise.
+ * call.c (build_special_member_call): Likewise.
+ * cvt.c (build_expr_type_conversion): Likewise.
+ * init.c (build_new): Likewise.
+ * typeck2.c (build_functional_cast): Likewise.
+ * cp-tree.h: Declare it.
+
+ * init.c (build_value_init): Add complain parm.
+ (build_value_init_noctor): Likewise.
+ (perform_member_init): Pass it.
+ (expand_aggr_init_1): Likewise.
+ (build_new_1): Likewise.
+ (build_vec_init): Likewise.
+ * pt.c (tsubst_expr): Likewise.
+ * typeck2.c (build_functional_cast): Likewise.
+ * cp-tree.h: Adjust.
+ * tree.c (build_target_expr_with_type): Handle error_mark_node.
+
* typeck.c (decay_conversion): Any expression with type nullptr_t
decays to nullptr.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 0bc99bf..fbf98f1 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -6189,7 +6189,7 @@ build_special_member_call (tree instance, tree name, VEC(tree,gc) **args,
if (TYPE_P (binfo))
{
/* Resolve the name. */
- if (!complete_type_or_else (binfo, NULL_TREE))
+ if (!complete_type_or_maybe_complain (binfo, NULL_TREE, complain))
return error_mark_node;
binfo = TYPE_BINFO (binfo);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 155db4c..baa6656 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4915,8 +4915,8 @@ extern tree build_aggr_init (tree, tree, int,
extern int is_class_type (tree, int);
extern tree get_type_value (tree);
extern tree build_zero_init (tree, tree, bool);
-extern tree build_value_init (tree);
-extern tree build_value_init_noctor (tree);
+extern tree build_value_init (tree, tsubst_flags_t);
+extern tree build_value_init_noctor (tree, tsubst_flags_t);
extern tree build_offset_ref (tree, tree, bool);
extern tree build_new (VEC(tree,gc) **, tree, tree,
VEC(tree,gc) **, int,
@@ -5419,6 +5419,7 @@ extern tree condition_conversion (tree);
extern tree require_complete_type (tree);
extern tree complete_type (tree);
extern tree complete_type_or_else (tree, tree);
+extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t);
extern int type_unknown_p (const_tree);
enum { ce_derived, ce_normal, ce_exact };
extern bool comp_except_specs (const_tree, const_tree, int);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 26c4442..ab2b6bf 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1468,7 +1468,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
/* The code for conversions from class type is currently only used for
delete expressions. Other expressions are handled by build_new_op. */
- if (!complete_type_or_else (basetype, expr))
+ if (!complete_type_or_maybe_complain (basetype, expr, complain))
return error_mark_node;
if (!TYPE_HAS_CONVERSION (basetype))
return NULL_TREE;
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 0edb800..8555fad 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -269,7 +269,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
TYPE, as described in [dcl.init]. */
tree
-build_value_init (tree type)
+build_value_init (tree type, tsubst_flags_t complain)
{
/* [dcl.init]
@@ -302,7 +302,7 @@ build_value_init (tree type)
(type,
build_special_member_call (NULL_TREE, complete_ctor_identifier,
NULL, type, LOOKUP_NORMAL,
- tf_warning_or_error));
+ complain));
else if (TREE_CODE (type) != UNION_TYPE && TYPE_NEEDS_CONSTRUCTING (type))
{
/* This is a class that needs constructing, but doesn't have
@@ -311,21 +311,21 @@ build_value_init (tree type)
This will be handled in simplify_aggr_init_expr. */
tree ctor = build_special_member_call
(NULL_TREE, complete_ctor_identifier,
- NULL, type, LOOKUP_NORMAL, tf_warning_or_error);
+ NULL, type, LOOKUP_NORMAL, complain);
ctor = build_aggr_init_expr (type, ctor);
AGGR_INIT_ZERO_FIRST (ctor) = 1;
return ctor;
}
}
- return build_value_init_noctor (type);
+ return build_value_init_noctor (type, complain);
}
/* Like build_value_init, but don't call the constructor for TYPE. Used
for base initializers. */
tree
-build_value_init_noctor (tree type)
+build_value_init_noctor (tree type, tsubst_flags_t complain)
{
if (CLASS_TYPE_P (type))
{
@@ -347,7 +347,12 @@ build_value_init_noctor (tree type)
ftype = TREE_TYPE (field);
if (TREE_CODE (ftype) == REFERENCE_TYPE)
- error ("value-initialization of reference");
+ {
+ if (complain & tf_error)
+ error ("value-initialization of reference");
+ else
+ return error_mark_node;
+ }
/* We could skip vfields and fields of types with
user-defined constructors, but I think that won't improve
@@ -359,7 +364,7 @@ build_value_init_noctor (tree type)
corresponding to base classes as well. Thus, iterating
over TYPE_FIELDs will result in correct initialization of
all of the subobjects. */
- value = build_value_init (ftype);
+ value = build_value_init (ftype, complain);
if (value)
CONSTRUCTOR_APPEND_ELT(v, field, value);
@@ -401,7 +406,7 @@ build_value_init_noctor (tree type)
ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node,
max_index);
- ce->value = build_value_init (TREE_TYPE (type));
+ ce->value = build_value_init (TREE_TYPE (type), complain);
/* The gimplifier can't deal with a RANGE_EXPR of TARGET_EXPRs. */
gcc_assert (TREE_CODE (ce->value) != TARGET_EXPR
@@ -459,7 +464,8 @@ perform_member_init (tree member, tree init)
member);
else
{
- init = build2 (INIT_EXPR, type, decl, build_value_init (type));
+ init = build2 (INIT_EXPR, type, decl,
+ build_value_init (type, tf_warning_or_error));
finish_expr_stmt (init);
}
}
@@ -1473,7 +1479,8 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
then just zero out the object and we're done. */
else
{
- init = build2 (INIT_EXPR, type, exp, build_value_init_noctor (type));
+ init = build2 (INIT_EXPR, type, exp,
+ build_value_init_noctor (type, complain));
finish_expr_stmt (init);
return;
}
@@ -2314,8 +2321,10 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
else if (explicit_value_init_p)
{
/* Something like `new int()'. */
- init_expr = build2 (INIT_EXPR, type,
- init_expr, build_value_init (type));
+ tree val = build_value_init (type, complain);
+ if (val == error_mark_node)
+ return error_mark_node;
+ init_expr = build2 (INIT_EXPR, type, init_expr, val);
}
else
{
@@ -2534,7 +2543,7 @@ build_new (VEC(tree,gc) **placement, tree type, tree nelts,
/* The type allocated must be complete. If the new-type-id was
"T[N]" then we are just checking that "T" is complete here, but
that is equivalent, since the value of "N" doesn't matter. */
- if (!complete_type_or_else (type, NULL_TREE))
+ if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
return error_mark_node;
rval = build_new_1 (placement, type, nelts, init, use_global_new, complain);
@@ -3041,8 +3050,13 @@ build_vec_init (tree base, tree maxindex, tree init,
0, complain);
}
else if (explicit_value_init_p)
- elt_init = build2 (INIT_EXPR, type, to,
- build_value_init (type));
+ {
+ elt_init = build_value_init (type, complain);
+ if (elt_init == error_mark_node)
+ return error_mark_node;
+ else
+ elt_init = build2 (INIT_EXPR, type, to, elt_init);
+ }
else
{
gcc_assert (TYPE_NEEDS_CONSTRUCTING (type));
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2777ab7..bb6b1a0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11705,7 +11705,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
pack expansion where the parameter packs
used in that expansion were of length
zero. */
- init = build_value_init (TREE_TYPE (decl));
+ init = build_value_init (TREE_TYPE (decl),
+ complain);
if (TREE_CODE (init) == AGGR_INIT_EXPR)
init = get_target_expr (init);
}
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 450b9e8..5441448 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -477,7 +477,8 @@ build_target_expr_with_type (tree init, tree type)
{
gcc_assert (!VOID_TYPE_P (type));
- if (TREE_CODE (init) == TARGET_EXPR)
+ if (TREE_CODE (init) == TARGET_EXPR
+ || init == error_mark_node)
return init;
else if (CLASS_TYPE_P (type) && type_has_nontrivial_copy_init (type)
&& !VOID_TYPE_P (TREE_TYPE (init))
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 177f4bb..03e7297 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -135,7 +135,7 @@ complete_type (tree type)
Returns NULL_TREE if the type cannot be made complete. */
tree
-complete_type_or_else (tree type, tree value)
+complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain)
{
type = complete_type (type);
if (type == error_mark_node)
@@ -143,13 +143,20 @@ complete_type_or_else (tree type, tree value)
return NULL_TREE;
else if (!COMPLETE_TYPE_P (type))
{
- cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+ if (complain & tf_error)
+ cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
return NULL_TREE;
}
else
return type;
}
+tree
+complete_type_or_else (tree type, tree value)
+{
+ return complete_type_or_maybe_complain (type, value, tf_warning_or_error);
+}
+
/* Return truthvalue of whether type of EXP is instantiated. */
int
@@ -2209,7 +2216,7 @@ build_class_member_access_expr (tree object, tree member,
complete type). */
object_type = TREE_TYPE (object);
if (!currently_open_class (object_type)
- && !complete_type_or_else (object_type, object))
+ && !complete_type_or_maybe_complain (object_type, object, complain))
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
@@ -2585,7 +2592,7 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
The type of the first expression shall be "class object" (of a
complete type). */
if (!currently_open_class (object_type)
- && !complete_type_or_else (object_type, object))
+ && !complete_type_or_maybe_complain (object_type, object, complain))
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index ce83d7c..59b9c40 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1606,7 +1606,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
then the slot being initialized will be filled in. */
- if (!complete_type_or_else (type, NULL_TREE))
+ if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
return error_mark_node;
if (abstract_virtuals_error (NULL_TREE, type))
return error_mark_node;
@@ -1631,7 +1631,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
just calling the constructor, so fall through. */
&& !TYPE_HAS_USER_CONSTRUCTOR (type))
{
- exp = build_value_init (type);
+ exp = build_value_init (type, complain);
return get_target_expr (exp);
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d2ba094..9013a05 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2010-08-06 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/cpp0x/sfinae3.C: New.
+ * g++.dg/cpp0x/sfinae4.C: New.
+
2010-08-06 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/ssa-dce-3.c: XFAIL.
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae3.C b/gcc/testsuite/g++.dg/cpp0x/sfinae3.C
new file mode 100644
index 0000000..8582ba7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae3.C
@@ -0,0 +1,56 @@
+// { dg-options -std=c++0x }
+
+namespace std { template <class T> T&& declval(); }
+
+template<typename _Tp, typename... _Args>
+ class is_constructible_mini
+ {
+ typedef char __one;
+ typedef struct { char __arr[2]; } __two;
+
+ template<typename _Tp1, typename... _Args1>
+ static decltype(::new _Tp1(std::declval<_Args1>()...), __one())
+ __test(int);
+
+ template<typename, typename...>
+ static __two __test(...);
+
+ public:
+ static const bool value = sizeof(__test<_Tp, _Args...>(0)) == 1;
+ };
+
+/*
+template<typename _Tp>
+ class is_constructible_mini<_Tp>
+ {
+ typedef char __one;
+ typedef struct { char __arr[2]; } __two;
+
+ template<typename _Tp1>
+ static decltype(::new _Tp1, __one()) __test(int);
+
+ template<typename>
+ static __two __test(...);
+
+ public:
+ static const bool value
+ = sizeof(__test<typename std::remove_cv<_Tp>::type>(0)) == 1;
+ };
+*/
+
+struct A
+{
+ A(int);
+};
+
+struct B { };
+
+static_assert( is_constructible_mini<A, int>::value, "");
+static_assert( is_constructible_mini<A, A>::value, "");
+static_assert( !is_constructible_mini<A, int, double>::value, "");
+
+static_assert( !is_constructible_mini<A>::value, ""); // doesn't compile without the
+ // partial specialization
+
+static_assert( is_constructible_mini<B>::value, "");
+static_assert( is_constructible_mini<const B>::value, "");
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae4.C b/gcc/testsuite/g++.dg/cpp0x/sfinae4.C
new file mode 100644
index 0000000..b664831
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae4.C
@@ -0,0 +1,23 @@
+// { dg-options -std=c++0x }
+
+namespace std { template <class T> T&& declval(); }
+
+template<typename _Tp, typename... _Args>
+ class is_constructible_mini
+ {
+ typedef char __one;
+ typedef struct { char __arr[2]; } __two;
+
+ template<typename _Tp1, typename... _Args1>
+ static decltype(::new _Tp1(std::declval<_Args1>()...), __one())
+ __test(int);
+
+ template<typename, typename...>
+ static __two __test(...);
+
+ public:
+ static const bool value = sizeof(__test<_Tp, _Args...>(0)) == 1;
+ };
+
+static_assert( !is_constructible_mini<int[], int>::value, "");
+static_assert( !is_constructible_mini<void, int>::value, "");