aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--parse.c38
-rw-r--r--symbol.c19
-rw-r--r--symbol.h2
-rw-r--r--validation/autotype-ko.c45
-rw-r--r--validation/autotype.c55
5 files changed, 159 insertions, 0 deletions
diff --git a/parse.c b/parse.c
index 0e6f66a8..a29c67c8 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 ab6e9841..c2e6f0b4 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 270ae098..c86dfb33 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 00000000..5b6cd708
--- /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 00000000..98683c93
--- /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
+ */