Re: [PATCH] add support for GCC's __auto_type

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 24/03/2020 09:57, Luc Van Oostenryck wrote:
> Despite the similarity with typeof, the approach taken here
> is relatively different. A specific symbol type (SYM_TYPEOF)
> is not used, instead a new flag is added to decl_state, another
> one in the declared symbol and a new internal type is used:
> 'autotype_ctype'. It's this new internal type that will be
> resolved to the definitive type at evalution time.
> 
> It seems to be working pretty well, maybe because it
> hasn't been tested well enough.

I haven't tested this (yet) either, but it looks good from what I see
in my email client! ;-) (I deleted my Linux repo many years ago, because
I was always over 90+% used on my disk - and I was only using it as a
'large' repo to test git!).

BTW, I recently upgraded an 32-bit Linux Mint 18.3 to 19.2 using a
'nuke and pave' procedure, rather than the 'upgrade path' provided
by Linux Mint. As part of that, I backed up my $HOME directory from
18.3 and 'restored' it to the new 19.2 (so far, so good). When I built
sparse (before installing llvm), the test-suite failed all of the
'backend/' tests. Given that these tests should have been SKIPed, since
sparse-llvm was disabled, I was a little surprised.

I am sure that you will have guessed by now, that I had an sparse-llvm
executable from 18.3 laying around, ... :-D

I thought about sending a patch to the Makefile to always include the
sparse-llvm program in the clean target (it wouldn't hurt being in the
'rm' invocation twice), but decided that this is unlikely to happen very
often, so ...

BTW, I noticed that we don't install 'sparse-llvm-dis' or 'sparsei' as
part of the 'llvm programs' - should we?

ATB,
Ramsay Jones

> 
> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx>
> ---
>  parse.c                  | 38 +++++++++++++++++++++++++++
>  symbol.c                 | 19 ++++++++++++++
>  symbol.h                 |  2 ++
>  validation/autotype-ko.c | 45 ++++++++++++++++++++++++++++++++
>  validation/autotype.c    | 55 ++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 159 insertions(+)
>  create mode 100644 validation/autotype-ko.c
>  create mode 100644 validation/autotype.c
> 
> diff --git a/parse.c b/parse.c
> index 0e6f66a86037..a29c67c8cf41 100644
> --- a/parse.c
> +++ b/parse.c
> @@ -60,6 +60,7 @@ static declarator_t
>  	thread_specifier, const_qualifier, volatile_qualifier;
>  static declarator_t restrict_qualifier;
>  static declarator_t atomic_qualifier;
> +static declarator_t autotype_specifier;
>  
>  static struct token *parse_if_statement(struct token *token, struct statement *stmt);
>  static struct token *parse_return_statement(struct token *token, struct statement *stmt);
> @@ -213,6 +214,13 @@ static struct symbol_op typeof_op = {
>  	.set = Set_S|Set_T,
>  };
>  
> +static struct symbol_op autotype_op = {
> +	.type = KW_SPECIFIER,
> +	.declarator = autotype_specifier,
> +	.test = Set_Any,
> +	.set = Set_S|Set_T,
> +};
> +
>  static struct symbol_op attribute_op = {
>  	.type = KW_ATTRIBUTE,
>  	.declarator = attribute_specifier,
> @@ -505,6 +513,7 @@ static struct init_keyword {
>  	{ "typeof", 	NS_TYPEDEF, .op = &typeof_op },
>  	{ "__typeof", 	NS_TYPEDEF, .op = &typeof_op },
>  	{ "__typeof__",	NS_TYPEDEF, .op = &typeof_op },
> +	{ "__auto_type",NS_TYPEDEF, .op = &autotype_op },
>  
>  	{ "__attribute",   NS_TYPEDEF, .op = &attribute_op },
>  	{ "__attribute__", NS_TYPEDEF, .op = &attribute_op },
> @@ -1078,6 +1087,13 @@ static struct token *typeof_specifier(struct token *token, struct decl_state *ct
>  	return expect(token, ')', "after typeof");
>  }
>  
> +static struct token *autotype_specifier(struct token *token, struct decl_state *ctx)
> +{
> +	ctx->ctype.base_type = &autotype_ctype;
> +	ctx->autotype = 1;
> +	return token;
> +}
> +
>  static struct token *ignore_attribute(struct token *token, struct symbol *attr, struct decl_state *ctx)
>  {
>  	struct expression *expr = NULL;
> @@ -2985,6 +3001,11 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis
>  			}
>  		}
>  	} else if (base_type && base_type->type == SYM_FN) {
> +		if (base_type->ctype.base_type == &autotype_ctype) {
> +			sparse_error(decl->pos, "'%s()' has __auto_type return type",
> +				show_ident(decl->ident));
> +			base_type->ctype.base_type = &int_ctype;
> +		}
>  		if (base_type->ctype.base_type == &incomplete_ctype) {
>  			warning(decl->pos, "'%s()' has implicit return type",
>  				show_ident(decl->ident));
> @@ -3037,6 +3058,23 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis
>  			}
>  		}
>  
> +		if (ctx.autotype) {
> +			const char *msg = NULL;
> +			if (decl->ctype.base_type != &autotype_ctype)
> +				msg = "on non-identifier";
> +			else if (match_op(token, ','))
> +				msg = "on declaration list";
> +			else if (!decl->initializer)
> +				msg = "without initializer";
> +			else if (decl->initializer->type == EXPR_SYMBOL &&
> +				 decl->initializer->symbol == decl)
> +				msg = "on self-init var";
> +			if (msg) {
> +				sparse_error(decl->pos, "__auto_type %s", msg);
> +				decl->ctype.base_type = &bad_ctype;
> +			}
> +		}
> +
>  		if (!match_op(token, ','))
>  			break;
>  
> diff --git a/symbol.c b/symbol.c
> index ab6e9841696f..c2e6f0b426b3 100644
> --- a/symbol.c
> +++ b/symbol.c
> @@ -192,6 +192,10 @@ static struct symbol * examine_struct_union_type(struct symbol *sym, int advance
>  
>  	fn = advance ? lay_out_struct : lay_out_union;
>  	FOR_EACH_PTR(sym->symbol_list, member) {
> +		if (member->ctype.base_type == &autotype_ctype) {
> +			sparse_error(member->pos, "member '%s' has __auto_type", show_ident(member->ident));
> +			member->ctype.base_type = &incomplete_ctype;
> +		}
>  		fn(member, &info);
>  	} END_FOR_EACH_PTR(member);
>  
> @@ -210,6 +214,19 @@ static struct symbol *examine_base_type(struct symbol *sym)
>  {
>  	struct symbol *base_type;
>  
> +	if (sym->ctype.base_type == &autotype_ctype) {
> +		struct symbol *type = evaluate_expression(sym->initializer);
> +		if (!type)
> +			type = &bad_ctype;
> +		if (is_bitfield_type(type)) {
> +			warning(sym->pos, "__auto_type on bitfield");
> +			if (type->type == SYM_NODE)
> +				type = type->ctype.base_type;
> +			type = type->ctype.base_type;
> +		}
> +		sym->ctype.base_type = type;
> +	}
> +
>  	/* Check the base type */
>  	base_type = examine_symbol_type(sym->ctype.base_type);
>  	if (!base_type || base_type->type == SYM_PTR)
> @@ -734,6 +751,7 @@ struct symbol	bool_ctype, void_ctype, type_ctype,
>  		string_ctype, ptr_ctype, lazy_ptr_ctype,
>  		incomplete_ctype, label_ctype, bad_ctype,
>  		null_ctype;
> +struct symbol	autotype_ctype;
>  struct symbol	int_ptr_ctype, uint_ptr_ctype;
>  struct symbol	long_ptr_ctype, ulong_ptr_ctype;
>  struct symbol	llong_ptr_ctype, ullong_ptr_ctype;
> @@ -792,6 +810,7 @@ static const struct ctype_declare {
>  	{ &void_ctype,         T_BASETYPE },
>  	{ &type_ctype,         T_BASETYPE },
>  	{ &incomplete_ctype,   T_BASETYPE },
> +	{ &autotype_ctype,     T_BASETYPE },
>  	{ &bad_ctype,          T_BASETYPE },
>  
>  	{ &char_ctype,         T__INT(-2, char) },
> diff --git a/symbol.h b/symbol.h
> index 270ae098cacf..c86dfb335e29 100644
> --- a/symbol.h
> +++ b/symbol.h
> @@ -110,6 +110,7 @@ struct decl_state {
>  	unsigned long f_modifiers;		// function attributes
>  	unsigned char prefer_abstract, is_inline, storage_class, is_tls;
>  	unsigned char is_ext_visible;
> +	unsigned char autotype;
>  };
>  
>  struct pseudo;
> @@ -281,6 +282,7 @@ extern struct symbol	bool_ctype, void_ctype, type_ctype,
>  			string_ctype, ptr_ctype, lazy_ptr_ctype,
>  			incomplete_ctype, label_ctype, bad_ctype,
>  			null_ctype;
> +extern struct symbol	autotype_ctype;
>  extern struct symbol	int_ptr_ctype, uint_ptr_ctype;
>  extern struct symbol	long_ptr_ctype, ulong_ptr_ctype;
>  extern struct symbol	llong_ptr_ctype, ullong_ptr_ctype;
> diff --git a/validation/autotype-ko.c b/validation/autotype-ko.c
> new file mode 100644
> index 000000000000..5b6cd708ade7
> --- /dev/null
> +++ b/validation/autotype-ko.c
> @@ -0,0 +1,45 @@
> +__auto_type u;				// KO: no initializer
> +__auto_type r[2] = { 0, 1 };		// KO: not a plain identifier
> +__auto_type foo(void) { }		// KO: not a plain identifier
> +__auto_type v = 0, w = 1;		// KO: in list
> +struct { __auto_type x; } s;		// KO: not valid for struct/union
> +__auto_type self = self;		// KO: self-declared
> +__auto_type undc = this;		// KO: undeclared
> +
> +int i = 1;
> +double f = 1.0;
> +__auto_type i = 2;			// KO: redecl, same type
> +__auto_type f = 2.0f;			// KO: redecl, diff type
> +
> +
> +static int foo(int a, const int *ptr)
> +{
> +	__auto_type i = a;
> +	__auto_type c = *ptr;
> +
> +	c += 1;
> +	return i;
> +}
> +
> +/*
> + * check-name: autotype-ko
> + * check-command: sparse -Wno-decl $file
> + *
> + * check-error-start
> +autotype-ko.c:1:13: error: __auto_type without initializer
> +autotype-ko.c:2:13: error: __auto_type on non-identifier
> +autotype-ko.c:3:13: error: 'foo()' has __auto_type return type
> +autotype-ko.c:4:13: error: __auto_type on declaration list
> +autotype-ko.c:6:13: error: __auto_type on self-init var
> +autotype-ko.c:2:20: error: invalid initializer
> +autotype-ko.c:5:22: error: member 'x' has __auto_type
> +autotype-ko.c:7:20: error: undefined identifier 'this'
> +autotype-ko.c:11:13: error: symbol 'i' has multiple initializers (originally initialized at autotype-ko.c:9)
> +autotype-ko.c:12:13: error: symbol 'f' has multiple initializers (originally initialized at autotype-ko.c:10)
> +autotype-ko.c:12:13: error: symbol 'f' redeclared with different type (different type sizes):
> +autotype-ko.c:12:13:    float [addressable] [toplevel] f
> +autotype-ko.c:10:8: note: previously declared as:
> +autotype-ko.c:10:8:    double [addressable] [toplevel] f
> +autotype-ko.c:20:9: error: assignment to const expression
> + * check-error-end
> + */
> diff --git a/validation/autotype.c b/validation/autotype.c
> new file mode 100644
> index 000000000000..98683c93d2e8
> --- /dev/null
> +++ b/validation/autotype.c
> @@ -0,0 +1,55 @@
> +#ifdef __CHECKER__
> +#define	is_type(X, T)	_Static_assert([typeof(X)] == [T], "")
> +#else
> +#define	is_type(X, T)	_Static_assert(1, "")
> +#endif
> +
> +struct s {
> +	int x;
> +	int bf:3;
> +};
> +
> +extern char ch;
> +extern const int ci;
> +
> +__auto_type i = 0;		is_type(i, int);
> +__auto_type m = 1UL;		is_type(m, unsigned long);
> +__auto_type l = (int)0L;	is_type(l, int);
> +__auto_type c = (char)'\n';	is_type(c, char);
> +__auto_type p = &i;		is_type(p, int *);
> +__auto_type f = 0.0;		is_type(f, double);
> +__auto_type s = (struct s){0};	is_type(s, struct s);
> +__auto_type pci = &ci;		is_type(pci, const int *);
> +
> +// ~~: not valid for bitfield
> +__auto_type b = (struct s){0}.bf; is_type(b, int);
> +
> +static __auto_type si = 0;	is_type(si, int);
> +const  __auto_type ci = 0;	is_type(ci, const int);
> +__auto_type ch = (char) '\n';	is_type(ch, char);
> +
> +static int foo(int a)
> +{
> +	__auto_type i = a;	is_type(i, int);
> +	__auto_type c = ch;	is_type(c, char);
> +	__auto_type ct = ci;	is_type(&ct, const int *);
> +
> +	return ct += i + c;
> +}
> +
> +
> +
> +#define __as __attribute__((address_space(42)))
> +extern int __as aa;
> +
> +__auto_type pa = &aa;		is_type(pa, int __as *);
> +
> +/*
> + * check-name: autotype
> + * check-command: sparse -Wno-decl $file
> + *
> + * check-error-start
> +autotype.c:25:13: warning: __auto_type on bitfield
> +autotype.c:37:16: error: assignment to const expression
> + * check-error-end
> + */
> 



[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux