- implemented non-constant initializers
authorMatthias Braun <matze@braunis.de>
Fri, 15 Feb 2008 20:17:01 +0000 (20:17 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 15 Feb 2008 20:17:01 +0000 (20:17 +0000)
- differentiate between specified and effective storage_class
- improve constness checks (esp. for constant initializers)

=> make selfcheck works

[r18870]

TODO
ast.c
ast.h
ast2firm.c
ast_t.h
parser.c
parsetest/compoundlit3.c [new file with mode: 0644]
parsetest/cp_error021.c [new file with mode: 0644]
parsetest/init7.c [new file with mode: 0644]
parsetest/shouldfail/init8.c [new file with mode: 0644]

diff --git a/TODO b/TODO
index 51176d4..510490c 100644 (file)
--- a/TODO
+++ b/TODO
@@ -2,6 +2,7 @@ Refactoring:
 - create an empty_statement_t and use that instead of a NULL pointer in places
   like if, loop bodys, statements after labels
 - eliminate target_architecture.h and replace with stuff in lang_features.h
+- redo storage classes: so we can separate real from declared storage class
 
 Lexer:
 - Add preprocessor code
@@ -10,6 +11,7 @@ Lexer:
   compressed table) and only storing pointers to it on the AST.
 
 Parser:
+- disallow storage class specifiers in sturct/union members
 - the expect macros abort functions directly. This leads to some functions
   not resetting the current context properly (parse_for); expect in expressions
   suddenly return NULL which triggers asserts
diff --git a/ast.c b/ast.c
index 0501211..a1f1073 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -594,8 +594,7 @@ static void print_select(const select_expression_t *expression)
 {
        unsigned prec = get_expression_precedence(expression->base.kind);
        print_expression_prec(expression->compound, prec);
-       if(expression->compound->base.type == NULL ||
-                       expression->compound->base.type->kind == TYPE_POINTER) {
+       if(is_type_pointer(expression->compound->base.type)) {
                fputs("->", out);
        } else {
                fputc('.', out);
@@ -1111,9 +1110,9 @@ void print_statement(const statement_t *statement)
  *
  * @param storage_class   the storage class
  */
-static void print_storage_class(unsigned storage_class)
+static void print_storage_class(storage_class_tag_t storage_class)
 {
-       switch((storage_class_tag_t) storage_class) {
+       switch(storage_class) {
        case STORAGE_CLASS_ENUM_ENTRY:
        case STORAGE_CLASS_NONE:
                break;
@@ -1183,7 +1182,7 @@ void print_initializer(const initializer_t *initializer)
  */
 static void print_normal_declaration(const declaration_t *declaration)
 {
-       print_storage_class(declaration->storage_class);
+       print_storage_class((storage_class_tag_t) declaration->declared_storage_class);
        if(declaration->is_inline) {
                if (declaration->modifiers & DM_FORCEINLINE)
                        fputs("__forceinline ", out);
@@ -1277,7 +1276,7 @@ void print_ast(const translation_unit_t *unit)
        }
 }
 
-static bool is_initializer_const(const initializer_t *initializer)
+bool is_constant_initializer(const initializer_t *initializer)
 {
        switch(initializer->kind) {
        case INITIALIZER_STRING:
@@ -1291,7 +1290,7 @@ static bool is_initializer_const(const initializer_t *initializer)
        case INITIALIZER_LIST: {
                for(size_t i = 0; i < initializer->list.len; ++i) {
                        initializer_t *sub_initializer = initializer->list.initializers[i];
-                       if(!is_initializer_const(sub_initializer))
+                       if(!is_constant_initializer(sub_initializer))
                                return false;
                }
                return true;
@@ -1300,12 +1299,83 @@ static bool is_initializer_const(const initializer_t *initializer)
        panic("invalid initializer kind found");
 }
 
-/**
- * Returns true if a given expression is a compile time
- * constant.
- *
- * @param expression  the expression to check
- */
+static bool is_object_with_constant_address(const expression_t *expression)
+{
+       switch(expression->kind) {
+       case EXPR_UNARY_DEREFERENCE:
+               return is_address_constant(expression->unary.value);
+
+       case EXPR_SELECT: {
+               if(is_type_pointer(expression->select.compound->base.type)) {
+                       /* it's a -> */
+                       return is_address_constant(expression->select.compound);
+               } else {
+                       return is_object_with_constant_address(expression->select.compound);
+               }
+       }
+
+       case EXPR_ARRAY_ACCESS:
+               return is_constant_expression(expression->array_access.index)
+                       && is_address_constant(expression->array_access.array_ref);
+
+       case EXPR_REFERENCE: {
+               declaration_t *declaration = expression->reference.declaration;
+               switch((storage_class_tag_t) declaration->storage_class) {
+               case STORAGE_CLASS_NONE:
+               case STORAGE_CLASS_EXTERN:
+               case STORAGE_CLASS_STATIC:
+                       return true;
+               default:
+                       return false;
+               }
+       }
+
+       default:
+               return false;
+       }
+}
+
+bool is_address_constant(const expression_t *expression)
+{
+       switch(expression->kind) {
+       case EXPR_UNARY_TAKE_ADDRESS:
+               return is_object_with_constant_address(expression->unary.value);
+
+       case EXPR_UNARY_CAST:
+               return is_type_pointer(expression->base.type)
+                       && (is_constant_expression(expression->unary.value)
+                       || is_address_constant(expression->unary.value));
+
+       case EXPR_BINARY_ADD:
+       case EXPR_BINARY_SUB: {
+               expression_t *left  = expression->binary.left;
+               expression_t *right = expression->binary.right;
+
+               if(is_type_pointer(left->base.type)) {
+                       return is_address_constant(left) && is_constant_expression(right);
+               } else if(is_type_pointer(right->base.type)) {
+                       return is_constant_expression(left)     && is_address_constant(right);
+               }
+
+               return false;
+       }
+
+       case EXPR_REFERENCE: {
+               declaration_t *declaration = expression->reference.declaration;
+               type_t *type = skip_typeref(declaration->type);
+               if(is_type_function(type))
+                       return true;
+               if(is_type_array(type)) {
+                       return is_object_with_constant_address(expression);
+               }
+               return false;
+       }
+
+       default:
+               return false;
+       }
+}
+
 bool is_constant_expression(const expression_t *expression)
 {
        switch(expression->kind) {
@@ -1336,6 +1406,8 @@ bool is_constant_expression(const expression_t *expression)
        case EXPR_UNARY_PREFIX_DECREMENT:
        case EXPR_UNARY_BITFIELD_EXTRACT:
        case EXPR_UNARY_ASSUME: /* has VOID type */
+       case EXPR_UNARY_DEREFERENCE:
+       case EXPR_UNARY_TAKE_ADDRESS:
        case EXPR_BINARY_ASSIGN:
        case EXPR_BINARY_MUL_ASSIGN:
        case EXPR_BINARY_DIV_ASSIGN:
@@ -1354,11 +1426,12 @@ bool is_constant_expression(const expression_t *expression)
        case EXPR_UNARY_PLUS:
        case EXPR_UNARY_BITWISE_NEGATE:
        case EXPR_UNARY_NOT:
-       case EXPR_UNARY_DEREFERENCE:
-       case EXPR_UNARY_TAKE_ADDRESS:
+               return is_constant_expression(expression->unary.value);
+
        case EXPR_UNARY_CAST:
        case EXPR_UNARY_CAST_IMPLICIT:
-               return is_constant_expression(expression->unary.value);
+               return is_type_arithmetic(expression->base.type)
+                       && is_constant_expression(expression->unary.value);
 
        case EXPR_BINARY_ADD:
        case EXPR_BINARY_SUB:
@@ -1389,7 +1462,7 @@ bool is_constant_expression(const expression_t *expression)
                        && is_constant_expression(expression->binary.right);
 
        case EXPR_COMPOUND_LITERAL:
-               return is_initializer_const(expression->compound_literal.initializer);
+               return is_constant_initializer(expression->compound_literal.initializer);
 
        case EXPR_CONDITIONAL:
                /* TODO: not correct, we only have to test expressions which are
diff --git a/ast.h b/ast.h
index de29c09..5e5b7a2 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -78,8 +78,24 @@ void  print_declaration(const declaration_t *declaration);
 void  change_indent(int delta);
 void *allocate_ast(size_t size);
 
+/**
+ * Returns true if a given expression is a compile time
+ * constant.
+ *
+ * @param expression  the expression to check
+ */
+bool is_constant_initializer(const initializer_t *initializer);
+
+/**
+ * Returns true if a given expression is a compile time
+ * constant.
+ *
+ * @param expression  the expression to check
+ */
 bool is_constant_expression(const expression_t *expression);
 
+bool is_address_constant(const expression_t *expression);
+
 long fold_constant(const expression_t *expression);
 
 #endif
index 6cc3300..5a12c4b 100644 (file)
@@ -1,7 +1,5 @@
 #include <config.h>
 
-#define _GNU_SOURCE
-
 #include <assert.h>
 #include <string.h>
 #include <stdbool.h>
@@ -2339,8 +2337,8 @@ static ir_node *compound_literal_to_firm(
        create_local_initializer(initializer, dbgi, entity, type);
 
        /* create a sel for the compound literal address */
-       ir_node   *frame = get_local_frame(entity);
-       ir_node   *sel   = new_d_simpleSel(dbgi, new_NoMem(), frame, entity);
+       ir_node *frame = get_local_frame(entity);
+       ir_node *sel   = new_d_simpleSel(dbgi, new_NoMem(), frame, entity);
        return sel;
 }
 
@@ -3249,6 +3247,101 @@ static ir_initializer_t *create_ir_initializer(
        panic("unknown initializer");
 }
 
+static void create_dynamic_initializer_sub(ir_initializer_t *initializer,
+               ir_type *type, dbg_info *dbgi, ir_node *base_addr)
+{
+       switch(get_initializer_kind(initializer)) {
+       case IR_INITIALIZER_NULL: {
+               ir_mode *mode = get_type_mode(type);
+               /* TODO: implement this for compound types... */
+               assert(type != NULL);
+               tarval  *zero = get_mode_null(mode);
+               ir_node *cnst = new_d_Const(dbgi, mode, zero);
+
+               /* TODO: bitfields */
+               ir_node *mem    = get_store();
+               ir_node *store  = new_d_Store(dbgi, mem, base_addr, cnst);
+               ir_node *proj_m = new_Proj(store, mode_M, pn_Store_M);
+               set_store(proj_m);
+               return;
+       }
+       case IR_INITIALIZER_CONST: {
+               ir_node *node = get_initializer_const_value(initializer);
+               ir_mode *mode = get_irn_mode(node);
+               assert(get_type_mode(type) == mode);
+
+               /* TODO: bitfields... */
+               ir_node *mem    = get_store();
+               ir_node *store  = new_d_Store(dbgi, mem, base_addr, node);
+               ir_node *proj_m = new_Proj(store, mode_M, pn_Store_M);
+               set_store(proj_m);
+               return;
+       }
+       case IR_INITIALIZER_TARVAL: {
+               tarval  *tv   = get_initializer_tarval_value(initializer);
+               ir_mode *mode = get_tarval_mode(tv);
+               ir_node *cnst = new_d_Const(dbgi, mode, tv);
+               assert(get_type_mode(type) == mode);
+
+               /* TODO: bitfields... */
+               ir_node *mem    = get_store();
+               ir_node *store  = new_d_Store(dbgi, mem, base_addr, cnst);
+               ir_node *proj_m = new_Proj(store, mode_M, pn_Store_M);
+               set_store(proj_m);
+               return;
+       }
+       case IR_INITIALIZER_COMPOUND: {
+               assert(is_compound_type(type));
+               int n_members;
+               if(is_Array_type(type)) {
+                       assert(has_array_upper_bound(type, 0));
+                       n_members = get_array_upper_bound_int(type, 0);
+               } else {
+                       n_members = get_compound_n_members(type);
+               }
+
+               if(get_initializer_compound_n_entries(initializer)
+                               != (unsigned) n_members)
+                       panic("initializer doesn't match compound type");
+
+               for(int i = 0; i < n_members; ++i) {
+                       ir_node *addr;
+                       ir_type *irtype;
+                       if(is_Array_type(type)) {
+                               ir_entity *entity   = get_array_element_entity(type);
+                               tarval    *index_tv = new_tarval_from_long(i, mode_uint);
+                               ir_node   *cnst     = new_d_Const(dbgi, mode_uint, index_tv);
+                               ir_node   *in[1]    = { cnst };
+                               irtype = get_array_element_type(type);
+                               addr   = new_d_Sel(dbgi, new_NoMem(), base_addr, 1, in, entity);
+                       } else {
+                               ir_entity *member = get_compound_member(type, i);
+
+                               irtype = get_entity_type(member);
+                               addr   = new_d_simpleSel(dbgi, new_NoMem(), base_addr, member);
+                       }
+
+                       ir_initializer_t *sub_init
+                               = get_initializer_compound_value(initializer, i);
+
+                       create_dynamic_initializer_sub(sub_init, irtype, dbgi, addr);
+               }
+               return;
+       }
+       }
+
+       panic("invalid IR_INITIALIZER found");
+}
+
+static void create_dynamic_initializer(ir_initializer_t *initializer,
+               dbg_info *dbgi, ir_entity *entity)
+{
+       ir_node *frame     = get_local_frame(entity);
+       ir_node *base_addr = new_d_simpleSel(dbgi, new_NoMem(), frame, entity);
+       ir_type *type      = get_entity_type(entity);
+
+       create_dynamic_initializer_sub(initializer, type, dbgi, base_addr);
+}
 
 static void create_local_initializer(initializer_t *initializer, dbg_info *dbgi,
                                      ir_entity *entity, type_t *type)
@@ -3267,6 +3360,23 @@ static void create_local_initializer(initializer_t *initializer, dbg_info *dbgi,
                return;
        }
 
+       if(!is_constant_initializer(initializer)) {
+               ir_initializer_t *irinitializer
+                       = create_ir_initializer(initializer, type);
+
+               create_dynamic_initializer(irinitializer, dbgi, entity);
+               return;
+       }
+
+       /* create the ir_initializer */
+       ir_graph *const old_current_ir_graph = current_ir_graph;
+       current_ir_graph = get_const_code_irg();
+
+       ir_initializer_t *irinitializer = create_ir_initializer(initializer, type);
+
+       assert(current_ir_graph == get_const_code_irg());
+       current_ir_graph = old_current_ir_graph;
+
        /* create a "template" entity which is copied to the entity on the stack */
        ident     *const id          = unique_ident("initializer");
        ir_type   *const irtype      = get_ir_type(type);
@@ -3278,17 +3388,10 @@ static void create_local_initializer(initializer_t *initializer, dbg_info *dbgi,
        set_entity_visibility(init_entity, visibility_local);
        set_entity_allocation(init_entity, allocation_static);
 
-       ir_graph *const old_current_ir_graph = current_ir_graph;
-       current_ir_graph = get_const_code_irg();
-
-       ir_initializer_t *irinitializer = create_ir_initializer(initializer, type);
        set_entity_initializer(init_entity, irinitializer);
 
-       assert(current_ir_graph == get_const_code_irg());
-       current_ir_graph = old_current_ir_graph;
-
-       ir_node *const src_addr  = create_symconst(dbgi, mode_P_data, init_entity);
-       ir_node *const copyb     = new_d_CopyB(dbgi, memory, addr, src_addr, irtype);
+       ir_node *const src_addr = create_symconst(dbgi, mode_P_data, init_entity);
+       ir_node *const copyb    = new_d_CopyB(dbgi, memory, addr, src_addr, irtype);
 
        ir_node *const copyb_mem = new_Proj(copyb, mode_M, pn_CopyB_M_regular);
        set_store(copyb_mem);
diff --git a/ast_t.h b/ast_t.h
index 34a03f5..ef20c90 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -324,15 +324,15 @@ union expression_t {
 
 typedef enum {
        STORAGE_CLASS_NONE,
-       STORAGE_CLASS_TYPEDEF,
        STORAGE_CLASS_EXTERN,
        STORAGE_CLASS_STATIC,
+       STORAGE_CLASS_TYPEDEF,
        STORAGE_CLASS_AUTO,
        STORAGE_CLASS_REGISTER,
        STORAGE_CLASS_ENUM_ENTRY,
        STORAGE_CLASS_THREAD,
        STORAGE_CLASS_THREAD_EXTERN,
-       STORAGE_CLASS_THREAD_STATIC
+       STORAGE_CLASS_THREAD_STATIC,
 } storage_class_tag_t;
 
 typedef enum {
@@ -406,6 +406,7 @@ typedef unsigned short decl_modifiers_t;
 
 struct declaration_t {
        unsigned char       namespc;
+       unsigned char       declared_storage_class;
        unsigned char       storage_class;
        decl_modifiers_t    modifiers;
        unsigned int        address_taken : 1;
index 7a52c9a..306de11 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -31,7 +31,7 @@ typedef struct {
 typedef struct declaration_specifiers_t  declaration_specifiers_t;
 struct declaration_specifiers_t {
        source_position_t  source_position;
-       unsigned char      storage_class;
+       unsigned char      declared_storage_class;
        bool               is_inline;
        decl_modifiers_t   decl_modifiers;
        type_t            *type;
@@ -809,11 +809,12 @@ static type_t *make_global_typedef(const char *name, type_t *type)
        symbol_t *const symbol       = symbol_table_insert(name);
 
        declaration_t *const declaration = allocate_declaration_zero();
-       declaration->namespc         = NAMESPACE_NORMAL;
-       declaration->storage_class   = STORAGE_CLASS_TYPEDEF;
-       declaration->type            = type;
-       declaration->symbol          = symbol;
-       declaration->source_position = builtin_source_position;
+       declaration->namespc                = NAMESPACE_NORMAL;
+       declaration->storage_class          = STORAGE_CLASS_TYPEDEF;
+       declaration->declared_storage_class = STORAGE_CLASS_TYPEDEF;
+       declaration->type                   = type;
+       declaration->symbol                 = symbol;
+       declaration->source_position        = builtin_source_position;
 
        record_declaration(declaration);
 
@@ -1003,6 +1004,12 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
        return result;
 }
 
+static bool is_initializer_constant(const expression_t *expression)
+{
+       return is_constant_expression(expression)
+               || is_address_constant(expression);
+}
+
 static initializer_t *parse_scalar_initializer(type_t *type,
                                                bool must_be_constant)
 {
@@ -1017,7 +1024,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
        }
 
        expression_t *expression = parse_assignment_expression();
-       if(must_be_constant && !is_constant_expression(expression)) {
+       if(must_be_constant && !is_initializer_constant(expression)) {
                errorf(expression->base.source_position,
                       "Initialisation expression '%E' is not constant\n",
                       expression);
@@ -1365,7 +1372,7 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                        /* must be an expression */
                        expression_t *expression = parse_assignment_expression();
 
-                       if(must_be_constant && !is_constant_expression(expression)) {
+                       if(must_be_constant && !is_initializer_constant(expression)) {
                                errorf(expression->base.source_position,
                                       "Initialisation expression '%E' is not constant\n",
                                       expression);
@@ -1471,23 +1478,11 @@ static void parse_initializer(parse_initializer_env_t *env)
        initializer_t *result = NULL;
        size_t         max_index;
 
-       if(token.type != '{') {
-               expression_t *expression = parse_assignment_expression();
-
-               result = initializer_from_expression(type, expression);
-               if(result == NULL) {
-                       errorf(HERE,
-                               "initializer expression '%E' of type '%T' is incompatible with type '%T'",
-                               expression, expression->base.type, env->type);
-               }
-       } else if(is_type_scalar(type)) {
+       if(is_type_scalar(type)) {
                /* TODO: § 6.7.8.11; eat {} without warning */
                result = parse_scalar_initializer(type, env->must_be_constant);
-
-               if(token.type == ',')
-                       next_token();
        } else if(token.type == '{') {
-               next_token();
+               eat('{');
 
                type_path_t path;
                memset(&path, 0, sizeof(path));
@@ -1504,8 +1499,9 @@ static void parse_initializer(parse_initializer_env_t *env)
 
                expect_void('}');
        } else {
-               /* TODO: can this even happen? */
-               panic("TODO");
+               /* parse_scalar_initializer also works in this case: we simply
+                * have an expression without {} around it */
+               result = parse_scalar_initializer(type, env->must_be_constant);
        }
 
        /* § 6.7.5 (22)  array initializers for arrays with unknown size determine
@@ -1825,13 +1821,13 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                switch(token.type) {
 
                /* storage class */
-#define MATCH_STORAGE_CLASS(token, class)                                \
-               case token:                                                      \
-                       if(specifiers->storage_class != STORAGE_CLASS_NONE) {        \
+#define MATCH_STORAGE_CLASS(token, class)                                  \
+               case token:                                                        \
+                       if(specifiers->declared_storage_class != STORAGE_CLASS_NONE) { \
                                errorf(HERE, "multiple storage classes in declaration specifiers"); \
-                       }                                                            \
-                       specifiers->storage_class = class;                           \
-                       next_token();                                                \
+                       }                                                              \
+                       specifiers->declared_storage_class = class;                    \
+                       next_token();                                                  \
                        break;
 
                MATCH_STORAGE_CLASS(T_typedef,  STORAGE_CLASS_TYPEDEF)
@@ -1841,22 +1837,22 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_STORAGE_CLASS(T_register, STORAGE_CLASS_REGISTER)
 
                case T___thread:
-                       switch (specifiers->storage_class) {
-                               case STORAGE_CLASS_NONE:
-                                       specifiers->storage_class = STORAGE_CLASS_THREAD;
-                                       break;
+                       switch (specifiers->declared_storage_class) {
+                       case STORAGE_CLASS_NONE:
+                               specifiers->declared_storage_class = STORAGE_CLASS_THREAD;
+                               break;
 
-                               case STORAGE_CLASS_EXTERN:
-                                       specifiers->storage_class = STORAGE_CLASS_THREAD_EXTERN;
-                                       break;
+                       case STORAGE_CLASS_EXTERN:
+                               specifiers->declared_storage_class = STORAGE_CLASS_THREAD_EXTERN;
+                               break;
 
-                               case STORAGE_CLASS_STATIC:
-                                       specifiers->storage_class = STORAGE_CLASS_THREAD_STATIC;
-                                       break;
+                       case STORAGE_CLASS_STATIC:
+                               specifiers->declared_storage_class = STORAGE_CLASS_THREAD_STATIC;
+                               break;
 
-                               default:
-                                       errorf(HERE, "multiple storage classes in declaration specifiers");
-                                       break;
+                       default:
+                               errorf(HERE, "multiple storage classes in declaration specifiers");
+                               break;
                        }
                        next_token();
                        break;
@@ -2150,10 +2146,10 @@ static void semantic_parameter(declaration_t *declaration)
 {
        /* TODO: improve error messages */
 
-       if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) {
+       if(declaration->declared_storage_class == STORAGE_CLASS_TYPEDEF) {
                errorf(HERE, "typedef not allowed in parameter list");
-       } else if(declaration->storage_class != STORAGE_CLASS_NONE
-                       && declaration->storage_class != STORAGE_CLASS_REGISTER) {
+       } else if(declaration->declared_storage_class != STORAGE_CLASS_NONE
+                       && declaration->declared_storage_class != STORAGE_CLASS_REGISTER) {
                errorf(HERE, "parameter may only have none or register storage class");
        }
 
@@ -2548,10 +2544,16 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 static declaration_t *parse_declarator(
                const declaration_specifiers_t *specifiers, bool may_be_abstract)
 {
-       declaration_t *const declaration = allocate_declaration_zero();
-       declaration->storage_class  = specifiers->storage_class;
-       declaration->modifiers      = specifiers->decl_modifiers;
-       declaration->is_inline      = specifiers->is_inline;
+       declaration_t *const declaration    = allocate_declaration_zero();
+       declaration->declared_storage_class = specifiers->declared_storage_class;
+       declaration->modifiers              = specifiers->decl_modifiers;
+       declaration->is_inline              = specifiers->is_inline;
+
+       declaration->storage_class          = specifiers->declared_storage_class;
+       if(declaration->storage_class == STORAGE_CLASS_NONE
+                       && scope != global_scope) {
+               declaration->storage_class = STORAGE_CLASS_AUTO;
+       }
 
        construct_type_t *construct_type
                = parse_inner_declarator(declaration, may_be_abstract);
@@ -2743,6 +2745,7 @@ warn_redundant_declaration:
                                                }
                                                if (new_storage_class == STORAGE_CLASS_NONE) {
                                                        previous_declaration->storage_class = STORAGE_CLASS_NONE;
+                                                       previous_declaration->declared_storage_class = STORAGE_CLASS_NONE;
                                                }
                                        }
                                } else {
@@ -2873,14 +2876,15 @@ static void parse_anonymous_declaration_rest(
 {
        eat(';');
 
-       declaration_t *const declaration = allocate_declaration_zero();
-       declaration->type            = specifiers->type;
-       declaration->storage_class   = specifiers->storage_class;
-       declaration->source_position = specifiers->source_position;
+       declaration_t *const declaration    = allocate_declaration_zero();
+       declaration->type                   = specifiers->type;
+       declaration->declared_storage_class = specifiers->declared_storage_class;
+       declaration->source_position        = specifiers->source_position;
 
-       if (declaration->storage_class != STORAGE_CLASS_NONE) {
+       if (declaration->declared_storage_class != STORAGE_CLASS_NONE) {
                warningf(declaration->source_position, "useless storage class in empty declaration");
        }
+       declaration->storage_class = STORAGE_CLASS_NONE;
 
        type_t *type = declaration->type;
        switch (type->kind) {
@@ -2955,6 +2959,7 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration)
 
        if(previous_declaration->type == NULL) {
                previous_declaration->type          = declaration->type;
+               previous_declaration->declared_storage_class = declaration->declared_storage_class;
                previous_declaration->storage_class = declaration->storage_class;
                previous_declaration->parent_scope  = scope;
                return previous_declaration;
@@ -3300,12 +3305,13 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
 
                        type_t *type = make_bitfield_type(base_type, size, source_position);
 
-                       declaration                  = allocate_declaration_zero();
-                       declaration->namespc         = NAMESPACE_NORMAL;
-                       declaration->storage_class   = STORAGE_CLASS_NONE;
-                       declaration->source_position = source_position;
-                       declaration->modifiers       = specifiers->decl_modifiers;
-                       declaration->type            = type;
+                       declaration                         = allocate_declaration_zero();
+                       declaration->namespc                = NAMESPACE_NORMAL;
+                       declaration->declared_storage_class = STORAGE_CLASS_NONE;
+                       declaration->storage_class          = STORAGE_CLASS_NONE;
+                       declaration->source_position        = source_position;
+                       declaration->modifiers              = specifiers->decl_modifiers;
+                       declaration->type                   = type;
                } else {
                        declaration = parse_declarator(specifiers,/*may_be_abstract=*/true);
 
@@ -3390,7 +3396,7 @@ static type_t *parse_typename(void)
        declaration_specifiers_t specifiers;
        memset(&specifiers, 0, sizeof(specifiers));
        parse_declaration_specifiers(&specifiers);
-       if(specifiers.storage_class != STORAGE_CLASS_NONE) {
+       if(specifiers.declared_storage_class != STORAGE_CLASS_NONE) {
                /* TODO: improve error message, user does probably not know what a
                 * storage class is...
                 */
@@ -3555,12 +3561,13 @@ static declaration_t *create_implicit_function(symbol_t *symbol,
                free_type(ntype);
        }
 
-       declaration_t *const declaration = allocate_declaration_zero();
-       declaration->storage_class   = STORAGE_CLASS_EXTERN;
-       declaration->type            = type;
-       declaration->symbol          = symbol;
-       declaration->source_position = source_position;
-       declaration->parent_scope  = global_scope;
+       declaration_t *const declaration    = allocate_declaration_zero();
+       declaration->storage_class          = STORAGE_CLASS_EXTERN;
+       declaration->declared_storage_class = STORAGE_CLASS_EXTERN;
+       declaration->type                   = type;
+       declaration->symbol                 = symbol;
+       declaration->source_position        = source_position;
+       declaration->parent_scope           = global_scope;
 
        scope_t *old_scope = scope;
        set_scope(global_scope);
@@ -5935,7 +5942,6 @@ static statement_t *parse_break(void)
  */
 static bool is_local_var_declaration(const declaration_t *declaration) {
        switch ((storage_class_tag_t) declaration->storage_class) {
-       case STORAGE_CLASS_NONE:
        case STORAGE_CLASS_AUTO:
        case STORAGE_CLASS_REGISTER: {
                const type_t *type = skip_typeref(declaration->type);
@@ -5954,25 +5960,11 @@ static bool is_local_var_declaration(const declaration_t *declaration) {
  * Check if a given declaration represents a variable.
  */
 static bool is_var_declaration(const declaration_t *declaration) {
-       switch ((storage_class_tag_t) declaration->storage_class) {
-       case STORAGE_CLASS_NONE:
-       case STORAGE_CLASS_EXTERN:
-       case STORAGE_CLASS_STATIC:
-       case STORAGE_CLASS_AUTO:
-       case STORAGE_CLASS_REGISTER:
-       case STORAGE_CLASS_THREAD:
-       case STORAGE_CLASS_THREAD_EXTERN:
-       case STORAGE_CLASS_THREAD_STATIC: {
-               const type_t *type = skip_typeref(declaration->type);
-               if(is_type_function(type)) {
-                       return false;
-               } else {
-                       return true;
-               }
-       }
-       default:
+       if(declaration->storage_class == STORAGE_CLASS_TYPEDEF)
                return false;
-       }
+
+       const type_t *type = skip_typeref(declaration->type);
+       return !is_type_function(type);
 }
 
 /**
diff --git a/parsetest/compoundlit3.c b/parsetest/compoundlit3.c
new file mode 100644 (file)
index 0000000..10e7d33
--- /dev/null
@@ -0,0 +1,17 @@
+int a, b, c;
+
+typedef struct S {
+       int k[3];
+       struct lku {
+               double d, e;
+       } elem;
+} S;
+S kg;
+
+int main(void) {
+       S k = { a, b };
+
+       kg = k;
+
+       return 0;
+}
diff --git a/parsetest/cp_error021.c b/parsetest/cp_error021.c
new file mode 100644 (file)
index 0000000..d2b03a8
--- /dev/null
@@ -0,0 +1,6 @@
+
+int main(void) {
+       int arr[] = { [4] = 2, };
+
+       return 0;
+}
diff --git a/parsetest/init7.c b/parsetest/init7.c
new file mode 100644 (file)
index 0000000..cb42382
--- /dev/null
@@ -0,0 +1,16 @@
+struct S {
+       int a, b;
+} glob;
+
+struct S *globptr  = &glob;
+struct S *globptr2 = &*&glob;
+int      *intptr   = &*&glob.b;
+int      *intp2    = &(&glob + 3)->b;
+
+int arr[10];
+int *p = arr + 4;
+
+int main(void)
+{
+       return 0;
+}
diff --git a/parsetest/shouldfail/init8.c b/parsetest/shouldfail/init8.c
new file mode 100644 (file)
index 0000000..58845e5
--- /dev/null
@@ -0,0 +1,13 @@
+struct S {
+       int a, b;
+} glob;
+
+struct S *globptr  = &glob;
+struct S *globptr2 = &*&glob;
+int      *intptr   = &*&glob.b;
+int      *intp2    = ((int*) ((short) &intptr));
+
+int main(void)
+{
+       return 0;
+}