c23: tag compatibility rules for struct and unions
Implement redeclaration and compatibility rules for structures and unions in C23. gcc/c/: * c-decl.cc (previous_tag): New function. (parser_xref_tag): Find earlier definition. (get_parm_info): Turn off warning for C23. (start_struct): Allow redefinitons. (finish_struct): Diagnose conflicts. * c-tree.h (comptypes_same_p): Add prototype. * c-typeck.cc (comptypes_same_p): New function. (comptypes_internal): Activate comparison of tagged types. (convert_for_assignment): Ignore qualifiers. (digest_init): Add error. (initialized_elementwise_p): Allow compatible types. gcc/testsuite/: * gcc.dg/c23-enum-7.c: Remove warning. * gcc.dg/c23-tag-1.c: New test. * gcc.dg/c23-tag-2.c: New deactivated test. * gcc.dg/c23-tag-3.c: New test. * gcc.dg/c23-tag-4.c: New test. * gcc.dg/c23-tag-5.c: New deactivated test. * gcc.dg/c23-tag-6.c: New test. * gcc.dg/c23-tag-7.c: New test. * gcc.dg/c23-tag-8.c: New test. * gcc.dg/gnu23-tag-1.c: New test. * gcc.dg/gnu23-tag-2.c: New test. * gcc.dg/gnu23-tag-3.c: New test. * gcc.dg/gnu23-tag-4.c: New test. * gcc.dg/pr112488-2.c: Remove warning.
This commit is contained in:
parent
514ea1df44
commit
23fee88f84
17 changed files with 454 additions and 17 deletions
|
@ -2037,6 +2037,28 @@ locate_old_decl (tree decl)
|
||||||
decl, TREE_TYPE (decl));
|
decl, TREE_TYPE (decl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper function. For a tagged type, it finds the declaration
|
||||||
|
for a visible tag declared in the the same scope if such a
|
||||||
|
declaration exists. */
|
||||||
|
static tree
|
||||||
|
previous_tag (tree type)
|
||||||
|
{
|
||||||
|
struct c_binding *b = NULL;
|
||||||
|
tree name = TYPE_NAME (type);
|
||||||
|
|
||||||
|
if (name)
|
||||||
|
b = I_TAG_BINDING (name);
|
||||||
|
|
||||||
|
if (b)
|
||||||
|
b = b->shadowed;
|
||||||
|
|
||||||
|
if (b && B_IN_CURRENT_SCOPE (b))
|
||||||
|
return b->decl;
|
||||||
|
|
||||||
|
return NULL_TREE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL.
|
/* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL.
|
||||||
Returns true if the caller should proceed to merge the two, false
|
Returns true if the caller should proceed to merge the two, false
|
||||||
if OLDDECL should simply be discarded. As a side effect, issues
|
if OLDDECL should simply be discarded. As a side effect, issues
|
||||||
|
@ -8573,11 +8595,14 @@ get_parm_info (bool ellipsis, tree expr)
|
||||||
if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE)
|
if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE)
|
||||||
{
|
{
|
||||||
if (b->id)
|
if (b->id)
|
||||||
/* The %s will be one of 'struct', 'union', or 'enum'. */
|
{
|
||||||
warning_at (b->locus, 0,
|
/* The %s will be one of 'struct', 'union', or 'enum'. */
|
||||||
"%<%s %E%> declared inside parameter list"
|
if (!flag_isoc23)
|
||||||
" will not be visible outside of this definition or"
|
warning_at (b->locus, 0,
|
||||||
" declaration", keyword, b->id);
|
"%<%s %E%> declared inside parameter list"
|
||||||
|
" will not be visible outside of this definition or"
|
||||||
|
" declaration", keyword, b->id);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
/* The %s will be one of 'struct', 'union', or 'enum'. */
|
/* The %s will be one of 'struct', 'union', or 'enum'. */
|
||||||
warning_at (b->locus, 0,
|
warning_at (b->locus, 0,
|
||||||
|
@ -8668,6 +8693,16 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name,
|
||||||
present, only a definition in the current scope is relevant. */
|
present, only a definition in the current scope is relevant. */
|
||||||
|
|
||||||
ref = lookup_tag (code, name, has_enum_type_specifier, &refloc);
|
ref = lookup_tag (code, name, has_enum_type_specifier, &refloc);
|
||||||
|
|
||||||
|
/* If the visble type is still being defined, see if there is
|
||||||
|
an earlier definition (which may be complete). */
|
||||||
|
if (flag_isoc23 && ref && C_TYPE_BEING_DEFINED (ref))
|
||||||
|
{
|
||||||
|
tree vis = previous_tag (ref);
|
||||||
|
if (vis)
|
||||||
|
ref = vis;
|
||||||
|
}
|
||||||
|
|
||||||
/* If this is the right type of tag, return what we found.
|
/* If this is the right type of tag, return what we found.
|
||||||
(This reference will be shadowed by shadow_tag later if appropriate.)
|
(This reference will be shadowed by shadow_tag later if appropriate.)
|
||||||
If this is the wrong type of tag, do not return it. If it was the
|
If this is the wrong type of tag, do not return it. If it was the
|
||||||
|
@ -8782,6 +8817,14 @@ start_struct (location_t loc, enum tree_code code, tree name,
|
||||||
|
|
||||||
if (name != NULL_TREE)
|
if (name != NULL_TREE)
|
||||||
ref = lookup_tag (code, name, true, &refloc);
|
ref = lookup_tag (code, name, true, &refloc);
|
||||||
|
|
||||||
|
/* For C23, even if we already have a completed definition,
|
||||||
|
we do not use it. We will check for consistency later.
|
||||||
|
If we are in a nested redefinition the type is not
|
||||||
|
complete. We will then detect this below. */
|
||||||
|
if (flag_isoc23 && ref && TYPE_SIZE (ref))
|
||||||
|
ref = NULL_TREE;
|
||||||
|
|
||||||
if (ref && TREE_CODE (ref) == code)
|
if (ref && TREE_CODE (ref) == code)
|
||||||
{
|
{
|
||||||
if (TYPE_STUB_DECL (ref))
|
if (TYPE_STUB_DECL (ref))
|
||||||
|
@ -9581,6 +9624,25 @@ 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for consistency with previous definition. */
|
||||||
|
if (flag_isoc23)
|
||||||
|
{
|
||||||
|
tree vistype = previous_tag (t);
|
||||||
|
if (vistype
|
||||||
|
&& TREE_CODE (vistype) == TREE_CODE (t)
|
||||||
|
&& !C_TYPE_BEING_DEFINED (vistype))
|
||||||
|
{
|
||||||
|
TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (t);
|
||||||
|
if (c_type_variably_modified_p (t))
|
||||||
|
error ("redefinition of struct or union %qT with variably "
|
||||||
|
"modified type", t);
|
||||||
|
else if (!comptypes_same_p (t, vistype))
|
||||||
|
error ("redefinition of struct or union %qT", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C_TYPE_BEING_DEFINED (t) = 0;
|
||||||
|
|
||||||
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))
|
||||||
{
|
{
|
||||||
|
|
|
@ -757,6 +757,7 @@ extern tree c_objc_common_truthvalue_conversion (location_t, tree);
|
||||||
extern tree require_complete_type (location_t, tree);
|
extern tree require_complete_type (location_t, tree);
|
||||||
extern bool same_translation_unit_p (const_tree, const_tree);
|
extern bool same_translation_unit_p (const_tree, const_tree);
|
||||||
extern int comptypes (tree, tree);
|
extern int comptypes (tree, tree);
|
||||||
|
extern bool comptypes_same_p (tree, tree);
|
||||||
extern int comptypes_check_different_types (tree, tree, bool *);
|
extern int comptypes_check_different_types (tree, tree, bool *);
|
||||||
extern int comptypes_check_enum_int (tree, tree, bool *);
|
extern int comptypes_check_enum_int (tree, tree, bool *);
|
||||||
extern bool c_mark_addressable (tree, bool = false);
|
extern bool c_mark_addressable (tree, bool = false);
|
||||||
|
|
|
@ -1080,6 +1080,23 @@ comptypes (tree type1, tree type2)
|
||||||
return ret ? (data.warning_needed ? 2 : 1) : 0;
|
return ret ? (data.warning_needed ? 2 : 1) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Like comptypes, but it returns non-zero only for identical
|
||||||
|
types. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
comptypes_same_p (tree type1, tree type2)
|
||||||
|
{
|
||||||
|
struct comptypes_data data = { };
|
||||||
|
bool ret = comptypes_internal (type1, type2, &data);
|
||||||
|
|
||||||
|
if (data.different_types_p)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Like comptypes, but if it returns non-zero because enum and int are
|
/* Like comptypes, but if it returns non-zero because enum and int are
|
||||||
compatible, it sets *ENUM_AND_INT_P to true. */
|
compatible, it sets *ENUM_AND_INT_P to true. */
|
||||||
|
|
||||||
|
@ -1266,11 +1283,11 @@ comptypes_internal (const_tree type1, const_tree type2,
|
||||||
case ENUMERAL_TYPE:
|
case ENUMERAL_TYPE:
|
||||||
case RECORD_TYPE:
|
case RECORD_TYPE:
|
||||||
case UNION_TYPE:
|
case UNION_TYPE:
|
||||||
if (false)
|
|
||||||
{
|
if (!flag_isoc23)
|
||||||
return tagged_types_tu_compatible_p (t1, t2, data);
|
return false;
|
||||||
}
|
|
||||||
return false;
|
return tagged_types_tu_compatible_p (t1, t2, data);
|
||||||
|
|
||||||
case VECTOR_TYPE:
|
case VECTOR_TYPE:
|
||||||
return known_eq (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2))
|
return known_eq (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2))
|
||||||
|
@ -7102,7 +7119,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
|
||||||
/* Aggregates in different TUs might need conversion. */
|
/* Aggregates in different TUs might need conversion. */
|
||||||
if ((codel == RECORD_TYPE || codel == UNION_TYPE)
|
if ((codel == RECORD_TYPE || codel == UNION_TYPE)
|
||||||
&& codel == coder
|
&& codel == coder
|
||||||
&& comptypes (type, rhstype))
|
&& comptypes (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT (rhstype)))
|
||||||
return convert_and_check (expr_loc != UNKNOWN_LOCATION
|
return convert_and_check (expr_loc != UNKNOWN_LOCATION
|
||||||
? expr_loc : location, type, rhs);
|
? expr_loc : location, type, rhs);
|
||||||
|
|
||||||
|
@ -8457,6 +8474,13 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
|
||||||
conversion. */
|
conversion. */
|
||||||
inside_init = convert (type, inside_init);
|
inside_init = convert (type, inside_init);
|
||||||
|
|
||||||
|
if ((code == RECORD_TYPE || code == UNION_TYPE)
|
||||||
|
&& !comptypes (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT (TREE_TYPE (inside_init))))
|
||||||
|
{
|
||||||
|
error_init (init_loc, "invalid initializer");
|
||||||
|
return error_mark_node;
|
||||||
|
}
|
||||||
|
|
||||||
if (require_constant
|
if (require_constant
|
||||||
&& TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
|
&& TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
|
||||||
{
|
{
|
||||||
|
@ -10542,7 +10566,7 @@ initialize_elementwise_p (tree type, tree value)
|
||||||
return !VECTOR_TYPE_P (value_type);
|
return !VECTOR_TYPE_P (value_type);
|
||||||
|
|
||||||
if (AGGREGATE_TYPE_P (type))
|
if (AGGREGATE_TYPE_P (type))
|
||||||
return type != TYPE_MAIN_VARIANT (value_type);
|
return !comptypes (type, TYPE_MAIN_VARIANT (value_type));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,17 +26,15 @@ enum e13 : short x13; /* { dg-error "'enum' underlying type may not be specified
|
||||||
enum e14 : short f14 (); /* { dg-error "'enum' underlying type may not be specified here" } */
|
enum e14 : short f14 (); /* { dg-error "'enum' underlying type may not be specified here" } */
|
||||||
typeof (enum e15 : long) x15; /* { dg-error "'enum' underlying type may not be specified here" } */
|
typeof (enum e15 : long) x15; /* { dg-error "'enum' underlying type may not be specified here" } */
|
||||||
int f16 (enum e16 : char p); /* { dg-error "'enum' underlying type may not be specified here" } */
|
int f16 (enum e16 : char p); /* { dg-error "'enum' underlying type may not be specified here" } */
|
||||||
/* { dg-warning "will not be visible outside of this definition or declaration" "warning" { target *-*-* } .-1 } */
|
|
||||||
int f17 (enum e17 : char); /* { dg-error "'enum' underlying type may not be specified here" } */
|
int f17 (enum e17 : char); /* { dg-error "'enum' underlying type may not be specified here" } */
|
||||||
/* { dg-warning "will not be visible outside of this definition or declaration" "warning" { target *-*-* } .-1 } */
|
|
||||||
struct s18 { enum e18 : int x; }; /* { dg-error "'enum' underlying type may not be specified here" } */
|
struct s18 { enum e18 : int x; }; /* { dg-error "'enum' underlying type may not be specified here" } */
|
||||||
|
|
||||||
/* But those are OK if the enum content is defined. */
|
/* But those are OK if the enum content is defined. */
|
||||||
enum e19 : short { E19 } x19;
|
enum e19 : short { E19 } x19;
|
||||||
enum e20 : long { E20 } f20 ();
|
enum e20 : long { E20 } f20 ();
|
||||||
typeof (enum e21 : long { E21 }) x21;
|
typeof (enum e21 : long { E21 }) x21;
|
||||||
int f22 (enum e22 : long long { E22 } p); /* { dg-warning "will not be visible outside of this definition or declaration" } */
|
int f22 (enum e22 : long long { E22 } p);
|
||||||
int f23 (enum e23 : long long { E23 } p); /* { dg-warning "will not be visible outside of this definition or declaration" } */
|
int f23 (enum e23 : long long { E23 } p);
|
||||||
struct s24 { enum e24 : int { E24 } x; };
|
struct s24 { enum e24 : int { E24 } x; };
|
||||||
|
|
||||||
/* Incompatible kinds of tags in the same scope are errors. */
|
/* Incompatible kinds of tags in the same scope are errors. */
|
||||||
|
|
67
gcc/testsuite/gcc.dg/c23-tag-1.c
Normal file
67
gcc/testsuite/gcc.dg/c23-tag-1.c
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* { dg-do compile }
|
||||||
|
* { dg-options "-std=c23" }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// allowed and forbidden redefinitions of the same struct/union in the same scope
|
||||||
|
|
||||||
|
typedef struct p { int a; } pd_t;
|
||||||
|
typedef struct p { int a; } pd_t;
|
||||||
|
|
||||||
|
typedef struct bar { int x; } X;
|
||||||
|
typedef struct bar { float x; } Y; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
|
||||||
|
void test(void)
|
||||||
|
{
|
||||||
|
struct foo { int x; };
|
||||||
|
struct foo { float x; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
}
|
||||||
|
|
||||||
|
struct aa { int a; };
|
||||||
|
|
||||||
|
void f(void)
|
||||||
|
{
|
||||||
|
typedef struct aa A;
|
||||||
|
struct bb { struct aa a; } x;
|
||||||
|
struct aa { int a; };
|
||||||
|
typedef struct aa A; /* { dg-error "redefinition" } */
|
||||||
|
struct bb { struct aa a; } y; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
(void)x; (void)y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void h(void)
|
||||||
|
{
|
||||||
|
struct a2 { int a; };
|
||||||
|
{
|
||||||
|
typedef struct a2 A;
|
||||||
|
struct b2 { struct a2 a; } x;
|
||||||
|
struct a2 { int a; };
|
||||||
|
typedef struct a2 A; /* { dg-error "redefinition" } */
|
||||||
|
struct b2 { struct a2 a; } y; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
(void)x; (void)y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
union cc { int x; float y; } z;
|
||||||
|
union cc { int x; float y; } z1;
|
||||||
|
union cc { float y; int x; } z2; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
|
||||||
|
void g(void)
|
||||||
|
{
|
||||||
|
struct s { int a; };
|
||||||
|
struct s { int a; } x0;
|
||||||
|
struct p { struct s c; } y1 = { x0 };
|
||||||
|
struct p { struct s { int a; } c; } y = { x0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
struct q { struct { int a; }; };
|
||||||
|
struct q { struct { int a; }; };
|
||||||
|
struct q { int a; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
|
||||||
|
struct r { int a; char b[]; };
|
||||||
|
struct r { int a; char b[]; };
|
||||||
|
struct r { int a; char b[1]; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
|
43
gcc/testsuite/gcc.dg/c23-tag-2.c
Normal file
43
gcc/testsuite/gcc.dg/c23-tag-2.c
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/* { dg-do compile { target { ! "*-*-*" } } }
|
||||||
|
* { dg-options "-std=c23" }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// compatibility of structs in assignment
|
||||||
|
|
||||||
|
typedef struct p { int a; } pd_t;
|
||||||
|
|
||||||
|
void test1(void)
|
||||||
|
{
|
||||||
|
pd_t y0;
|
||||||
|
struct p { int a; } x;
|
||||||
|
y0 = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test2(void)
|
||||||
|
{
|
||||||
|
struct p { int a; } x;
|
||||||
|
struct p y0 = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test3(void)
|
||||||
|
{
|
||||||
|
struct p { int a; } x;
|
||||||
|
pd_t y0 = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct p { int a; } p2_t;
|
||||||
|
|
||||||
|
void test4(void)
|
||||||
|
{
|
||||||
|
p2_t x;
|
||||||
|
pd_t y0 = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test5(void)
|
||||||
|
{
|
||||||
|
struct q { int a; } a;
|
||||||
|
struct q { int a; } b;
|
||||||
|
a = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
16
gcc/testsuite/gcc.dg/c23-tag-3.c
Normal file
16
gcc/testsuite/gcc.dg/c23-tag-3.c
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* { dg-do compile }
|
||||||
|
* { dg-options "-std=c23" }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// conflicting types via linkage
|
||||||
|
|
||||||
|
extern struct foo { int x; } x;
|
||||||
|
extern struct bar { float x; } y;
|
||||||
|
|
||||||
|
void test(void)
|
||||||
|
{
|
||||||
|
extern struct foo { int x; } x;
|
||||||
|
extern struct bar { int x; } y; /* { dg-error "conflicting types" } */
|
||||||
|
}
|
||||||
|
|
26
gcc/testsuite/gcc.dg/c23-tag-4.c
Normal file
26
gcc/testsuite/gcc.dg/c23-tag-4.c
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* { dg-do compile }
|
||||||
|
* { dg-options "-std=c23" }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// conflicting types for anonymous structs / unions
|
||||||
|
|
||||||
|
extern struct { int x; } a;
|
||||||
|
extern struct { int x; } a; /* { dg-error "conflicting types" } */
|
||||||
|
|
||||||
|
extern union { int x; } b;
|
||||||
|
extern union { int x; } b; /* { dg-error "conflicting types" } */
|
||||||
|
|
||||||
|
typedef struct { int x; } u;
|
||||||
|
typedef struct { int x; } v;
|
||||||
|
|
||||||
|
u c;
|
||||||
|
v c; /* { dg-error "conflicting types" } */
|
||||||
|
|
||||||
|
typedef union { int x; } q;
|
||||||
|
typedef union { int x; } r;
|
||||||
|
|
||||||
|
q d;
|
||||||
|
r d; /* { dg-error "conflicting types" } */
|
||||||
|
|
||||||
|
|
33
gcc/testsuite/gcc.dg/c23-tag-5.c
Normal file
33
gcc/testsuite/gcc.dg/c23-tag-5.c
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/* { dg-do run { target { ! "*-*-*" } } }
|
||||||
|
* { dg-options "-std=c23 -fpermissive" }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// nesting and parameters
|
||||||
|
|
||||||
|
#define product_type(T, A, B) \
|
||||||
|
struct product_ ## T { A a ; B b ; }
|
||||||
|
#define sum_type(T, A, B) \
|
||||||
|
struct sum_ ## T { _Bool flag ; union { A a ; B b ; }; }
|
||||||
|
|
||||||
|
float foo1(product_type(iSfd_, int, sum_type(fd, float, double)) x)
|
||||||
|
{
|
||||||
|
return x.b.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test1(void)
|
||||||
|
{
|
||||||
|
product_type(iSfd_, int, sum_type(fd, float, double)) y = { 3, { 1, { .a = 1. } } };
|
||||||
|
product_type(iSfd_, int, sum_type(fd, float, double)) z = y;
|
||||||
|
product_type(iSfd_, int, sum_type(fd, float, double)) *zp = &y;
|
||||||
|
float a = foo1(y);
|
||||||
|
product_type(iSid_, int, sum_type(id, int, double)) *wp = &y; /* { dg-warning "incompatible pointer type" } */
|
||||||
|
float b = foo1(y);
|
||||||
|
product_type(iSid_, int, sum_type(id, int, double)) w = *wp;
|
||||||
|
(void)a; (void)b; (void)z; (void)zp; (void)w; (void)wp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
test1();
|
||||||
|
}
|
||||||
|
|
58
gcc/testsuite/gcc.dg/c23-tag-6.c
Normal file
58
gcc/testsuite/gcc.dg/c23-tag-6.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* { dg-do compile }
|
||||||
|
* { dg-options "-std=c23" }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// (in-)completeness
|
||||||
|
|
||||||
|
struct foo {
|
||||||
|
char x[10];
|
||||||
|
} x;
|
||||||
|
|
||||||
|
// complete, same type
|
||||||
|
|
||||||
|
struct foo {
|
||||||
|
_Static_assert(_Generic(&x, struct foo*: 1, default: 0));
|
||||||
|
char x[_Generic(&x, struct foo*: 10, default: 1)];
|
||||||
|
_Static_assert(_Generic(0, struct foo: 0, default: 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
// incomplete, same type
|
||||||
|
|
||||||
|
struct bar* p;
|
||||||
|
struct bar {
|
||||||
|
_Static_assert(_Generic(p, struct bar*: 1, default: 0));
|
||||||
|
char x[_Generic(p, struct bar*: 10, default: 1)];
|
||||||
|
_Static_assert(_Generic(0, struct bar: 0, default: 1)); /* { dg-error "incomplete type" } */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bar {
|
||||||
|
char x[10];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct h *hp;
|
||||||
|
|
||||||
|
void f(void)
|
||||||
|
{
|
||||||
|
// again incomplete, different type
|
||||||
|
|
||||||
|
struct foo {
|
||||||
|
char x[_Generic(&x, struct foo*: 1, default: 10)];
|
||||||
|
_Static_assert(_Generic(0, struct foo: 0, default: 1)); /* { dg-error "incomplete type" } */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct foo z;
|
||||||
|
_Static_assert(10 == sizeof(z.x), "");
|
||||||
|
|
||||||
|
// still incomplete, different type
|
||||||
|
|
||||||
|
struct h {
|
||||||
|
char x[_Generic(hp, struct h*: 1, default: 10)];
|
||||||
|
_Static_assert(_Generic(0, struct h: 0, default: 1)); /* { dg-error "incomplete type" } */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct h y;
|
||||||
|
_Static_assert(10 == sizeof(y.x), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
12
gcc/testsuite/gcc.dg/c23-tag-7.c
Normal file
12
gcc/testsuite/gcc.dg/c23-tag-7.c
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* { dg-do compile }
|
||||||
|
* { dg-options "-std=c23" }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// recursive declarations
|
||||||
|
|
||||||
|
extern struct bar { struct bar* p; int x; } b;
|
||||||
|
extern struct bar { struct bar* p; int x; } b;
|
||||||
|
|
||||||
|
struct foo { struct foo { struct foo* p; int x; }* p; int x; } a; /* { dg-error "nested" } */
|
||||||
|
|
10
gcc/testsuite/gcc.dg/c23-tag-8.c
Normal file
10
gcc/testsuite/gcc.dg/c23-tag-8.c
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/* { dg-do compile }
|
||||||
|
{ dg-options "-std=c23" } */
|
||||||
|
|
||||||
|
void foo(void)
|
||||||
|
{
|
||||||
|
struct bar { struct bar* next; };
|
||||||
|
struct bar { struct bar* next; };
|
||||||
|
struct bar { struct bar { struct bar* next; }* next; }; /* { dg-error "nested" } */
|
||||||
|
}
|
||||||
|
|
10
gcc/testsuite/gcc.dg/gnu23-tag-1.c
Normal file
10
gcc/testsuite/gcc.dg/gnu23-tag-1.c
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* { dg-do compile }
|
||||||
|
* { dg-options "-std=gnu23" }
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct r { int a; char b[]; };
|
||||||
|
struct r { int a; char b[0]; }; /* allowed GNU extension */
|
||||||
|
struct r { int a; char b[1]; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
|
||||||
|
|
18
gcc/testsuite/gcc.dg/gnu23-tag-2.c
Normal file
18
gcc/testsuite/gcc.dg/gnu23-tag-2.c
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* { dg-do compile }
|
||||||
|
* { dg-options "-std=gnu23" }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// conflicting attributes
|
||||||
|
|
||||||
|
extern struct [[gnu::transaction_safe]] foo { int x; } x;
|
||||||
|
extern struct [[gnu::unused]] foo2 { int x; } x2;
|
||||||
|
extern struct [[gnu::may_alias]] foo3 { int x; } x3;
|
||||||
|
|
||||||
|
void test()
|
||||||
|
{
|
||||||
|
extern struct foo { int x; } x; /* { dg-error "conflicting types" } */
|
||||||
|
extern struct foo2 { int x; } x2;
|
||||||
|
extern struct foo3 { int x; } x3;
|
||||||
|
}
|
||||||
|
|
28
gcc/testsuite/gcc.dg/gnu23-tag-3.c
Normal file
28
gcc/testsuite/gcc.dg/gnu23-tag-3.c
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* { dg-do compile }
|
||||||
|
* { dg-options "-Wno-vla -std=gnu23" }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// arrays in structs
|
||||||
|
|
||||||
|
void foo(int n, int m)
|
||||||
|
{
|
||||||
|
struct f { int b; int a[n]; };
|
||||||
|
struct f { int b; int a[n]; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
struct f { int b; int a[m]; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
struct f { int b; int a[5]; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
struct f { int b; int a[]; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
|
||||||
|
struct g { int a[n]; int b; };
|
||||||
|
struct g { int a[n]; int b; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
struct g { int a[m]; int b; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
struct g { int a[4]; int b; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
|
||||||
|
struct h { int (*a)[n]; int b; };
|
||||||
|
struct h { int (*a)[n]; int b; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
struct h { int (*a)[m]; int b; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
struct h { int (*a)[4]; int b; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
struct h { int (*a)[]; int b; }; /* { dg-error "redefinition of struct or union" } */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
31
gcc/testsuite/gcc.dg/gnu23-tag-4.c
Normal file
31
gcc/testsuite/gcc.dg/gnu23-tag-4.c
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/* { dg-do compile }
|
||||||
|
* { dg-options "-std=gnu23" } */
|
||||||
|
|
||||||
|
// structs with variably modified types
|
||||||
|
|
||||||
|
void bar(int n, int m)
|
||||||
|
{
|
||||||
|
struct f { int b; int a[n]; } *x;
|
||||||
|
{ struct f { int b; int a[n]; } *x2 = x; }
|
||||||
|
{ struct f { int b; int a[m]; } *x2 = x; }
|
||||||
|
{ struct f { int b; int a[5]; } *x2 = x; }
|
||||||
|
{ struct f { int b; int a[0]; } *x2 = x; }
|
||||||
|
{ struct f { int b; int a[]; } *x2 = x; }
|
||||||
|
|
||||||
|
struct g { int a[n]; int b; } *y;
|
||||||
|
{ struct g { int a[n]; int b; } *y2 = y; }
|
||||||
|
{ struct g { int a[m]; int b; } *y2 = y; }
|
||||||
|
{ struct g { int a[4]; int b; } *y2 = y; }
|
||||||
|
|
||||||
|
struct h { int b; int a[5]; } *w;
|
||||||
|
{ struct h { int b; int a[5]; } *w2 = w; }
|
||||||
|
{ struct h { int b; int a[n]; } *w2 = w; }
|
||||||
|
{ struct h { int b; int a[m]; } *w2 = w; }
|
||||||
|
|
||||||
|
struct i { int b; int (*a)(int c[n]); } *u;
|
||||||
|
{ struct i { int b; int (*a)(int c[4]); } *u2 = u; }
|
||||||
|
{ struct i { int b; int (*a)(int c[]); } *u2 = u; }
|
||||||
|
{ struct i { int b; int (*a)(int c[*]); } *u2 = u; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
extern void abort(void);
|
extern void abort(void);
|
||||||
|
|
||||||
int test(int *n, struct T { char a[*n], b[*n]; }*) { /* { dg-warning "declared inside parameter list" } */
|
int test(int *n, struct T { char a[*n], b[*n]; }*) {
|
||||||
return sizeof(struct T) - sizeof(struct T);
|
return sizeof(struct T) - sizeof(struct T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue