Commit 046c5890 by Jakub Jelinek

c: Handle C_TYPE_INCOMPLETE_VARS even for ENUMERAL_TYPEs [PR94172]

The following testcases ICE, because they contain extern variable
declarations with incomplete enum types that is later completed and after
that those variables are accessed.  The ICEs are because the vars then may have
incorrect DECL_MODE etc., e.g. in the first case the var has SImode
DECL_MODE (the guessed mode for the enum), but the enum then actually has
DImode because its enumerators don't fit into unsigned int.

The following patch fixes it by using C_TYPE_INCOMPLETE_VARS not just on
incomplete struct/union types, but also incomplete enum types.
TYPE_VFIELD can't be used as it is TYPE_MIN_VALUE on ENUMERAL_TYPE,
thankfully TYPE_LANG_SLOT_1 has been used in the C FE only on
FUNCTION_TYPEs.

2020-03-17  Jakub Jelinek  <jakub@redhat.com>

	PR c/94172
	* c-tree.h (C_TYPE_INCOMPLETE_VARS): Define to TYPE_LANG_SLOT_1
	instead of TYPE_VFIELD, and support it on {RECORD,UNION,ENUMERAL}_TYPE.
	(TYPE_ACTUAL_ARG_TYPES): Check that it is only used on FUNCTION_TYPEs.
	* c-decl.c (pushdecl): Push C_TYPE_INCOMPLETE_VARS also to
	ENUMERAL_TYPEs.
	(finish_incomplete_vars): New function, moved from finish_struct.  Use
	relayout_decl instead of layout_decl.
	(finish_struct): Remove obsolete comment about C_TYPE_INCOMPLETE_VARS
	being TYPE_VFIELD.  Use finish_incomplete_vars.
	(finish_enum): Clear C_TYPE_INCOMPLETE_VARS.  Call
	finish_incomplete_vars.
	* c-typeck.c (c_build_qualified_type): Clear C_TYPE_INCOMPLETE_VARS
	also on ENUMERAL_TYPEs.

	* gcc.dg/pr94172-1.c: New test.
	* gcc.dg/pr94172-2.c: New test.
