aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog30
-rw-r--r--gcc/cp/class.c5
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/decl.c19
-rw-r--r--gcc/cp/parse.y13
-rw-r--r--gcc/cp/pt.c20
-rw-r--r--gcc/cp/search.c89
-rw-r--r--gcc/cp/tree.c22
-rw-r--r--gcc/cp/typeck.c105
-rw-r--r--gcc/cp/typeck2.c53
10 files changed, 284 insertions, 76 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 74bde45..3617a86 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,33 @@
+1999-08-04 Nathan Sidwell <nathan@acm.org>
+
+ * cp-tree.h (empty_except_spec): New global var.
+ (compexcepttypes): Remove prototype.
+ (comp_except_specs): Prototype new global function.
+ (add_exception_specifier): Prototype new global function.
+ * decl.c (empty_except_spec): Define new global var.
+ (duplicate_decls): Use comp_except_specs, reword error message.
+ (init_decl_processing): Initialize empty_except_spec.
+ Adjust build_exception_variant calls.
+ * parse.y (exception_specification_opt): Use empty_except_spec.
+ (ansi_raise_identifier): Call check_for_new_type.
+ (ansi_raise_identifiers): Use add_exception_specifier.
+ * pt.c (tsubst): Use add_exception_specifier to build exception
+ specifier.
+ * search.c (check_final_overrider): New static function, broken
+ out of get_matching_virtual. Check throw specifiers, reword
+ diagnostics.
+ (get_matching_virtual): Use check_final_overrider.
+ * tree.c (build_exception_variant): Use comp_except_specs.
+ * typeck.c (compexcepttypes): Remove.
+ (comp_except_types): New static function, helper for
+ comp_except_specs. Compare two types as exception specifiers.
+ (comp_except_specs): New global function, compare two exception
+ specifiers.
+ (comptypes): Adjust for comp_except_specs.
+ * typeck2.c (add_exception_specifier): New global function.
+
+ * class.c (check_for_override): Reword error message.
+
1999-08-03 Nathan Sidwell <nathan@acm.org>
* call.c (convert_arg_to_ellipsis): Use pod_type_p.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 8ba5694..4f7172b 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -2977,9 +2977,8 @@ check_for_override (decl, ctype)
path to its virtual baseclass. */
if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
{
- cp_error_at ("method `%D' may not be declared static",
- decl);
- cp_error_at ("(since `%D' declared virtual in base class.)",
+ cp_error_at ("`static %#D' cannot be declared", decl);
+ cp_error_at (" since `virtual %#D' declared in base class",
tmp);
break;
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 31e9f8c..5c7f737 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2288,6 +2288,7 @@ extern tree delta2_identifier;
extern tree pfn_or_delta2_identifier;
extern tree tag_identifier;
extern tree vt_off_identifier;
+extern tree empty_except_spec;
/* A node that is a list (length 1) of error_mark_nodes. */
extern tree error_mark_list;
@@ -3533,7 +3534,7 @@ extern int fntype_p PROTO((tree));
extern tree commonparms PROTO((tree, tree));
extern tree original_type PROTO((tree));
extern tree common_type PROTO((tree, tree));
-extern int compexcepttypes PROTO((tree, tree));
+extern int comp_except_specs PROTO((tree, tree, int));
extern int comptypes PROTO((tree, tree, int));
extern int comp_target_types PROTO((tree, tree, int));
extern int compparms PROTO((tree, tree));
@@ -3618,6 +3619,7 @@ extern tree build_functional_cast PROTO((tree, tree));
extern char *enum_name_string PROTO((tree, tree));
extern void report_case_error PROTO((int, tree, tree, tree));
extern void check_for_new_type PROTO((const char *, flagged_type_tree));
+extern tree add_exception_specifier PROTO((tree, tree, int));
/* in xref.c */
extern void GNU_xref_begin PROTO((const char *));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 498384b..6702f2c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -336,6 +336,9 @@ tree pfn_identifier, index_identifier, delta_identifier, delta2_identifier;
tree pfn_or_delta2_identifier, tag_identifier;
tree vt_off_identifier;
+/* Exception specifier used for throw(). */
+tree empty_except_spec;
+
struct named_label_list
{
struct binding_level *binding_level;
@@ -3478,11 +3481,12 @@ duplicate_decls (newdecl, olddecl)
if ((pedantic || ! DECL_IN_SYSTEM_HEADER (olddecl))
&& DECL_SOURCE_LINE (olddecl) != 0
&& flag_exceptions
- && ! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)))
+ && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)),
+ TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl)), 1))
{
- cp_pedwarn ("declaration of `%D' throws different exceptions",
+ cp_error ("declaration of `%F' throws different exceptions",
newdecl);
- cp_pedwarn_at ("previous declaration here", olddecl);
+ cp_error_at ("to previous declaration `%F'", olddecl);
}
}
TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
@@ -6361,6 +6365,7 @@ init_decl_processing ()
const_string_type_node
= build_pointer_type (build_qualified_type (char_type_node,
TYPE_QUAL_CONST));
+ empty_except_spec = build_tree_list (NULL_TREE, NULL_TREE);
#if 0
record_builtin_type (RID_MAX, NULL_PTR, string_type_node);
#endif
@@ -6400,8 +6405,7 @@ init_decl_processing ()
c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin);
void_ftype_ptr
- = build_exception_variant (void_ftype_ptr,
- tree_cons (NULL_TREE, NULL_TREE, NULL_TREE));
+ = build_exception_variant (void_ftype_ptr, empty_except_spec);
/* C++ extensions */
@@ -6547,9 +6551,8 @@ init_decl_processing ()
if (flag_honor_std)
pop_namespace ();
newtype = build_exception_variant
- (ptr_ftype_sizetype, build_tree_list (NULL_TREE, bad_alloc_type_node));
- deltype = build_exception_variant
- (void_ftype_ptr, build_tree_list (NULL_TREE, NULL_TREE));
+ (ptr_ftype_sizetype, add_exception_specifier (NULL_TREE, bad_alloc_type_node, -1));
+ deltype = build_exception_variant (void_ftype_ptr, empty_except_spec);
auto_function (ansi_opname[(int) NEW_EXPR], newtype, NOT_BUILT_IN);
auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype, NOT_BUILT_IN);
global_delete_fndecl
diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y
index 9551c15..1fd3c5a 100644
--- a/gcc/cp/parse.y
+++ b/gcc/cp/parse.y
@@ -3685,21 +3685,22 @@ exception_specification_opt:
| THROW '(' ansi_raise_identifiers ')' %prec EMPTY
{ $$ = $3; }
| THROW LEFT_RIGHT %prec EMPTY
- { $$ = build_decl_list (NULL_TREE, NULL_TREE); }
+ { $$ = empty_except_spec; }
;
ansi_raise_identifier:
type_id
- { $$ = build_decl_list (NULL_TREE, groktypename($1.t)); }
+ {
+ check_for_new_type ("exception specifier", $1);
+ $$ = groktypename ($1.t);
+ }
;
ansi_raise_identifiers:
ansi_raise_identifier
+ { $$ = add_exception_specifier (NULL_TREE, $1, 1); }
| ansi_raise_identifiers ',' ansi_raise_identifier
- {
- TREE_CHAIN ($3) = $$;
- $$ = $3;
- }
+ { $$ = add_exception_specifier ($1, $3, 1); }
;
conversion_declarator:
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4e9b412..b516cb9 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3937,6 +3937,7 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
type_decl = build_decl (TYPE_DECL, DECL_NAME (template), t);
SET_DECL_ARTIFICIAL (type_decl);
DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t);
+
DECL_SOURCE_FILE (type_decl)
= DECL_SOURCE_FILE (TYPE_STUB_DECL (template_type));
DECL_SOURCE_LINE (type_decl)
@@ -6499,10 +6500,21 @@ tsubst (t, args, complain, in_decl)
raises = TYPE_RAISES_EXCEPTIONS (t);
if (raises)
{
- raises = tsubst (raises, args, complain, in_decl);
- if (raises == error_mark_node)
- return raises;
- fntype = build_exception_variant (fntype, raises);
+ tree list = NULL_TREE;
+
+ if (! TREE_VALUE (raises))
+ list = raises;
+ else
+ for (; raises != NULL_TREE; raises = TREE_CHAIN (raises))
+ {
+ tree spec = TREE_VALUE (raises);
+
+ spec = tsubst (spec, args, complain, in_decl);
+ if (spec == error_mark_node)
+ return spec;
+ list = add_exception_specifier (list, spec, complain);
+ }
+ fntype = build_exception_variant (fntype, list);
}
return fntype;
}
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 3af71f1..14e1ce9 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -117,6 +117,7 @@ static tree get_virtuals_named_this PROTO((tree, tree));
static tree get_virtual_destructor PROTO((tree, void *));
static tree tree_has_any_destructor_p PROTO((tree, void *));
static int covariant_return_p PROTO((tree, tree));
+static int check_final_overrider PROTO((tree, tree));
static struct search_level *push_search_level
PROTO((struct stack_level *, struct obstack *));
static struct search_level *pop_search_level
@@ -1884,6 +1885,63 @@ covariant_return_p (brettype, drettype)
return 1;
}
+/* Check that virtual overrider OVERRIDER is acceptable for base function
+ BASEFN. Issue diagnostic, and return zero, if unacceptable. */
+
+int
+check_final_overrider (overrider, basefn)
+ tree overrider, basefn;
+{
+ tree over_type = TREE_TYPE (overrider);
+ tree base_type = TREE_TYPE (basefn);
+ tree over_return = TREE_TYPE (over_type);
+ tree base_return = TREE_TYPE (base_type);
+ tree over_throw = TYPE_RAISES_EXCEPTIONS (over_type);
+ tree base_throw = TYPE_RAISES_EXCEPTIONS (base_type);
+ int i;
+
+ if (same_type_p (base_return, over_return))
+ /* OK */;
+ else if ((i = covariant_return_p (base_return, over_return)))
+ {
+ if (i == 2)
+ sorry ("adjusting pointers for covariant returns");
+
+ if (pedantic && i == -1)
+ {
+ cp_pedwarn_at ("invalid covariant return type for `virtual %#D'", overrider);
+ cp_pedwarn_at (" overriding `virtual %#D' (must be pointer or reference to class)", basefn);
+ }
+ }
+ else if (IS_AGGR_TYPE_2 (base_return, over_return)
+ && same_or_base_type_p (base_return, over_return))
+ {
+ cp_error_at ("invalid covariant return type for `virtual %#D'", overrider);
+ cp_error_at (" overriding `virtual %#D' (must use pointer or reference)", basefn);
+ return 0;
+ }
+ else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)) == NULL_TREE)
+ {
+ cp_error_at ("conflicting return type specified for `virtual %#D'", overrider);
+ cp_error_at (" overriding `virtual %#D'", basefn);
+ SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),
+ DECL_CLASS_CONTEXT (overrider));
+ return 0;
+ }
+
+ /* Check throw specifier is subset. */
+ /* XXX At the moment, punt on an overriding artificial function. We
+ don't generate its exception specifier, so can't check it properly. */
+ if (! DECL_ARTIFICIAL (overrider)
+ && !comp_except_specs (base_throw, over_throw, 0))
+ {
+ cp_error_at ("looser throw specifier for `virtual %#F'", overrider);
+ cp_error_at (" overriding `virtual %#F'", basefn);
+ return 0;
+ }
+ return 1;
+}
+
/* Given a class type TYPE, and a function decl FNDECL, look for a
virtual function in TYPE's hierarchy which FNDECL could match as a
virtual function. It doesn't matter which one we find.
@@ -1897,7 +1955,6 @@ get_matching_virtual (binfo, fndecl, dtorp)
int dtorp;
{
tree tmp = NULL_TREE;
- int i;
if (TREE_CODE (fndecl) == TEMPLATE_DECL)
/* In [temp.mem] we have:
@@ -1914,9 +1971,7 @@ get_matching_virtual (binfo, fndecl, dtorp)
else
{
tree drettype, dtypes, btypes, instptr_type;
- tree basetype = DECL_CLASS_CONTEXT (fndecl);
tree baselink, best = NULL_TREE;
- tree name = DECL_ASSEMBLER_NAME (fndecl);
tree declarator = DECL_NAME (fndecl);
if (IDENTIFIER_VIRTUAL_P (declarator) == 0)
return NULL_TREE;
@@ -1958,33 +2013,7 @@ get_matching_virtual (binfo, fndecl, dtorp)
== TYPE_QUALS (instptr_type))
&& compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
{
- tree brettype = TREE_TYPE (TREE_TYPE (tmp));
- if (same_type_p (brettype, drettype))
- /* OK */;
- else if ((i = covariant_return_p (brettype, drettype)))
- {
- if (i == 2)
- sorry ("adjusting pointers for covariant returns");
-
- if (pedantic && i == -1)
- {
- cp_pedwarn_at ("invalid covariant return type for `%#D' (must be pointer or reference to class)", fndecl);
- cp_pedwarn_at (" overriding `%#D'", tmp);
- }
- }
- else if (IS_AGGR_TYPE_2 (brettype, drettype)
- && same_or_base_type_p (brettype, drettype))
- {
- error ("invalid covariant return type (must use pointer or reference)");
- cp_error_at (" overriding `%#D'", tmp);
- cp_error_at (" with `%#D'", fndecl);
- }
- else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE)
- {
- cp_error_at ("conflicting return type specified for virtual function `%#D'", fndecl);
- cp_error_at (" overriding definition as `%#D'", tmp);
- SET_IDENTIFIER_ERROR_LOCUS (name, basetype);
- }
+ check_final_overrider (fndecl, tmp);
/* FNDECL overrides this function. We continue to
check all the other functions in order to catch
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index ab71470..f40632a 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1484,25 +1484,9 @@ build_exception_variant (type, raises)
int type_quals = TYPE_QUALS (type);
for (; v; v = TYPE_NEXT_VARIANT (v))
- {
- tree t;
- tree u;
-
- if (TYPE_QUALS (v) != type_quals)
- continue;
-
- for (t = TYPE_RAISES_EXCEPTIONS (v), u = raises;
- t != NULL_TREE && u != NULL_TREE;
- t = TREE_CHAIN (t), u = TREE_CHAIN (u))
- if (((TREE_VALUE (t) != NULL_TREE)
- != (TREE_VALUE (u) != NULL_TREE))
- || !same_type_p (TREE_VALUE (t), TREE_VALUE (u)))
- break;
-
- if (!t && !u)
- /* There's a memory leak here; RAISES is not freed. */
- return v;
- }
+ if (TYPE_QUALS (v) == type_quals
+ && comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (v), 1))
+ return v;
/* Need to build a new variant. */
v = build_type_copy (type);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 582572a..03bc2c0 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -48,6 +48,7 @@ static int comp_target_parms PROTO((tree, tree, int));
static int comp_ptr_ttypes_real PROTO((tree, tree, int));
static int comp_ptr_ttypes_const PROTO((tree, tree));
static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
+static int comp_except_types PROTO((tree, tree, int));
static int comp_array_types PROTO((int (*) (tree, tree, int), tree,
tree, int));
static tree common_base_type PROTO((tree, tree));
@@ -853,13 +854,102 @@ common_type (t1, t2)
}
}
-/* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */
+/* Compare two exception specifier types for exactness or subsetness, if
+ allowed. Returns 0 for mismatch, 1 for same, 2 if B is allowed by A.
+
+ [except.spec] "If a class X ... objects of class X or any class publicly
+ and unambigously derrived from X. Similarly, if a pointer type Y * ...
+ exceptions of type Y * or that are pointers to any type publicly and
+ unambigously derrived from Y. Otherwise a function only allows exceptions
+ that have the same type ..."
+ This does not mention cv qualifiers and is different to what throw
+ [except.throw] and catch [except.catch] will do. They will ignore the
+ top level cv qualifiers, and allow qualifiers in the pointer to class
+ example.
+
+ We implement the letter of the standard. */
+
+static int
+comp_except_types (a, b, exact)
+ tree a, b;
+ int exact;
+{
+ if (same_type_p (a, b))
+ return 1;
+ else if (!exact)
+ {
+ if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
+ return 0;
+
+ if (TREE_CODE (a) == POINTER_TYPE
+ && TREE_CODE (b) == POINTER_TYPE)
+ {
+ a = TREE_TYPE (a);
+ b = TREE_TYPE (b);
+ if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
+ return 0;
+ }
+
+ if (TREE_CODE (a) != RECORD_TYPE
+ || TREE_CODE (b) != RECORD_TYPE)
+ return 0;
+
+ if (ACCESSIBLY_UNIQUELY_DERIVED_P (a, b))
+ return 2;
+ }
+ return 0;
+}
+
+/* Return 1 if TYPE1 and TYPE2 are equivalent exception specifiers.
+ If EXACT is 0, T2 can be a subset of T1 (according to 15.4/7),
+ otherwise it must be exact. Exception lists are unordered, but
+ we've already filtered out duplicates. Most lists will be in order,
+ we should try to make use of that. */
int
-compexcepttypes (t1, t2)
+comp_except_specs (t1, t2, exact)
tree t1, t2;
+ int exact;
{
- return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
+ tree probe;
+ tree base;
+ int length = 0;
+
+ if (t1 == t2)
+ return 1;
+
+ if (t1 == NULL_TREE) /* T1 is ... */
+ return t2 == NULL_TREE || !exact;
+ if (!TREE_VALUE (t1)) /* t1 is EMPTY */
+ return t2 != NULL_TREE && !TREE_VALUE (t2);
+ if (t2 == NULL_TREE) /* T2 is ... */
+ return 0;
+ if (TREE_VALUE(t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
+ return !exact;
+
+ /* Neither set is ... or EMPTY, make sure each part of T2 is in T1.
+ Count how many we find, to determine exactness. For exact matching and
+ ordered T1, T2, this is an O(n) operation, otherwise its worst case is
+ O(nm). */
+ for (base = t1; t2 != NULL_TREE; t2 = TREE_CHAIN (t2))
+ {
+ for (probe = base; probe != NULL_TREE; probe = TREE_CHAIN (probe))
+ {
+ tree a = TREE_VALUE (probe);
+ tree b = TREE_VALUE (t2);
+
+ if (comp_except_types (a, b, exact))
+ {
+ if (probe == base && exact)
+ base = TREE_CHAIN (probe);
+ length++;
+ break;
+ }
+ }
+ if (probe == NULL_TREE)
+ return 0;
+ }
+ return !exact || base == NULL_TREE || length == list_length (t1);
}
/* Compare the array types T1 and T2, using CMP as the type comparison
@@ -1031,7 +1121,8 @@ comptypes (t1, t2, strict)
break;
case METHOD_TYPE:
- if (! compexcepttypes (t1, t2))
+ if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+ TYPE_RAISES_EXCEPTIONS (t2), 1))
return 0;
/* This case is anti-symmetrical!
@@ -1058,7 +1149,8 @@ comptypes (t1, t2, strict)
break;
case FUNCTION_TYPE:
- if (! compexcepttypes (t1, t2))
+ if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+ TYPE_RAISES_EXCEPTIONS (t2), 1))
return 0;
val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
@@ -2175,6 +2267,9 @@ build_component_ref (datum, component, basetype_path, protect)
tree name = component;
if (TREE_CODE (component) == VAR_DECL)
name = DECL_NAME (component);
+ if (TREE_CODE (component) == NAMESPACE_DECL)
+ /* Source is in error, but produce a sensible diagnostic. */
+ name = DECL_NAME (component);
if (basetype_path == NULL_TREE)
basetype_path = TYPE_BINFO (basetype);
field = lookup_field (basetype_path, name,
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index e6a6088..cce836c 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1520,3 +1520,56 @@ check_for_new_type (string, inptree)
&& (pedantic || strcmp (string, "cast") != 0))
pedwarn ("ANSI C++ forbids defining types within %s",string);
}
+
+/* Add new exception specifier SPEC, to the LIST we currently have.
+ If it's already in LIST then do nothing.
+ Moan if it's bad and we're allowed to. COMPLAIN < 0 means we
+ know what we're doing. */
+
+tree
+add_exception_specifier (list, spec, complain)
+ tree list, spec;
+ int complain;
+{
+ int ok;
+ tree core = spec;
+ int is_ptr;
+
+ if (spec == error_mark_node)
+ return list;
+
+ my_friendly_assert (spec && (!list || TREE_VALUE (list)), 19990317);
+
+ /* [except.spec] 1, type in an exception specifier shall not be
+ incomplete, or pointer or ref to incomplete other than pointer
+ to cv void. */
+ is_ptr = TREE_CODE (core) == POINTER_TYPE;
+ if (is_ptr || TREE_CODE (core) == REFERENCE_TYPE)
+ core = TREE_TYPE (core);
+ if (complain < 0)
+ ok = 1;
+ else if (TYPE_MAIN_VARIANT (core) == void_type_node)
+ ok = is_ptr;
+ else if (TREE_CODE (core) == TEMPLATE_TYPE_PARM)
+ ok = 1;
+ else
+ ok = TYPE_SIZE (core) != NULL_TREE;
+
+ if (ok)
+ {
+ tree probe;
+
+ for (probe = list; probe; probe = TREE_CHAIN (probe))
+ if (same_type_p (TREE_VALUE (probe), spec))
+ break;
+ if (!probe)
+ {
+ spec = build_decl_list (NULL_TREE, spec);
+ TREE_CHAIN (spec) = list;
+ list = spec;
+ }
+ }
+ else if (complain)
+ incomplete_type_error (NULL_TREE, core);
+ return list;
+}