mirror of
git://repo.or.cz/tinycc.git
synced 2026-11-04 21:26:36 +08:00
tccgen: Minimal implementation of restrict
TCC currently recognises the restrict keyword but discards it. Give the qualifier its own type bit and diagnose misuse that violates constraints in ISO C. There is (obviously) no new aliasing analysis.
This commit is contained in:
parent
c9829912d7
commit
f4d81ced3e
@ -669,7 +669,9 @@ is the same as writing
|
||||
emitted at the end of the compilation unit only if used. The behavior
|
||||
of @code{extern inline} depends on @option{-fgnu89-inline} (@pxref{Invoke}).
|
||||
|
||||
@item @code{restrict} keyword is ignored.
|
||||
@item @code{restrict} type qualifier. TCC retains the qualifier and checks
|
||||
that it is applied only to pointers to object or incomplete types. It is not
|
||||
currently used for alias analysis or optimization.
|
||||
@end itemize
|
||||
|
||||
@section ISO C11 extensions
|
||||
|
||||
19
tcc.h
19
tcc.h
@ -1063,17 +1063,18 @@ struct filespec {
|
||||
#define VT_BITFIELD 0x0080 /* bitfield modifier */
|
||||
#define VT_CONSTANT 0x0100 /* const modifier */
|
||||
#define VT_VOLATILE 0x0200 /* volatile modifier */
|
||||
#define VT_QUAL (VT_CONSTANT | VT_VOLATILE)
|
||||
#define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */
|
||||
#define VT_LONG 0x0800 /* long type (also has VT_INT rsp. VT_LLONG) */
|
||||
#define VT_RESTRICT 0x0400 /* restrict modifier */
|
||||
#define VT_QUAL (VT_CONSTANT | VT_VOLATILE | VT_RESTRICT)
|
||||
#define VT_VLA 0x0800 /* VLA type (also has VT_PTR and VT_ARRAY) */
|
||||
#define VT_LONG 0x1000 /* long type (also has VT_INT rsp. VT_LLONG) */
|
||||
|
||||
/* storage */
|
||||
#define VT_EXTERN 0x00001000 /* extern definition */
|
||||
#define VT_STATIC 0x00002000 /* static variable */
|
||||
#define VT_TYPEDEF 0x00004000 /* typedef definition */
|
||||
#define VT_INLINE 0x00008000 /* inline definition */
|
||||
#define VT_TLS 0x00010000 /* thread-local storage */
|
||||
/* currently unused: 0x000[248]0000 */
|
||||
#define VT_EXTERN 0x00002000 /* extern definition */
|
||||
#define VT_STATIC 0x00004000 /* static variable */
|
||||
#define VT_TYPEDEF 0x00008000 /* typedef definition */
|
||||
#define VT_INLINE 0x00010000 /* inline definition */
|
||||
#define VT_TLS 0x00020000 /* thread-local storage */
|
||||
/* currently unused: 0x000[48]0000 */
|
||||
|
||||
#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
|
||||
#define VT_STRUCT_MASK (((1U << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
|
||||
|
||||
32
tccgen.c
32
tccgen.c
@ -136,6 +136,7 @@ static void block(int flags);
|
||||
static void gen_cast(CType *type);
|
||||
static void gen_cast_s(int t);
|
||||
static inline CType *pointed_type(CType *type);
|
||||
static void check_restrict_type(CType *type);
|
||||
static int type_qualifiers(CType *type);
|
||||
static void parse_btype_qualify(CType *type, int qualifiers);
|
||||
static int is_compatible_types(CType *type1, CType *type2);
|
||||
@ -2677,6 +2678,8 @@ static void type_to_str(char *buf, int buf_size,
|
||||
if (t & VT_INLINE)
|
||||
pstrcat(buf, buf_size, "inline ");
|
||||
if (bt != VT_PTR) {
|
||||
if (t & VT_RESTRICT)
|
||||
pstrcat(buf, buf_size, "restrict ");
|
||||
if (t & VT_VOLATILE)
|
||||
pstrcat(buf, buf_size, "volatile ");
|
||||
if (t & VT_CONSTANT)
|
||||
@ -2775,6 +2778,8 @@ static void type_to_str(char *buf, int buf_size,
|
||||
goto no_var;
|
||||
}
|
||||
pstrcpy(buf1, sizeof(buf1), "*");
|
||||
if (t & VT_RESTRICT)
|
||||
pstrcat(buf1, sizeof(buf1), "restrict ");
|
||||
if (t & VT_CONSTANT)
|
||||
pstrcat(buf1, buf_size, "const ");
|
||||
if (t & VT_VOLATILE)
|
||||
@ -3568,6 +3573,18 @@ static inline CType *pointed_type(CType *type)
|
||||
return &type->ref->type;
|
||||
}
|
||||
|
||||
static void check_restrict_type(CType *type)
|
||||
{
|
||||
while ((type->t & VT_BTYPE) == VT_PTR) {
|
||||
if ((type->t & VT_RESTRICT)
|
||||
&& (pointed_type(type)->t & VT_BTYPE) == VT_FUNC)
|
||||
tcc_error("restrict-qualified type must be a pointer to object or incomplete type");
|
||||
type = pointed_type(type);
|
||||
}
|
||||
if (type->t & VT_RESTRICT)
|
||||
tcc_error("restrict-qualified type must be a pointer to object or incomplete type");
|
||||
}
|
||||
|
||||
/* Array qualifiers are represented on the element type. */
|
||||
static int type_qualifiers(CType *type)
|
||||
{
|
||||
@ -4724,6 +4741,8 @@ static void parse_btype_qualify(CType *type, int qualifiers)
|
||||
type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c);
|
||||
type = &type->ref->type;
|
||||
}
|
||||
if (qualifiers & VT_RESTRICT)
|
||||
check_restrict_type(type);
|
||||
type->t |= qualifiers;
|
||||
}
|
||||
|
||||
@ -4882,11 +4901,14 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label)
|
||||
next();
|
||||
typespec_found = 1;
|
||||
break;
|
||||
case TOK_REGISTER:
|
||||
case TOK_AUTO:
|
||||
case TOK_RESTRICT1:
|
||||
case TOK_RESTRICT2:
|
||||
case TOK_RESTRICT3:
|
||||
t |= VT_RESTRICT;
|
||||
next();
|
||||
break;
|
||||
case TOK_REGISTER:
|
||||
case TOK_AUTO:
|
||||
next();
|
||||
break;
|
||||
case TOK_UNSIGNED:
|
||||
@ -4998,6 +5020,7 @@ the_end:
|
||||
t = (t & ~(VT_BTYPE|VT_LONG)) | (VT_DOUBLE|VT_LONG);
|
||||
#endif
|
||||
type->t = t;
|
||||
check_restrict_type(type);
|
||||
return type_found;
|
||||
}
|
||||
|
||||
@ -5162,6 +5185,9 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
next();
|
||||
continue;
|
||||
case TOK_RESTRICT1: case TOK_RESTRICT2: case TOK_RESTRICT3:
|
||||
array_qualifiers |= VT_RESTRICT;
|
||||
next();
|
||||
continue;
|
||||
case TOK_STATIC:
|
||||
case '*':
|
||||
next();
|
||||
@ -5297,6 +5323,7 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td)
|
||||
case TOK_RESTRICT1:
|
||||
case TOK_RESTRICT2:
|
||||
case TOK_RESTRICT3:
|
||||
qualifiers |= VT_RESTRICT;
|
||||
goto redo;
|
||||
/* XXX: clarify attribute handling */
|
||||
case TOK_ATTRIBUTE1:
|
||||
@ -5336,6 +5363,7 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td)
|
||||
}
|
||||
post_type(post, ad, post != ret ? 0 : storage,
|
||||
td & ~(TYPE_DIRECT|TYPE_ABSTRACT));
|
||||
check_restrict_type(type);
|
||||
parse_attribute(ad);
|
||||
type->t |= storage;
|
||||
return ret;
|
||||
|
||||
@ -20,6 +20,26 @@ void fooc(int x[volatile 5])
|
||||
}
|
||||
void foovm(int x[const *]);
|
||||
void foovm(int * const x);
|
||||
|
||||
typedef int *pointer_array[2];
|
||||
typedef int *restrict restricted_pointer;
|
||||
typedef restrict pointer_array restricted_pointer_array;
|
||||
|
||||
_Static_assert(!__builtin_types_compatible_p(int **,
|
||||
restricted_pointer *),
|
||||
"nested restrict qualifier is retained");
|
||||
_Static_assert(__builtin_types_compatible_p(restricted_pointer_array,
|
||||
restricted_pointer[2]),
|
||||
"restrict can qualify an array of pointer types");
|
||||
|
||||
restricted_pointer *restricted_pp;
|
||||
int **unrestricted_pp;
|
||||
|
||||
_Static_assert(__builtin_types_compatible_p(
|
||||
__typeof__(1 ? restricted_pp : unrestricted_pp),
|
||||
restricted_pointer *),
|
||||
"conditional expression combines restrict qualifiers");
|
||||
|
||||
#ifdef INVALID
|
||||
void wrongc(int x[3][const 4]);
|
||||
void wrongvm(int x[static *]);
|
||||
|
||||
@ -679,4 +679,24 @@ void test(void)
|
||||
(1 ? vap : cap)[0][0][0] = 4;
|
||||
}
|
||||
|
||||
#elif defined test_restrict_scalar
|
||||
|
||||
restrict int object;
|
||||
|
||||
#elif defined test_restrict_function_pointer
|
||||
|
||||
int (*restrict function_pointer)(void);
|
||||
|
||||
#elif defined test_discarded_restrict
|
||||
|
||||
typedef int *restrict restricted_pointer;
|
||||
|
||||
restricted_pointer *source;
|
||||
int **destination;
|
||||
|
||||
void test(void)
|
||||
{
|
||||
destination = source;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -296,3 +296,12 @@ bar 15 12 34
|
||||
60_errors_and_warnings.c:677: warning: assignment of read-only location
|
||||
60_errors_and_warnings.c:678: warning: assignment of read-only location
|
||||
60_errors_and_warnings.c:679: warning: assignment of read-only location
|
||||
|
||||
[test_restrict_scalar]
|
||||
60_errors_and_warnings.c:684: error: restrict-qualified type must be a pointer to object or incomplete type
|
||||
|
||||
[test_restrict_function_pointer]
|
||||
60_errors_and_warnings.c:688: error: restrict-qualified type must be a pointer to object or incomplete type
|
||||
|
||||
[test_discarded_restrict]
|
||||
60_errors_and_warnings.c:699: warning: assignment discards qualifiers from pointer target type
|
||||
|
||||
Loading…
Reference in New Issue
Block a user