parent cd0b7124
2020-03-17 Jakub Jelinek <jakub@redhat.com>
PR c/94172
* c-tree.h (C_TYPE_INCOMPLETE_VARS): Define to TYPE_LANG_SLOT_1
instead of TYPE_VFIELD, and support it on {RECORD,UNION,ENUMERAL}_TYPE.
(TYPE_ACTUAL_ARG_TYPES): Check that it is only used on FUNCTION_TYPEs.
* c-decl.c (pushdecl): Push C_TYPE_INCOMPLETE_VARS also to
ENUMERAL_TYPEs.
(finish_incomplete_vars): New function, moved from finish_struct. Use
relayout_decl instead of layout_decl.
(finish_struct): Remove obsolete comment about C_TYPE_INCOMPLETE_VARS
being TYPE_VFIELD. Use finish_incomplete_vars.
(finish_enum): Clear C_TYPE_INCOMPLETE_VARS. Call
finish_incomplete_vars.
* c-typeck.c (c_build_qualified_type): Clear C_TYPE_INCOMPLETE_VARS
also on ENUMERAL_TYPEs.
2020-03-16 Jakub Jelinek <jakub@redhat.com> 2020-03-16 Jakub Jelinek <jakub@redhat.com>
PR c/94179 PR c/94179
......
...@@ -3312,7 +3312,8 @@ pushdecl (tree x) ...@@ -3312,7 +3312,8 @@ pushdecl (tree x)
element = TREE_TYPE (element); element = TREE_TYPE (element);
element = TYPE_MAIN_VARIANT (element); element = TYPE_MAIN_VARIANT (element);
if (RECORD_OR_UNION_TYPE_P (element) if ((RECORD_OR_UNION_TYPE_P (element)
|| TREE_CODE (element) == ENUMERAL_TYPE)
&& (TREE_CODE (x) != TYPE_DECL && (TREE_CODE (x) != TYPE_DECL
|| TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE) || TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE)
&& !COMPLETE_TYPE_P (element)) && !COMPLETE_TYPE_P (element))
...@@ -8354,6 +8355,26 @@ field_decl_cmp (const void *x_p, const void *y_p) ...@@ -8354,6 +8355,26 @@ field_decl_cmp (const void *x_p, const void *y_p)
return 1; return 1;
} }
/* If this structure or union completes the type of any previous
variable declaration, lay it out and output its rtl. */
static void
finish_incomplete_vars (tree incomplete_vars, bool toplevel)
{
for (tree x = incomplete_vars; x; x = TREE_CHAIN (x))
{
tree decl = TREE_VALUE (x);
if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
layout_array_type (TREE_TYPE (decl));
if (TREE_CODE (decl) != TYPE_DECL)
{
relayout_decl (decl);
if (c_dialect_objc ())
objc_check_decl (decl);
rest_of_decl_compilation (decl, toplevel, 0);
}
}
}
/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T. /* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
LOC is the location of the RECORD_TYPE or UNION_TYPE's definition. LOC is the location of the RECORD_TYPE or UNION_TYPE's definition.
FIELDLIST is a chain of FIELD_DECL nodes for the fields. FIELDLIST is a chain of FIELD_DECL nodes for the fields.
...@@ -8612,13 +8633,6 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, ...@@ -8612,13 +8633,6 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
warning_at (loc, 0, "union cannot be made transparent"); warning_at (loc, 0, "union cannot be made transparent");
} }
/* Note: C_TYPE_INCOMPLETE_VARS overloads TYPE_VFIELD which is used
in dwarf2out via rest_of_decl_compilation below and means
something totally different. Since we will be clearing
C_TYPE_INCOMPLETE_VARS shortly after we iterate through them,
clear it ahead of time and avoid problems in dwarf2out. Ideally,
C_TYPE_INCOMPLETE_VARS should use some language specific
node. */
tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)); tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t));
for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
{ {
...@@ -8639,21 +8653,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, ...@@ -8639,21 +8653,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
/* Finish debugging output for this type. */ /* Finish debugging output for this type. */
rest_of_type_compilation (t, toplevel); rest_of_type_compilation (t, toplevel);
/* If this structure or union completes the type of any previous finish_incomplete_vars (incomplete_vars, toplevel);
variable declaration, lay it out and output its rtl. */
for (x = incomplete_vars; x; x = TREE_CHAIN (x))
{
tree decl = TREE_VALUE (x);
if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
layout_array_type (TREE_TYPE (decl));
if (TREE_CODE (decl) != TYPE_DECL)
{
layout_decl (decl, 0);
if (c_dialect_objc ())
objc_check_decl (decl);
rest_of_decl_compilation (decl, toplevel, 0);
}
}
/* If we're inside a function proper, i.e. not file-scope and not still /* If we're inside a function proper, i.e. not file-scope and not still
parsing parameters, then arrange for the size of a variable sized type parsing parameters, then arrange for the size of a variable sized type
...@@ -8932,8 +8932,10 @@ finish_enum (tree enumtype, tree values, tree attributes) ...@@ -8932,8 +8932,10 @@ finish_enum (tree enumtype, tree values, tree attributes)
TYPE_LANG_SPECIFIC (enumtype) = lt; TYPE_LANG_SPECIFIC (enumtype) = lt;
/* Fix up all variant types of this enum type. */ /* Fix up all variant types of this enum type. */
tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (enumtype));
for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem)) for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem))
{ {
C_TYPE_INCOMPLETE_VARS (tem) = NULL_TREE;
if (tem == enumtype) if (tem == enumtype)
continue; continue;
TYPE_VALUES (tem) = TYPE_VALUES (enumtype); TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
...@@ -8952,6 +8954,8 @@ finish_enum (tree enumtype, tree values, tree attributes) ...@@ -8952,6 +8954,8 @@ finish_enum (tree enumtype, tree values, tree attributes)
/* Finish debugging output for this type. */ /* Finish debugging output for this type. */
rest_of_type_compilation (enumtype, toplevel); rest_of_type_compilation (enumtype, toplevel);
finish_incomplete_vars (incomplete_vars, toplevel);
/* If this enum is defined inside a struct, add it to /* If this enum is defined inside a struct, add it to
struct_types. */ struct_types. */
if (warn_cxx_compat if (warn_cxx_compat
......
...@@ -38,9 +38,12 @@ along with GCC; see the file COPYING3. If not see ...@@ -38,9 +38,12 @@ along with GCC; see the file COPYING3. If not see
nonzero if the definition of the type has already started. */ nonzero if the definition of the type has already started. */
#define C_TYPE_BEING_DEFINED(TYPE) TYPE_LANG_FLAG_0 (TYPE) #define C_TYPE_BEING_DEFINED(TYPE) TYPE_LANG_FLAG_0 (TYPE)
/* In an incomplete RECORD_TYPE or UNION_TYPE, a list of variable /* In an incomplete RECORD_TYPE, UNION_TYPE or ENUMERAL_TYPE, a list of
declarations whose type would be completed by completing that type. */ variable declarations whose type would be completed by completing
#define C_TYPE_INCOMPLETE_VARS(TYPE) TYPE_VFIELD (TYPE) that type. */
#define C_TYPE_INCOMPLETE_VARS(TYPE) \
TYPE_LANG_SLOT_1 (TREE_CHECK4 (TYPE, RECORD_TYPE, UNION_TYPE, \
QUAL_UNION_TYPE, ENUMERAL_TYPE))
/* In an IDENTIFIER_NODE, nonzero if this identifier is actually a /* In an IDENTIFIER_NODE, nonzero if this identifier is actually a
keyword. C_RID_CODE (node) is then the RID_* value of the keyword. */ keyword. C_RID_CODE (node) is then the RID_* value of the keyword. */
...@@ -108,7 +111,8 @@ along with GCC; see the file COPYING3. If not see ...@@ -108,7 +111,8 @@ along with GCC; see the file COPYING3. If not see
/* For FUNCTION_TYPE, a hidden list of types of arguments. The same as /* For FUNCTION_TYPE, a hidden list of types of arguments. The same as
TYPE_ARG_TYPES for functions with prototypes, but created for functions TYPE_ARG_TYPES for functions with prototypes, but created for functions
without prototypes. */ without prototypes. */
#define TYPE_ACTUAL_ARG_TYPES(NODE) TYPE_LANG_SLOT_1 (NODE) #define TYPE_ACTUAL_ARG_TYPES(NODE) \
TYPE_LANG_SLOT_1 (FUNCTION_TYPE_CHECK (NODE))
/* For a CONSTRUCTOR, whether some initializer contains a /* For a CONSTRUCTOR, whether some initializer contains a
subexpression meaning it is not a constant expression. */ subexpression meaning it is not a constant expression. */
......
...@@ -15207,7 +15207,8 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type, ...@@ -15207,7 +15207,8 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
: build_qualified_type (type, type_quals)); : build_qualified_type (type, type_quals));
/* A variant type does not inherit the list of incomplete vars from the /* A variant type does not inherit the list of incomplete vars from the
type main variant. */ type main variant. */
if (RECORD_OR_UNION_TYPE_P (var_type) if ((RECORD_OR_UNION_TYPE_P (var_type)
|| TREE_CODE (var_type) == ENUMERAL_TYPE)
&& TYPE_MAIN_VARIANT (var_type) != var_type) && TYPE_MAIN_VARIANT (var_type) != var_type)
C_TYPE_INCOMPLETE_VARS (var_type) = 0; C_TYPE_INCOMPLETE_VARS (var_type) = 0;
return var_type; return var_type;
......
2020-03-17 Jakub Jelinek <jakub@redhat.com> 2020-03-17 Jakub Jelinek <jakub@redhat.com>
PR c/94172
* gcc.dg/pr94172-1.c: New test.
* gcc.dg/pr94172-2.c: New test.
PR c++/90995 PR c++/90995
* g++.dg/cpp0x/enum40.C: New test. * g++.dg/cpp0x/enum40.C: New test.
......
/* PR c/94172 */
/* { dg-do compile } */
/* { dg-options "-O2" } */
extern enum E e;
enum E { l = 0x100000000ULL };
unsigned long long
foo (void)
{
return e;
}
/* PR c/94172 */
/* { dg-do compile } */
/* { dg-options "-Os -g -fshort-enums" } */
extern enum E e;
extern void bar (int a);
enum E { F };
void
foo (int a)
{
int l = e;
if (a)
{
__asm volatile ("nop");
l = 0;
}
bar (l);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment