- first iteration of new initializer code
authorMatthias Braun <matze@braunis.de>
Wed, 13 Feb 2008 18:20:39 +0000 (18:20 +0000)
committerMatthias Braun <matze@braunis.de>
Wed, 13 Feb 2008 18:20:39 +0000 (18:20 +0000)
- implemented __builtin_offsetof

[r18851]

14 files changed:
TODO
ast.c
ast.h
ast2firm.c
ast_t.h
lexer.c
parser.c
parser.h
parsetest/compoundlit.c [new file with mode: 0644]
parsetest/offsetof.c [new file with mode: 0644]
parsetest/shouldfail/offsetof.c [new file with mode: 0644]
type.c
type_t.h
types.h

diff --git a/TODO b/TODO
index 8c059a1..7bcd77b 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,11 @@
+Initializer rewrite:
+- determining of array size for array types of unspecified length is wrong in
+  presence of designators and unions
+
 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
 
 Lexer:
 - Add preprocessor code
@@ -10,22 +15,24 @@ Lexer:
 
 Parser:
 - the expect macros abort functions directly. This leads to some functions
-  not resetting the current context properly (parse_for)
+  not resetting the current context properly (parse_for); expect in expressions
+  suddenly return NULL which triggers asserts
 - label: declaration; is no valid C99 but we parse it anyway
 - designator support for initializers
 - add constant folding code
-- Refactor code, so code to handle number values and strings is
-  an own module and replacable
+- Refactor code, so code to handle number values (and strings?) is an own
+  module and replacable
 - Support some attributes. noreturn, unused, printf, scanf, packed would be
   interesting candidates
+- Add columns to source positions
 - SourcePositions could be stored selectively on expressions that really need
   them.
 - check semantic for functions declared/defined in global scope and declared
   again in a local scope
 
 ast2firm:
+- handle non-constant initializers
 - output source file positions for panics...
-- output variable names for uninitialized variable warnings
 - handle bitfield members with 0 correctly (standard says they finish the
   current unit)
 
diff --git a/ast.c b/ast.c
index 51b6a7c..db18071 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -83,6 +83,7 @@ static unsigned get_expression_precedence(expression_kind_t kind)
                [EXPR_CONST]                     = PREC_PRIM,
                [EXPR_STRING_LITERAL]            = PREC_PRIM,
                [EXPR_WIDE_STRING_LITERAL]       = PREC_PRIM,
+               [EXPR_COMPOUND_LITERAL]          = PREC_UNARY,
                [EXPR_CALL]                      = PREC_PRIM,
                [EXPR_CONDITIONAL]               = PREC_COND,
                [EXPR_SELECT]                    = PREC_ACCESS,
@@ -245,12 +246,10 @@ static void print_string_literal(
  *
  * @param wstr  the wide string literal expression
  */
-static void print_wide_string_literal(
-       const wide_string_literal_expression_t *const wstr)
+static void print_quoted_wide_string(const wide_string_t *const wstr)
 {
        fputs("L\"", out);
-       for (const wchar_rep_t *c   = wstr->value.begin,
-                              *end = c + wstr->value.size;
+       for (const wchar_rep_t *c = wstr->begin, *end = wstr->begin + wstr->size;
             c != end; ++c) {
                switch (*c) {
                        case L'\"':  fputs("\\\"", out); break;
@@ -290,6 +289,21 @@ static void print_wide_string_literal(
        fputc('"', out);
 }
 
+static void print_wide_string_literal(
+       const wide_string_literal_expression_t *const wstr)
+{
+       print_quoted_wide_string(&wstr->value);
+}
+
+static void print_compound_literal(
+               const compound_literal_expression_t *expression)
+{
+       fputc('(', out);
+       print_type(expression->type);
+       fputs(") ", out);
+       print_initializer(expression->initializer);
+}
+
 /**
  * Prints a call expression.
  *
@@ -609,11 +623,10 @@ static void print_classify_type_expression(
  */
 static void print_designator(const designator_t *designator)
 {
-       fputs(designator->symbol->string, out);
-       for (designator = designator->next; designator != NULL; designator = designator->next) {
-               if (designator->array_access) {
+       for ( ; designator != NULL; designator = designator->next) {
+               if (designator->symbol == NULL) {
                        fputc('[', out);
-                       print_expression_prec(designator->array_access, PREC_ACCESS);
+                       print_expression_prec(designator->array_index, PREC_ACCESS);
                        fputc(']', out);
                } else {
                        fputc('.', out);
@@ -681,6 +694,9 @@ static void print_expression_prec(const expression_t *expression, unsigned top_p
        case EXPR_WIDE_STRING_LITERAL:
                print_wide_string_literal(&expression->wide_string);
                break;
+       case EXPR_COMPOUND_LITERAL:
+               print_compound_literal(&expression->compound_literal);
+               break;
        case EXPR_CALL:
                print_call_expression(&expression->call);
                break;
@@ -1119,23 +1135,45 @@ static void print_storage_class(unsigned storage_class)
  */
 void print_initializer(const initializer_t *initializer)
 {
-       if(initializer->kind == INITIALIZER_VALUE) {
+       if(initializer == NULL) {
+               fputs("{ NIL-INITIALIZER }", out);
+               return;
+       }
+
+       switch(initializer->kind) {
+       case INITIALIZER_VALUE: {
                const initializer_value_t *value = &initializer->value;
                print_expression(value->value);
                return;
        }
-
-       assert(initializer->kind == INITIALIZER_LIST);
-       fputs("{ ", out);
-       const initializer_list_t *list = &initializer->list;
-
-       for(size_t i = 0 ; i < list->len; ++i) {
-               if(i > 0) {
-                       fputs(", ", out);
+       case INITIALIZER_LIST: {
+               assert(initializer->kind == INITIALIZER_LIST);
+               fputs("{ ", out);
+               const initializer_list_t *list = &initializer->list;
+
+               for(size_t i = 0 ; i < list->len; ++i) {
+                       const initializer_t *sub_init = list->initializers[i];
+                       print_initializer(list->initializers[i]);
+                       if(i < list->len-1 && sub_init->kind != INITIALIZER_DESIGNATOR) {
+                               fputs(", ", out);
+                       }
                }
-               print_initializer(list->initializers[i]);
+               fputs(" }", out);
+               return;
        }
-       fputs("}", out);
+       case INITIALIZER_STRING:
+               print_quoted_string(&initializer->string.string, '"');
+               return;
+       case INITIALIZER_WIDE_STRING:
+               print_quoted_wide_string(&initializer->wide_string.string);
+               return;
+       case INITIALIZER_DESIGNATOR:
+               print_designator(initializer->designator.designator);
+               fputs(" = ", out);
+               return;
+       }
+
+       panic("invalid initializer kind found");
 }
 
 /**
@@ -1327,6 +1365,10 @@ bool is_constant_expression(const expression_t *expression)
                return is_constant_expression(expression->binary.left)
                        && is_constant_expression(expression->binary.right);
 
+       case EXPR_COMPOUND_LITERAL:
+               /* TODO: check initializer if it is constant */
+               return true;
+
        case EXPR_CONDITIONAL:
                /* TODO: not correct, we only have to test expressions which are
                 * evaluated, which means either the true or false part might be not
diff --git a/ast.h b/ast.h
index f5eacfe..de29c09 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -10,6 +10,7 @@ typedef struct expression_base_t                expression_base_t;
 typedef struct const_expression_t               const_expression_t;
 typedef struct string_literal_expression_t      string_literal_expression_t;
 typedef struct wide_string_literal_expression_t wide_string_literal_expression_t;
+typedef struct compound_literal_expression_t    compound_literal_expression_t;
 typedef struct reference_expression_t           reference_expression_t;
 typedef struct cast_expression_t                cast_expression_t;
 typedef struct call_argument_t                  call_argument_t;
@@ -40,6 +41,7 @@ typedef struct initializer_list_t           initializer_list_t;
 typedef struct initializer_value_t          initializer_value_t;
 typedef struct initializer_string_t         initializer_string_t;
 typedef struct initializer_wide_string_t    initializer_wide_string_t;
+typedef struct initializer_designator_t     initializer_designator_t;
 typedef union  initializer_t                initializer_t;
 
 typedef struct declaration_t                declaration_t;
@@ -78,4 +80,6 @@ void *allocate_ast(size_t size);
 
 bool is_constant_expression(const expression_t *expression);
 
+long fold_constant(const expression_t *expression);
+
 #endif
index a4ee315..5fd9b57 100644 (file)
@@ -19,6 +19,7 @@
 #include "parser.h"
 #include "diagnostic.h"
 #include "lang_features.h"
+#include "types.h"
 #include "driver/firm_opt.h"
 #include "driver/firm_cmdline.h"
 
@@ -30,8 +31,6 @@ static ir_type *ir_type_void;
 static ir_type *ir_type_int;
 
 static type_t *type_const_char;
-static type_t *type_void;
-static type_t *type_int;
 
 static int       next_value_number_function;
 static ir_node  *continue_label;
@@ -63,8 +62,9 @@ ir_node *uninitialized_local_var(ir_graph *irg, ir_mode *mode, int pos)
 {
        const declaration_t *declaration = get_irg_loc_description(irg, pos);
 
-       warningf(declaration->source_position, "variable '%#T' might be used uninitialized",
-                       declaration->type, declaration->symbol);
+       warningf(declaration->source_position,
+                "variable '%#T' might be used uninitialized",
+                declaration->type, declaration->symbol);
        return new_r_Unknown(irg, mode);
 }
 
@@ -353,10 +353,6 @@ static unsigned count_parameters(const function_type_t *function_type)
 }
 
 
-
-
-static long fold_constant(const expression_t *expression);
-
 static ir_type *create_atomic_type(const atomic_type_t *type)
 {
        dbg_info *dbgi  = get_dbg_info(&type->type.source_position);
@@ -426,15 +422,15 @@ static ir_type *create_array_type(array_type_t *type)
        type_t  *element_type    = type->element_type;
        ir_type *ir_element_type = get_ir_type(element_type);
 
-       ident   *id      = unique_ident("array");
-       dbg_info *dbgi   = get_dbg_info(&type->type.source_position);
-       ir_type *ir_type = new_d_type_array(id, 1, ir_element_type, dbgi);
+       ident    *id      = unique_ident("array");
+       dbg_info *dbgi    = get_dbg_info(&type->type.source_position);
+       ir_type  *ir_type = new_d_type_array(id, 1, ir_element_type, dbgi);
 
        const int align = get_type_alignment_bytes(ir_element_type);
        set_type_alignment_bytes(ir_type, align);
 
-       if(type->size != NULL) {
-               int n_elements = fold_constant(type->size);
+       if(type->size_constant) {
+               int n_elements = type->size;
 
                set_array_bounds_int(ir_type, 0, 0, n_elements);
 
@@ -685,8 +681,8 @@ static ir_type *create_union_type(compound_type_t *type, ir_type *irtype,
                return declaration->v.irtype;
        }
 
-       size_t offset    = 0;
        size_t align_all = 1;
+       size_t offset    = 0;
        size_t size      = 0;
 
        if(irtype == NULL) {
@@ -700,6 +696,9 @@ static ir_type *create_union_type(compound_type_t *type, ir_type *irtype,
                dbg_info *dbgi = get_dbg_info(&type->type.source_position);
 
                irtype = new_d_type_union(id, dbgi);
+
+               declaration->v.irtype = irtype;
+               type->type.firm_type  = irtype;
        } else {
                offset    = *outer_offset;
                align_all = *outer_align;
@@ -712,11 +711,12 @@ static ir_type *create_union_type(compound_type_t *type, ir_type *irtype,
                if(entry->namespc != NAMESPACE_NORMAL)
                        continue;
 
-               type_t  *entry_type    = skip_typeref(entry->type);
-               ir_type *entry_ir_type = get_ir_type(entry_type);
+               symbol_t *symbol        = entry->symbol;
+               type_t   *entry_type    = skip_typeref(entry->type);
+               ir_type  *entry_ir_type = get_ir_type(entry_type);
 
                ident *ident;
-               if(entry->symbol != NULL) {
+               if(symbol != NULL) {
                        ident = new_id_from_str(entry->symbol->string);
                } else {
                        size_t offs = offset;
@@ -792,7 +792,7 @@ static ir_type *create_enum_type(enum_type_t *const type)
 {
        type->type.firm_type = ir_type_int;
 
-       ir_mode *const mode    = get_ir_mode((type_t*) type);
+       ir_mode *const mode    = mode_int;
        tarval  *const one     = get_mode_one(mode);
        tarval  *      tv_next = get_tarval_null(mode);
 
@@ -1078,10 +1078,10 @@ static ir_node *string_to_firm(const source_position_t *const src_pos,
                                const char *const id_prefix,
                                const string_t *const value)
 {
-       ir_type *const global_type = get_glob_type();
-       dbg_info *const dbgi       = get_dbg_info(src_pos);
-       ir_type *const type        = new_d_type_array(unique_ident("strtype"), 1,
-                                                   ir_type_const_char, dbgi);
+       ir_type  *const global_type = get_glob_type();
+       dbg_info *const dbgi        = get_dbg_info(src_pos);
+       ir_type  *const type        = new_d_type_array(unique_ident("strtype"), 1,
+                                                      ir_type_const_char, dbgi);
 
        ident     *const id     = unique_ident(id_prefix);
        ir_entity *const entity = new_d_entity(global_type, id, type, dbgi);
@@ -2257,6 +2257,82 @@ static ir_node *array_access_to_firm(
        return deref_address(irtype, addr, dbgi);
 }
 
+static long get_offsetof_offset(const offsetof_expression_t *expression)
+{
+       type_t *orig_type = expression->type;
+       long    offset    = 0;
+
+       designator_t *designator = expression->designator;
+       for( ; designator != NULL; designator = designator->next) {
+               type_t *type = skip_typeref(orig_type);
+               /* be sure the type is constructed */
+               (void) get_ir_type(type);
+
+               if(designator->symbol != NULL) {
+                       assert(is_type_compound(type));
+                       symbol_t *symbol = designator->symbol;
+
+                       declaration_t *declaration = type->compound.declaration;
+                       declaration_t *iter        = declaration->scope.declarations;
+                       for( ; iter != NULL; iter = iter->next) {
+                               if(iter->symbol == symbol) {
+                                       break;
+                               }
+                       }
+                       assert(iter != NULL);
+
+                       assert(iter->declaration_kind == DECLARATION_KIND_COMPOUND_MEMBER);
+                       offset += get_entity_offset(iter->v.entity);
+
+                       orig_type = iter->type;
+               } else {
+                       expression_t *array_index = designator->array_index;
+                       assert(designator->array_index != NULL);
+                       assert(is_type_array(type));
+                       assert(is_type_valid(array_index->base.type));
+
+                       long index         = fold_constant(array_index);
+                       ir_type *arr_type  = get_ir_type(type);
+                       ir_type *elem_type = get_array_element_type(arr_type);
+                       long     elem_size = get_type_size_bytes(elem_type);
+
+                       offset += index * elem_size;
+
+                       orig_type = type->array.element_type;
+               }
+       }
+
+       return offset;
+}
+
+static ir_node *offsetof_to_firm(const offsetof_expression_t *expression)
+{
+       ir_mode  *mode   = get_ir_mode(expression->base.type);
+       long      offset = get_offsetof_offset(expression);
+       tarval   *tv     = new_tarval_from_long(offset, mode);
+       dbg_info *dbgi   = get_dbg_info(&expression->base.source_position);
+
+       return new_d_Const(dbgi, mode, tv);
+}
+
+static ir_node *compound_literal_to_firm(
+               const compound_literal_expression_t *expression)
+{
+       /* create an entity on the stack */
+       ir_type *frame_type = get_irg_frame_type(current_ir_graph);
+
+       ident     *const id     = unique_ident("CompLit");
+       ir_type   *const irtype = get_ir_type(expression->type);
+       dbg_info  *const dbgi   = get_dbg_info(&expression->base.source_position);
+       ir_entity *const entity = new_d_entity(frame_type, id, irtype, dbgi);
+       set_entity_ld_ident(entity, id);
+
+       set_entity_variability(entity, variability_uninitialized);
+
+       /* create initialisation code TODO */
+       return NULL;
+}
+
 /**
  * Transform a sizeof expression into Firm code.
  */
@@ -2298,8 +2374,11 @@ static ir_node *alignof_to_firm(const typeprop_expression_t *expression)
        return new_SymConst(mode, sym, symconst_type_align);
 }
 
-static long fold_constant(const expression_t *expression)
+static void init_ir_types(void);
+long fold_constant(const expression_t *expression)
 {
+       init_ir_types();
+
        assert(is_constant_expression(expression));
 
        ir_graph *old_current_ir_graph = current_ir_graph;
@@ -2652,13 +2731,16 @@ static ir_node *_expression_to_firm(const expression_t *expression)
                return va_start_expression_to_firm(&expression->va_starte);
        case EXPR_VA_ARG:
                return va_arg_expression_to_firm(&expression->va_arge);
-       case EXPR_OFFSETOF:
        case EXPR_BUILTIN_SYMBOL:
                panic("unimplemented expression found");
        case EXPR_BUILTIN_CONSTANT_P:
                return builtin_constant_to_firm(&expression->builtin_constant);
        case EXPR_BUILTIN_PREFETCH:
                return builtin_prefetch_to_firm(&expression->builtin_prefetch);
+       case EXPR_OFFSETOF:
+               return offsetof_to_firm(&expression->offsetofe);
+       case EXPR_COMPOUND_LITERAL:
+               return compound_literal_to_firm(&expression->compound_literal);
 
        case EXPR_UNKNOWN:
        case EXPR_INVALID:
@@ -2781,8 +2863,249 @@ static void create_declaration_entity(declaration_t *declaration,
        /* TODO: visibility? */
 }
 
+
+typedef struct type_path_entry_t type_path_entry_t;
+struct type_path_entry_t {
+       type_t           *type;
+       ir_initializer_t *initializer;
+       size_t            index;
+       declaration_t    *compound_entry;
+};
+
+typedef struct type_path_t type_path_t;
+struct type_path_t {
+       type_path_entry_t *path;
+       type_t            *top_type;
+       bool               invalid;
+};
+
+static __attribute__((unused)) void debug_print_type_path(const type_path_t *path)
+{
+       size_t len = ARR_LEN(path->path);
+
+       for(size_t i = 0; i < len; ++i) {
+               const type_path_entry_t *entry = & path->path[i];
+
+               type_t *type = skip_typeref(entry->type);
+               if(is_type_compound(type)) {
+                       fprintf(stderr, ".%s", entry->compound_entry->symbol->string);
+               } else if(is_type_array(type)) {
+                       fprintf(stderr, "[%u]", entry->index);
+               } else {
+                       fprintf(stderr, "-INVALID-");
+               }
+       }
+       fprintf(stderr, "  (");
+       print_type(path->top_type);
+       fprintf(stderr, ")");
+}
+
+static type_path_entry_t *get_type_path_top(const type_path_t *path)
+{
+       size_t len = ARR_LEN(path->path);
+       assert(len > 0);
+       return & path->path[len-1];
+}
+
+static type_path_entry_t *append_to_type_path(type_path_t *path)
+{
+       size_t len = ARR_LEN(path->path);
+       ARR_RESIZE(type_path_entry_t, path->path, len+1);
+
+       type_path_entry_t *result = & path->path[len];
+       memset(result, 0, sizeof(result[0]));
+       return result;
+}
+
+static size_t get_compound_size(const compound_type_t *type)
+{
+       declaration_t *declaration = type->declaration;
+       declaration_t *member      = declaration->scope.declarations;
+       size_t         size        = 0;
+       for( ; member != NULL; member = member->next) {
+               ++size;
+       }
+       /* TODO: cache results? */
+
+       return size;
+}
+
+static ir_initializer_t *get_initializer_entry(type_path_t *path)
+{
+       type_t *orig_top_type = path->top_type;
+       type_t *top_type      = skip_typeref(orig_top_type);
+
+       assert(is_type_compound(top_type) || is_type_array(top_type));
+
+       if(ARR_LEN(path->path) == 0) {
+               return NULL;
+       } else {
+               type_path_entry_t *top         = get_type_path_top(path);
+               ir_initializer_t  *initializer = top->initializer;
+               return get_initializer_compound_value(initializer, top->index);
+       }
+}
+
+static void descend_into_subtype(type_path_t *path)
+{
+       type_t *orig_top_type = path->top_type;
+       type_t *top_type      = skip_typeref(orig_top_type);
+
+       assert(is_type_compound(top_type) || is_type_array(top_type));
+
+       ir_initializer_t *initializer = get_initializer_entry(path);
+
+       type_path_entry_t *top = append_to_type_path(path);
+       top->type              = top_type;
+
+       size_t len;
+
+       if(is_type_compound(top_type)) {
+               declaration_t *declaration = top_type->compound.declaration;
+               declaration_t *entry       = declaration->scope.declarations;
+
+               top->compound_entry = entry;
+               top->index          = 0;
+               path->top_type      = entry->type;
+               len                 = get_compound_size(&top_type->compound);
+       } else {
+               assert(is_type_array(top_type));
+               assert(top_type->array.size > 0);
+
+               top->index     = 0;
+               path->top_type = top_type->array.element_type;
+               len            = top_type->array.size;
+       }
+       if(initializer == NULL
+                       || get_initializer_kind(initializer) == IR_INITIALIZER_NULL) {
+               initializer = create_initializer_compound(len);
+               /* we have to set the entry at the 2nd latest path entry... */
+               size_t path_len = ARR_LEN(path->path);
+               assert(path_len >= 1);
+               if(path_len > 1) {
+                       type_path_entry_t *entry        = & path->path[path_len-2];
+                       ir_initializer_t  *tinitializer = entry->initializer;
+                       set_initializer_compound_value(tinitializer, entry->index,
+                                                      initializer);
+               }
+       }
+       top->initializer = initializer;
+}
+
+static void ascend_from_subtype(type_path_t *path)
+{
+       type_path_entry_t *top = get_type_path_top(path);
+
+       path->top_type = top->type;
+
+       size_t len = ARR_LEN(path->path);
+       ARR_RESIZE(type_path_entry_t, path->path, len-1);
+}
+
+static void walk_designator(type_path_t *path, const designator_t *designator)
+{
+       /* designators start at current object type */
+       ARR_RESIZE(type_path_entry_t, path->path, 1);
+
+       for( ; designator != NULL; designator = designator->next) {
+               type_path_entry_t *top         = get_type_path_top(path);
+               type_t            *orig_type   = top->type;
+               type_t            *type        = skip_typeref(orig_type);
+
+               if(designator->symbol != NULL) {
+                       assert(is_type_compound(type));
+                       size_t    index  = 0;
+                       symbol_t *symbol = designator->symbol;
+
+                       declaration_t *declaration = type->compound.declaration;
+                       declaration_t *iter        = declaration->scope.declarations;
+                       for( ; iter != NULL; iter = iter->next, ++index) {
+                               if(iter->symbol == symbol) {
+                                       break;
+                               }
+                       }
+                       assert(iter != NULL);
+
+                       top->type           = orig_type;
+                       top->compound_entry = iter;
+                       top->index          = index;
+                       orig_type           = iter->type;
+               } else {
+                       expression_t *array_index = designator->array_index;
+                       assert(designator->array_index != NULL);
+                       assert(is_type_array(type));
+                       assert(is_type_valid(array_index->base.type));
+
+                       long index = fold_constant(array_index);
+                       assert(index >= 0);
+#ifndef NDEBUG
+                       if(type->array.size_constant == 1) {
+                               long array_size = type->array.size;
+                               assert(index < array_size);
+                       }
+#endif
+
+                       top->type  = orig_type;
+                       top->index = (size_t) index;
+                       orig_type  = type->array.element_type;
+               }
+               path->top_type = orig_type;
+
+               if(designator->next != NULL) {
+                       descend_into_subtype(path);
+               }
+       }
+
+       path->invalid  = false;
+}
+
+static void advance_current_object(type_path_t *path)
+{
+       if(path->invalid) {
+               /* TODO: handle this... */
+               panic("invalid initializer in ast2firm (excessive elements)");
+               return;
+       }
+
+       type_path_entry_t *top = get_type_path_top(path);
+
+       type_t *type = skip_typeref(top->type);
+       if(is_type_union(type)) {
+               top->compound_entry = NULL;
+       } else if(is_type_struct(type)) {
+               declaration_t *entry = top->compound_entry;
+
+               top->index++;
+               entry               = entry->next;
+               top->compound_entry = entry;
+               if(entry != NULL) {
+                       path->top_type = entry->type;
+                       return;
+               }
+       } else {
+               assert(is_type_array(type));
+
+               top->index++;
+               if(!type->array.size_constant || top->index < type->array.size) {
+                       return;
+               }
+       }
+
+       /* we're past the last member of the current sub-aggregate, try if we
+        * can ascend in the type hierarchy and continue with another subobject */
+       size_t len = ARR_LEN(path->path);
+
+       if(len > 1) {
+               ascend_from_subtype(path);
+               advance_current_object(path);
+       } else {
+               path->invalid = true;
+       }
+}
+
+
 static ir_initializer_t *create_ir_initializer(
-               const initializer_t *initializer);
+               const initializer_t *initializer, type_t *type);
 
 static ir_initializer_t *create_ir_initializer_value(
                const initializer_value_t *initializer)
@@ -2791,34 +3114,68 @@ static ir_initializer_t *create_ir_initializer_value(
        return create_initializer_const(value);
 }
 
-static ir_initializer_t *create_ir_initializer_compound(
-               const initializer_list_t *initializer)
+static ir_initializer_t *create_ir_initializer_list(
+               const initializer_list_t *initializer, type_t *type)
 {
-       ir_initializer_t *irinitializer
-               = create_initializer_compound(initializer->len);
+       type_path_t path;
+       memset(&path, 0, sizeof(path));
+       path.top_type = type;
+       path.path     = NEW_ARR_F(type_path_entry_t, 0);
+
+       descend_into_subtype(&path);
 
        for(size_t i = 0; i < initializer->len; ++i) {
-               const initializer_t *sub_initializer   = initializer->initializers[i];
-               ir_initializer_t    *sub_irinitializer
-                       = create_ir_initializer(sub_initializer);
+               const initializer_t *sub_initializer = initializer->initializers[i];
 
-               set_initializer_compound_value(irinitializer, i, sub_irinitializer);
+               if(sub_initializer->kind == INITIALIZER_DESIGNATOR) {
+                       walk_designator(&path, sub_initializer->designator.designator);
+                       continue;
+               }
+
+               if(sub_initializer->kind == INITIALIZER_VALUE) {
+                       /* we might have to descend into types until we're at a scalar
+                        * type */
+                       while(true) {
+                               type_t *orig_top_type = path.top_type;
+                               type_t *top_type      = skip_typeref(orig_top_type);
+
+                               if(is_type_scalar(top_type))
+                                       break;
+                               descend_into_subtype(&path);
+                       }
+               }
+
+               ir_initializer_t *sub_irinitializer
+                       = create_ir_initializer(sub_initializer, path.top_type);
+
+               size_t path_len = ARR_LEN(path.path);
+               assert(path_len >= 1);
+               type_path_entry_t *entry        = & path.path[path_len-1];
+               ir_initializer_t  *tinitializer = entry->initializer;
+               set_initializer_compound_value(tinitializer, entry->index,
+                                              sub_irinitializer);
+
+               advance_current_object(&path);
        }
 
-       return irinitializer;
+       assert(ARR_LEN(path.path) >= 1);
+       ir_initializer_t *result = path.path[0].initializer;
+       DEL_ARR_F(path.path);
+
+       return result;
 }
 
 static ir_initializer_t *create_ir_initializer_string(
                const initializer_string_t *initializer)
 {
-       size_t len = initializer->string.size;
+       size_t            len           = initializer->string.size;
        ir_initializer_t *irinitializer = create_initializer_compound(len);
 
        const char *string = initializer->string.begin;
        ir_mode    *mode   = get_type_mode(ir_type_const_char);
 
        for(size_t i = 0; i < len; ++i) {
-               tarval *tv = new_tarval_from_long(string[i], mode);
+               tarval           *tv = new_tarval_from_long(string[i], mode);
                ir_initializer_t *char_initializer = create_initializer_tarval(tv);
 
                set_initializer_compound_value(irinitializer, i, char_initializer);
@@ -2830,7 +3187,7 @@ static ir_initializer_t *create_ir_initializer_string(
 static ir_initializer_t *create_ir_initializer_wide_string(
                const initializer_wide_string_t *initializer)
 {
-       size_t len = initializer->string.size;
+       size_t            len           = initializer->string.size;
        ir_initializer_t *irinitializer = create_initializer_compound(len);
 
        const wchar_rep_t *string = initializer->string.begin;
@@ -2846,9 +3203,10 @@ static ir_initializer_t *create_ir_initializer_wide_string(
        return irinitializer;
 }
 
-static ir_initializer_t *create_ir_initializer(const initializer_t *initializer)
+static ir_initializer_t *create_ir_initializer(
+               const initializer_t *initializer, type_t *type)
 {
-       switch((initializer_kind_t) initializer->kind) {
+       switch(initializer->kind) {
                case INITIALIZER_STRING:
                        return create_ir_initializer_string(&initializer->string);
 
@@ -2856,36 +3214,38 @@ static ir_initializer_t *create_ir_initializer(const initializer_t *initializer)
                        return create_ir_initializer_wide_string(&initializer->wide_string);
 
                case INITIALIZER_LIST:
-                       return create_ir_initializer_compound(&initializer->list);
+                       return create_ir_initializer_list(&initializer->list, type);
 
                case INITIALIZER_VALUE:
                        return create_ir_initializer_value(&initializer->value);
+
+               case INITIALIZER_DESIGNATOR:
+                       panic("unexpected designator initializer found");
        }
        panic("unknown initializer");
 }
 
-static void create_initializer_local_variable_entity(declaration_t *declaration)
+
+static void create_local_initializer(initializer_t *initializer, dbg_info *dbgi,
+                                     ir_entity *entity, type_t *type)
 {
-       initializer_t *initializer = declaration->init.initializer;
-       dbg_info      *dbgi        = get_dbg_info(&declaration->source_position);
-       ir_entity     *entity      = declaration->v.entity;
-       ir_node       *memory      = get_store();
-       ir_node       *nomem       = new_NoMem();
-       ir_node       *frame       = get_irg_frame(current_ir_graph);
-       ir_node       *addr        = new_d_simpleSel(dbgi, nomem, frame, entity);
+       ir_node *memory = get_store();
+       ir_node *nomem  = new_NoMem();
+       ir_node *frame  = get_irg_frame(current_ir_graph);
+       ir_node *addr   = new_d_simpleSel(dbgi, nomem, frame, entity);
 
        if(initializer->kind == INITIALIZER_VALUE) {
                initializer_value_t *initializer_value = &initializer->value;
 
                ir_node *value = expression_to_firm(initializer_value->value);
-               type_t  *type  = skip_typeref(declaration->type);
+               type = skip_typeref(type);
                assign_value(dbgi, addr, type, value);
                return;
        }
 
        /* 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(declaration->type);
+       ir_type   *const irtype      = get_ir_type(type);
        ir_type   *const global_type = get_glob_type();
        ir_entity *const init_entity = new_d_entity(global_type, id, irtype, dbgi);
        set_entity_ld_ident(init_entity, id);
@@ -2897,7 +3257,7 @@ static void create_initializer_local_variable_entity(declaration_t *declaration)
        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);
+       ir_initializer_t *irinitializer = create_ir_initializer(initializer, type);
        set_entity_initializer(init_entity, irinitializer);
 
        assert(current_ir_graph == get_const_code_irg());
@@ -2910,6 +3270,15 @@ static void create_initializer_local_variable_entity(declaration_t *declaration)
        set_store(copyb_mem);
 }
 
+static void create_initializer_local_variable_entity(declaration_t *declaration)
+{
+       initializer_t *initializer = declaration->init.initializer;
+       dbg_info      *dbgi        = get_dbg_info(&declaration->source_position);
+       ir_entity     *entity      = declaration->v.entity;
+       type_t        *type        = declaration->type;
+       create_local_initializer(initializer, dbgi, entity, type);
+}
+
 static void create_declaration_initializer(declaration_t *declaration)
 {
        initializer_t *initializer = declaration->init.initializer;
@@ -2943,7 +3312,8 @@ static void create_declaration_initializer(declaration_t *declaration)
                                || declaration_kind == DECLARATION_KIND_GLOBAL_VARIABLE);
 
                ir_entity        *entity        = declaration->v.entity;
-               ir_initializer_t *irinitializer = create_ir_initializer(initializer);
+               ir_initializer_t *irinitializer
+                       = create_ir_initializer(initializer, declaration->type);
 
                set_entity_variability(entity, variability_initialized);
                set_entity_initializer(entity, irinitializer);
@@ -4123,13 +4493,13 @@ void init_ast2firm(void)
        }
 }
 
-void exit_ast2firm(void)
+static void init_ir_types(void)
 {
-       obstack_free(&asm_obst, NULL);
-}
+       static int ir_types_initialized = 0;
+       if(ir_types_initialized)
+               return;
+       ir_types_initialized = 1;
 
-void translation_unit_to_firm(translation_unit_t *unit)
-{
        type_const_char = make_atomic_type(ATOMIC_TYPE_CHAR, TYPE_QUALIFIER_CONST);
        type_void       = make_atomic_type(ATOMIC_TYPE_VOID, TYPE_QUALIFIER_NONE);
        type_int        = make_atomic_type(ATOMIC_TYPE_INT,  TYPE_QUALIFIER_NONE);
@@ -4141,11 +4511,21 @@ void translation_unit_to_firm(translation_unit_t *unit)
                                                       type in firm */
 
        type_void->base.firm_type = ir_type_void;
+}
 
+void exit_ast2firm(void)
+{
+       obstack_free(&asm_obst, NULL);
+}
+
+void translation_unit_to_firm(translation_unit_t *unit)
+{
        /* just to be sure */
        continue_label      = NULL;
        break_label         = NULL;
        current_switch_cond = NULL;
 
+       init_ir_types();
+
        scope_to_firm(&unit->scope);
 }
diff --git a/ast_t.h b/ast_t.h
index 41e86c7..34a03f5 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -20,6 +20,7 @@ typedef enum {
        EXPR_CHAR_CONST,
        EXPR_STRING_LITERAL,
        EXPR_WIDE_STRING_LITERAL,
+       EXPR_COMPOUND_LITERAL,
        EXPR_CALL,
        EXPR_CONDITIONAL,
        EXPR_SELECT,
@@ -183,6 +184,12 @@ struct wide_string_literal_expression_t {
        wide_string_t      value;
 };
 
+struct compound_literal_expression_t {
+       expression_base_t  base;
+       type_t            *type;
+       initializer_t     *initializer;
+};
+
 struct builtin_symbol_expression_t {
        expression_base_t  base;
        symbol_t          *symbol;
@@ -250,9 +257,10 @@ struct typeprop_expression_t {
 };
 
 struct designator_t {
-       symbol_t     *symbol;
-       expression_t *array_access;
-       designator_t *next;
+       source_position_t  source_position;
+       symbol_t          *symbol;
+       expression_t      *array_index;
+       designator_t      *next;
 };
 
 struct offsetof_expression_t {
@@ -295,6 +303,7 @@ union expression_t {
        const_expression_t               conste;
        string_literal_expression_t      string;
        wide_string_literal_expression_t wide_string;
+       compound_literal_expression_t    compound_literal;
        builtin_symbol_expression_t      builtin_symbol;
        builtin_constant_expression_t    builtin_constant;
        builtin_prefetch_expression_t    builtin_prefetch;
@@ -338,7 +347,8 @@ typedef enum {
        INITIALIZER_VALUE,
        INITIALIZER_LIST,
        INITIALIZER_STRING,
-       INITIALIZER_WIDE_STRING
+       INITIALIZER_WIDE_STRING,
+       INITIALIZER_DESIGNATOR
 } initializer_kind_t;
 
 struct initializer_base_t {
@@ -346,26 +356,31 @@ struct initializer_base_t {
 };
 
 struct initializer_value_t {
-       initializer_base_t  initializer;
+       initializer_base_t  base;
        expression_t       *value;
 };
 
 struct initializer_list_t {
-       initializer_base_t  initializer;
+       initializer_base_t  base;
        size_t              len;
        initializer_t      *initializers[];
 };
 
 struct initializer_string_t {
-       initializer_base_t initializer;
+       initializer_base_t base;
        string_t           string;
 };
 
 struct initializer_wide_string_t {
-       initializer_base_t  initializer;
+       initializer_base_t  base;
        wide_string_t       string;
 };
 
+struct initializer_designator_t {
+       initializer_base_t  base;
+       designator_t       *designator;
+};
+
 union initializer_t {
        initializer_kind_t        kind;
        initializer_base_t        base;
@@ -373,6 +388,7 @@ union initializer_t {
        initializer_list_t        list;
        initializer_string_t      string;
        initializer_wide_string_t wide_string;
+       initializer_designator_t  designator;
 };
 
 typedef enum {
diff --git a/lexer.c b/lexer.c
index 4b86a38..8cf2d71 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -1314,7 +1314,7 @@ static void parse_preprocessor_directive(void)
                parse_line_directive();
                break;
        case '\n':
-               /* NULL directive, see § 6.10.7 */
+               /* NULL directive, see Â§ 6.10.7 */
                break;
        default:
                parse_error("invalid preprocessor directive");
index 6ace4a7..bb29247 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -54,7 +54,7 @@ static goto_statement_t   *goto_first        = NULL;
 static goto_statement_t   *goto_last         = NULL;
 static label_statement_t  *label_first       = NULL;
 static label_statement_t  *label_last        = NULL;
-static struct obstack  temp_obst;
+static struct obstack      temp_obst;
 
 /** The current source position. */
 #define HERE token.source_position
@@ -201,6 +201,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_CHAR_CONST]          = sizeof(const_expression_t),
                [EXPR_STRING_LITERAL]      = sizeof(string_literal_expression_t),
                [EXPR_WIDE_STRING_LITERAL] = sizeof(wide_string_literal_expression_t),
+               [EXPR_COMPOUND_LITERAL]    = sizeof(compound_literal_expression_t),
                [EXPR_CALL]                = sizeof(call_expression_t),
                [EXPR_UNARY_FIRST]         = sizeof(unary_expression_t),
                [EXPR_BINARY_FIRST]        = sizeof(binary_expression_t),
@@ -297,7 +298,8 @@ static size_t get_initializer_size(initializer_kind_t kind)
                [INITIALIZER_VALUE]       = sizeof(initializer_value_t),
                [INITIALIZER_STRING]      = sizeof(initializer_string_t),
                [INITIALIZER_WIDE_STRING] = sizeof(initializer_wide_string_t),
-               [INITIALIZER_LIST]        = sizeof(initializer_list_t)
+               [INITIALIZER_LIST]        = sizeof(initializer_list_t),
+               [INITIALIZER_DESIGNATOR]  = sizeof(initializer_designator_t)
        };
        assert(kind < sizeof(sizes) / sizeof(*sizes));
        assert(sizes[kind] != 0);
@@ -469,28 +471,34 @@ static void eat_paren(void)
 }
 
 #define expect(expected)                           \
+       do {                                           \
     if(UNLIKELY(token.type != (expected))) {       \
         parse_error_expected(NULL, (expected), 0); \
         eat_statement();                           \
         return NULL;                               \
     }                                              \
-    next_token();
+    next_token();                                  \
+       } while(0)
 
 #define expect_block(expected)                     \
+       do {                                           \
     if(UNLIKELY(token.type != (expected))) {       \
         parse_error_expected(NULL, (expected), 0); \
         eat_block();                               \
         return NULL;                               \
     }                                              \
-    next_token();
+    next_token();                                  \
+       } while(0)
 
 #define expect_void(expected)                      \
+       do {                                           \
     if(UNLIKELY(token.type != (expected))) {       \
         parse_error_expected(NULL, (expected), 0); \
         eat_statement();                           \
         return;                                    \
     }                                              \
-    next_token();
+    next_token();                                  \
+    } while(0)
 
 static void set_scope(scope_t *new_scope)
 {
@@ -760,7 +768,8 @@ static type_t *semantic_assign(type_t *orig_type_left,
                return orig_type_left;
        }
 
-       if (is_type_compound(type_left)  && is_type_compound(type_right)) {
+       if ((is_type_compound(type_left)  && is_type_compound(type_right))
+                       || (is_type_builtin(type_left) && is_type_builtin(type_right))) {
                type_t *const unqual_type_left  = get_unqualified_type(type_left);
                type_t *const unqual_type_right = get_unqualified_type(type_right);
                if (types_compatible(unqual_type_left, unqual_type_right)) {
@@ -879,26 +888,24 @@ attributes_finished:
        ;
 }
 
-#if 0
 static designator_t *parse_designation(void)
 {
-       if(token.type != '[' && token.type != '.')
-               return NULL;
-
        designator_t *result = NULL;
        designator_t *last   = NULL;
 
-       while(1) {
+       while(true) {
                designator_t *designator;
                switch(token.type) {
                case '[':
                        designator = allocate_ast_zero(sizeof(designator[0]));
+                       designator->source_position = token.source_position;
                        next_token();
-                       designator->array_access = parse_constant_expression();
+                       designator->array_index = parse_constant_expression();
                        expect(']');
                        break;
                case '.':
                        designator = allocate_ast_zero(sizeof(designator[0]));
+                       designator->source_position = token.source_position;
                        next_token();
                        if(token.type != T_IDENTIFIER) {
                                parse_error_expected("while parsing designator",
@@ -922,7 +929,6 @@ static designator_t *parse_designation(void)
                last = designator;
        }
 }
-#endif
 
 static initializer_t *initializer_from_string(array_type_t *type,
                                               const string_t *const string)
@@ -949,13 +955,15 @@ static initializer_t *initializer_from_wide_string(array_type_t *const type,
        return initializer;
 }
 
-static initializer_t *initializer_from_expression(type_t *type,
+static initializer_t *initializer_from_expression(type_t *orig_type,
                                                   expression_t *expression)
 {
        /* TODO check that expression is a constant expression */
 
        /* § 6.7.8.14/15 char array may be initialized by string literals */
-       type_t *const expr_type = expression->base.type;
+       type_t *type           = skip_typeref(orig_type);
+       type_t *expr_type_orig = expression->base.type;
+       type_t *expr_type      = skip_typeref(expr_type_orig);
        if (is_type_array(type) && expr_type->kind == TYPE_POINTER) {
                array_type_t *const array_type   = &type->array;
                type_t       *const element_type = skip_typeref(array_type->element_type);
@@ -995,220 +1003,429 @@ static initializer_t *initializer_from_expression(type_t *type,
        return result;
 }
 
-static initializer_t *parse_sub_initializer(type_t *type,
-                                            expression_t *expression);
-
-static initializer_t *parse_sub_initializer_elem(type_t *type)
+static initializer_t *parse_scalar_initializer(type_t *type)
 {
-       if(token.type == '{') {
-               return parse_sub_initializer(type, NULL);
+       /* there might be extra {} hierarchies */
+       int braces = 0;
+       while(token.type == '{') {
+               next_token();
+               if(braces == 0) {
+                       warningf(HERE, "extra curly braces around scalar initializer");
+               }
+               braces++;
        }
 
-       expression_t *expression = parse_assignment_expression();
-       return parse_sub_initializer(type, expression);
-}
+       expression_t  *expression  = parse_assignment_expression();
+       initializer_t *initializer = initializer_from_expression(type, expression);
 
-static bool had_initializer_brace_warning;
+       if(initializer == NULL) {
+               errorf(expression->base.source_position,
+                      "expression '%E' doesn't match expected type '%T'",
+                      expression, type);
+               /* TODO */
+               return NULL;
+       }
 
-static void skip_designator(void)
-{
-       while(1) {
-               if(token.type == '.') {
+       bool additional_warning_displayed = false;
+       while(braces > 0) {
+               if(token.type == ',') {
                        next_token();
-                       if(token.type == T_IDENTIFIER)
-                               next_token();
-               } else if(token.type == '[') {
-                       next_token();
-                       parse_constant_expression();
-                       if(token.type == ']')
-                               next_token();
-               } else {
-                       break;
                }
+               if(token.type != '}') {
+                       if(!additional_warning_displayed) {
+                               warningf(HERE, "additional elements in scalar initializer");
+                               additional_warning_displayed = true;
+                       }
+               }
+               eat_block();
+               braces--;
        }
+
+       return initializer;
 }
 
-static initializer_t *parse_sub_initializer(type_t *type,
-                                            expression_t *expression)
+typedef struct type_path_entry_t type_path_entry_t;
+struct type_path_entry_t {
+       type_t *type;
+       union {
+               size_t         index;
+               declaration_t *compound_entry;
+       } v;
+};
+
+typedef struct type_path_t type_path_t;
+struct type_path_t {
+       type_path_entry_t *path;
+       type_t            *top_type;
+       bool               invalid;
+};
+
+static __attribute__((unused)) void debug_print_type_path(const type_path_t *path)
 {
-       if(is_type_scalar(type)) {
-               /* there might be extra {} hierarchies */
-               if(token.type == '{') {
-                       next_token();
-                       if(!had_initializer_brace_warning) {
-                               warningf(HERE, "braces around scalar initializer");
-                               had_initializer_brace_warning = true;
-                       }
-                       initializer_t *result = parse_sub_initializer(type, NULL);
-                       if(token.type == ',') {
-                               next_token();
-                               /* TODO: warn about excessive elements */
-                       }
-                       expect_block('}');
-                       return result;
-               }
+       size_t len = ARR_LEN(path->path);
 
-               if(expression == NULL) {
-                       expression = parse_assignment_expression();
+       if(path->invalid) {
+               fprintf(stderr, "invalid path");
+               return;
+       }
+
+       for(size_t i = 0; i < len; ++i) {
+               const type_path_entry_t *entry = & path->path[i];
+
+               type_t *type = skip_typeref(entry->type);
+               if(is_type_compound(type)) {
+                       fprintf(stderr, ".%s", entry->v.compound_entry->symbol->string);
+               } else if(is_type_array(type)) {
+                       fprintf(stderr, "[%u]", entry->v.index);
+               } else {
+                       fprintf(stderr, "-INVALID-");
                }
-               return initializer_from_expression(type, expression);
        }
+       fprintf(stderr, "  (");
+       print_type(path->top_type);
+       fprintf(stderr, ")");
+}
 
-       /* does the expression match the currently looked at object to initialize */
-       if(expression != NULL) {
-               initializer_t *result = initializer_from_expression(type, expression);
-               if(result != NULL)
-                       return result;
+static type_path_entry_t *get_type_path_top(const type_path_t *path)
+{
+       size_t len = ARR_LEN(path->path);
+       assert(len > 0);
+       return & path->path[len-1];
+}
+
+static type_path_entry_t *append_to_type_path(type_path_t *path)
+{
+       size_t len = ARR_LEN(path->path);
+       ARR_RESIZE(type_path_entry_t, path->path, len+1);
+
+       type_path_entry_t *result = & path->path[len];
+       memset(result, 0, sizeof(result[0]));
+       return result;
+}
+
+static void descend_into_subtype(type_path_t *path)
+{
+       type_t *orig_top_type = path->top_type;
+       type_t *top_type      = skip_typeref(orig_top_type);
+
+       assert(is_type_compound(top_type) || is_type_array(top_type));
+
+       type_path_entry_t *top = append_to_type_path(path);
+       top->type              = top_type;
+
+       if(is_type_compound(top_type)) {
+               declaration_t *declaration = top_type->compound.declaration;
+               declaration_t *entry       = declaration->scope.declarations;
+
+               top->v.compound_entry = entry;
+               path->top_type        = entry->type;
+       } else {
+               assert(is_type_array(top_type));
+
+               top->v.index   = 0;
+               path->top_type = top_type->array.element_type;
        }
+}
 
-       bool read_paren = false;
-       if(token.type == '{') {
-               next_token();
-               read_paren = true;
+static void ascend_from_subtype(type_path_t *path)
+{
+       type_path_entry_t *top = get_type_path_top(path);
+
+       path->top_type = top->type;
+
+       size_t len = ARR_LEN(path->path);
+       ARR_RESIZE(type_path_entry_t, path->path, len-1);
+}
+
+static void ascend_to(type_path_t *path, size_t top_path_level)
+{
+       size_t len = ARR_LEN(path->path);
+       assert(len >= top_path_level);
+
+       while(len > top_path_level) {
+               ascend_from_subtype(path);
+               len = ARR_LEN(path->path);
        }
+}
 
-       /* descend into subtype */
-       initializer_t  *result = NULL;
-       initializer_t **elems;
-       if(is_type_array(type)) {
-               if(token.type == '.') {
-                       errorf(HERE,
-                              "compound designator in initializer for array type '%T'",
-                              type);
-                       skip_designator();
-               }
+static bool walk_designator(type_path_t *path, const designator_t *designator,
+                            bool used_in_offsetof)
+{
+       for( ; designator != NULL; designator = designator->next) {
+               type_path_entry_t *top       = get_type_path_top(path);
+               type_t            *orig_type = top->type;
 
-               type_t *const element_type = skip_typeref(type->array.element_type);
+               type_t *type = skip_typeref(orig_type);
 
-               initializer_t *sub;
-               had_initializer_brace_warning = false;
+               if(designator->symbol != NULL) {
+                       symbol_t *symbol = designator->symbol;
+                       if(!is_type_compound(type)) {
+                               if(is_type_valid(type)) {
+                                       errorf(designator->source_position,
+                                              "'.%Y' designator used for non-compound type '%T'",
+                                              symbol, orig_type);
+                               }
+                               goto failed;
+                       }
 
-               if(token.type == '{') {
-                       sub = parse_sub_initializer(element_type, NULL);
+                       declaration_t *declaration = type->compound.declaration;
+                       declaration_t *iter        = declaration->scope.declarations;
+                       for( ; iter != NULL; iter = iter->next) {
+                               if(iter->symbol == symbol) {
+                                       break;
+                               }
+                       }
+                       if(iter == NULL) {
+                               errorf(designator->source_position,
+                                      "'%T' has no member named '%Y'", orig_type, symbol);
+                               goto failed;
+                       }
+                       if(used_in_offsetof) {
+                               type_t *real_type = skip_typeref(iter->type);
+                               if(real_type->kind == TYPE_BITFIELD) {
+                                       errorf(designator->source_position,
+                                              "offsetof designator '%Y' may not specify bitfield",
+                                              symbol);
+                                       goto failed;
+                               }
+                       }
+
+                       top->type             = orig_type;
+                       top->v.compound_entry = iter;
+                       orig_type             = iter->type;
                } else {
-                       if(expression == NULL) {
-                               expression = parse_assignment_expression();
-
-                               /* 6.7.8.14 + 15: we can have an optional {} around the string
-                                * literal */
-                               if(read_paren && (expression->kind == EXPR_STRING_LITERAL
-                                               || expression->kind == EXPR_WIDE_STRING_LITERAL)) {
-                                       initializer_t *result
-                                               = initializer_from_expression(type, expression);
-                                       if(result != NULL) {
-                                               expect_block('}');
-                                               return result;
+                       expression_t *array_index = designator->array_index;
+                       assert(designator->array_index != NULL);
+
+                       if(!is_type_array(type)) {
+                               if(is_type_valid(type)) {
+                                       errorf(designator->source_position,
+                                              "[%E] designator used for non-array type '%T'",
+                                              array_index, orig_type);
+                               }
+                               goto failed;
+                       }
+                       if(!is_type_valid(array_index->base.type)) {
+                               goto failed;
+                       }
+
+                       long index = fold_constant(array_index);
+                       if(!used_in_offsetof) {
+                               if(index < 0) {
+                                       errorf(designator->source_position,
+                                              "array index [%E] must be positive", array_index);
+                                       goto failed;
+                               }
+                               if(type->array.size_constant == true) {
+                                       long array_size = type->array.size;
+                                       if(index >= array_size) {
+                                               errorf(designator->source_position,
+                                                               "designator [%E] (%d) exceeds array size %d",
+                                                               array_index, index, array_size);
+                                               goto failed;
                                        }
                                }
                        }
 
-                       sub = parse_sub_initializer(element_type, expression);
+                       top->type    = orig_type;
+                       top->v.index = (size_t) index;
+                       orig_type    = type->array.element_type;
                }
+               path->top_type = orig_type;
 
-               /* didn't match the subtypes -> try the parent type */
-               if(sub == NULL) {
-                       assert(!read_paren);
-                       return NULL;
+               if(designator->next != NULL) {
+                       descend_into_subtype(path);
                }
+       }
 
-               elems = NEW_ARR_F(initializer_t*, 0);
-               ARR_APP1(initializer_t*, elems, sub);
+       path->invalid  = false;
+       return true;
 
-               while(true) {
-                       if(token.type == '}')
-                               break;
-                       expect_block(',');
-                       if(token.type == '}')
-                               break;
+failed:
+       return false;
+}
 
-                       sub = parse_sub_initializer_elem(element_type);
-                       if(sub == NULL) {
-                               /* TODO error, do nicer cleanup */
-                               errorf(HERE, "member initializer didn't match");
-                               DEL_ARR_F(elems);
-                               return NULL;
-                       }
-                       ARR_APP1(initializer_t*, elems, sub);
+static void advance_current_object(type_path_t *path, size_t top_path_level)
+{
+       if(path->invalid)
+               return;
+
+       type_path_entry_t *top = get_type_path_top(path);
+
+       type_t *type = skip_typeref(top->type);
+       if(is_type_union(type)) {
+               /* in unions only the first element is initialized */
+               top->v.compound_entry = NULL;
+       } else if(is_type_struct(type)) {
+               declaration_t *entry = top->v.compound_entry;
+
+               entry                 = entry->next;
+               top->v.compound_entry = entry;
+               if(entry != NULL) {
+                       path->top_type = entry->type;
+                       return;
                }
        } else {
-               assert(is_type_compound(type));
-               scope_t *const scope = &type->compound.declaration->scope;
+               assert(is_type_array(type));
 
-               if(token.type == '[') {
-                       errorf(HERE,
-                              "array designator in initializer for compound type '%T'",
-                              type);
-                       skip_designator();
+               top->v.index++;
+
+               if(!type->array.size_constant || top->v.index < type->array.size) {
+                       return;
                }
+       }
 
-               declaration_t *first = scope->declarations;
-               if(first == NULL)
-                       return NULL;
-               type_t *first_type = first->type;
-               first_type         = skip_typeref(first_type);
+       /* we're past the last member of the current sub-aggregate, try if we
+        * can ascend in the type hierarchy and continue with another subobject */
+       size_t len = ARR_LEN(path->path);
 
-               initializer_t *sub;
-               had_initializer_brace_warning = false;
-               if(expression == NULL) {
-                       sub = parse_sub_initializer_elem(first_type);
-               } else {
-                       sub = parse_sub_initializer(first_type, expression);
+       if(len > top_path_level) {
+               ascend_from_subtype(path);
+               advance_current_object(path, top_path_level);
+       } else {
+               path->invalid = true;
+       }
+}
+
+static void skip_initializers(void)
+{
+       if(token.type == '{')
+               next_token();
+
+       while(token.type != '}') {
+               if(token.type == T_EOF)
+                       return;
+               if(token.type == '{') {
+                       eat_block();
+                       continue;
                }
+               next_token();
+       }
+}
+
+static initializer_t *parse_sub_initializer(type_path_t *path,
+               type_t *outer_type, size_t top_path_level)
+{
+       type_t *orig_type = path->top_type;
+       type_t *type      = skip_typeref(orig_type);
 
-               /* didn't match the subtypes -> try our parent type */
-               if(sub == NULL) {
-                       assert(!read_paren);
-                       return NULL;
+       /* we can't do usefull stuff if we didn't even parse the type. Skip the
+        * initializers in this case. */
+       if(!is_type_valid(type)) {
+               skip_initializers();
+               return NULL;
+       }
+
+       initializer_t **initializers = NEW_ARR_F(initializer_t*, 0);
+
+       while(true) {
+               designator_t *designator = NULL;
+               if(token.type == '.' || token.type == '[') {
+                       designator = parse_designation();
+
+                       /* reset path to toplevel, evaluate designator from there */
+                       ascend_to(path, top_path_level);
+                       if(!walk_designator(path, designator, false)) {
+                               /* can't continue after designation error */
+                               goto end_error;
+                       }
+
+                       initializer_t *designator_initializer
+                               = allocate_initializer_zero(INITIALIZER_DESIGNATOR);
+                       designator_initializer->designator.designator = designator;
+                       ARR_APP1(initializer_t*, initializers, designator_initializer);
                }
 
-               elems = NEW_ARR_F(initializer_t*, 0);
-               ARR_APP1(initializer_t*, elems, sub);
+               initializer_t *sub;
 
-               declaration_t *iter  = first->next;
-               for( ; iter != NULL; iter = iter->next) {
-                       if(iter->symbol == NULL)
-                               continue;
-                       if(iter->namespc != NAMESPACE_NORMAL)
-                               continue;
+               if(token.type == '{') {
+                       if(is_type_scalar(type)) {
+                               sub = parse_scalar_initializer(type);
+                       } else {
+                               eat('{');
+                               descend_into_subtype(path);
 
-                       if(token.type == '}')
-                               break;
-                       expect_block(',');
-                       if(token.type == '}')
-                               break;
+                               sub = parse_sub_initializer(path, orig_type, top_path_level+1);
 
-                       type_t *iter_type = iter->type;
-                       iter_type         = skip_typeref(iter_type);
+                               ascend_from_subtype(path);
 
-                       sub = parse_sub_initializer_elem(iter_type);
-                       if(sub == NULL) {
-                               /* TODO error, do nicer cleanup */
-                               errorf(HERE, "member initializer didn't match");
-                               DEL_ARR_F(elems);
-                               return NULL;
+                               expect_block('}');
+                       }
+               } else {
+                       /* must be an expression */
+                       expression_t *expression = parse_assignment_expression();
+
+                       /* handle { "string" } special case */
+                       if((expression->kind == EXPR_STRING_LITERAL
+                                       || expression->kind == EXPR_WIDE_STRING_LITERAL)
+                                       && outer_type != NULL) {
+                               sub = initializer_from_expression(outer_type, expression);
+                               if(sub != NULL) {
+                                       if(token.type == ',') {
+                                               next_token();
+                                       }
+                                       if(token.type != '}') {
+                                               warningf(HERE, "excessive elements in initializer for type '%T'",
+                                                                orig_type);
+                                       }
+                                       /* TODO: eat , ... */
+                                       return sub;
+                               }
+                       }
+
+                       /* descend into subtypes until expression matches type */
+                       while(true) {
+                               orig_type = path->top_type;
+                               type      = skip_typeref(orig_type);
+
+                               sub = initializer_from_expression(orig_type, expression);
+                               if(sub != NULL) {
+                                       break;
+                               }
+                               if(!is_type_valid(type)) {
+                                       goto end_error;
+                               }
+                               if(is_type_scalar(type)) {
+                                       errorf(expression->base.source_position,
+                                                       "expression '%E' doesn't match expected type '%T'",
+                                                       expression, orig_type);
+                                       goto end_error;
+                               }
+
+                               descend_into_subtype(path);
                        }
-                       ARR_APP1(initializer_t*, elems, sub);
                }
-       }
+               ARR_APP1(initializer_t*, initializers, sub);
 
-       int    len        = ARR_LEN(elems);
-       size_t elems_size = sizeof(initializer_t*) * len;
+               if(token.type == '}') {
+                       break;
+               }
+               expect(',');
+               if(token.type == '}') {
+                       break;
+               }
+               advance_current_object(path, top_path_level);
+       }
 
-       initializer_list_t *init = allocate_ast_zero(sizeof(init[0]) + elems_size);
+       size_t len  = ARR_LEN(initializers);
+       size_t size = sizeof(initializer_list_t) + len * sizeof(initializers[0]);
+       initializer_t *result = allocate_ast_zero(size);
+       result->kind          = INITIALIZER_LIST;
+       result->list.len      = len;
+       memcpy(&result->list.initializers, initializers,
+              len * sizeof(initializers[0]));
 
-       init->initializer.kind = INITIALIZER_LIST;
-       init->len              = len;
-       memcpy(init->initializers, elems, elems_size);
-       DEL_ARR_F(elems);
+       ascend_to(path, top_path_level);
 
-       result = (initializer_t*) init;
+       /* TODO: if(is_global && !is_constant(...)) { error } */
 
-       if(read_paren) {
-               if(token.type == ',')
-                       next_token();
-               expect('}');
-       }
        return result;
+
+end_error:
+       skip_initializers();
+       DEL_ARR_F(initializers);
+       ascend_to(path, top_path_level);
+       return NULL;
 }
 
 static initializer_t *parse_initializer(type_t *const orig_type)
@@ -1229,19 +1446,31 @@ static initializer_t *parse_initializer(type_t *const orig_type)
        }
 
        if(is_type_scalar(type)) {
-               /* § 6.7.8.11 */
-               eat('{');
+               /* TODO: § 6.7.8.11; eat {} without warning */
 
-               expression_t *expression = parse_assignment_expression();
-               result = initializer_from_expression(type, expression);
+               result = parse_scalar_initializer(type);
 
                if(token.type == ',')
                        next_token();
 
-               expect('}');
                return result;
+       } else if(token.type == '{') {
+               next_token();
+
+               type_path_t path;
+               memset(&path, 0, sizeof(path));
+               path.top_type = orig_type;
+               path.path     = NEW_ARR_F(type_path_entry_t, 0);
+
+               descend_into_subtype(&path);
+
+               result = parse_sub_initializer(&path, orig_type, 1);
+
+               DEL_ARR_F(path.path);
+
+               expect('}');
        } else {
-               result = parse_sub_initializer(type, NULL);
+               /* TODO ... */
        }
 
        return result;
@@ -2204,11 +2433,20 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                        parsed_array_t *parsed_array  = (parsed_array_t*) iter;
                        type_t         *array_type    = allocate_type_zero(TYPE_ARRAY, (source_position_t){NULL, 0});
 
-                       array_type->base.qualifiers    = parsed_array->type_qualifiers;
-                       array_type->array.element_type = type;
-                       array_type->array.is_static    = parsed_array->is_static;
-                       array_type->array.is_variable  = parsed_array->is_variable;
-                       array_type->array.size         = parsed_array->size;
+                       expression_t *size_expression = parsed_array->size;
+
+                       array_type->base.qualifiers       = parsed_array->type_qualifiers;
+                       array_type->array.element_type    = type;
+                       array_type->array.is_static       = parsed_array->is_static;
+                       array_type->array.is_variable     = parsed_array->is_variable;
+                       array_type->array.size_expression = size_expression;
+
+                       if(size_expression != NULL &&
+                                       is_constant_expression(size_expression)) {
+                               array_type->array.size_constant = true;
+                               array_type->array.size
+                                       = fold_constant(size_expression);
+                       }
 
                        type_t *skipped_type = skip_typeref(type);
                        if (is_type_atomic(skipped_type, ATOMIC_TYPE_VOID)) {
@@ -2536,33 +2774,38 @@ static void parse_init_declarator_rest(declaration_t *declaration)
        if(is_type_array(type) && initializer != NULL) {
                array_type_t *array_type = &type->array;
 
-               if(array_type->size == NULL) {
-                       expression_t *cnst = allocate_expression_zero(EXPR_CONST);
-
-                       cnst->base.type = type_size_t;
-
+               if(array_type->size_expression == NULL) {
+                       size_t size;
                        switch (initializer->kind) {
                                case INITIALIZER_LIST: {
-                                       cnst->conste.v.int_value = initializer->list.len;
+                                       /* TODO */
+                                       size = initializer->list.len;
                                        break;
                                }
 
                                case INITIALIZER_STRING: {
-                                       cnst->conste.v.int_value = initializer->string.string.size;
+                                       size = initializer->string.string.size;
                                        break;
                                }
 
                                case INITIALIZER_WIDE_STRING: {
-                                       cnst->conste.v.int_value = initializer->wide_string.string.size;
+                                       size = initializer->wide_string.string.size;
                                        break;
                                }
 
-                               default:
+                               default: {
                                        panic("invalid initializer type");
+                                       break;
+                               }
                        }
 
-                       array_type->size              = cnst;
-                       array_type->has_implicit_size = true;
+                       expression_t *cnst       = allocate_expression_zero(EXPR_CONST);
+                       cnst->base.type          = type_size_t;
+                       cnst->conste.v.int_value = size;
+
+                       array_type->size_expression = cnst;
+                       array_type->size_constant   = true;
+                       array_type->size            = size;
                }
        }
 
@@ -3442,15 +3685,32 @@ static void check_cast_allowed(expression_t *expression, type_t *dest_type)
        /* TODO check if explicit cast is allowed and issue warnings/errors */
 }
 
-static expression_t *parse_cast(void)
+static expression_t *parse_compound_literal(type_t *type)
 {
-       expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
+       expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
+
+       expression->compound_literal.type        = type;
+       expression->compound_literal.initializer = parse_initializer(type);
+       expression->base.type                    = automatic_type_conversion(type);
 
-       cast->base.source_position = token.source_position;
+       return expression;
+}
+
+static expression_t *parse_cast(void)
+{
+       source_position_t source_position = token.source_position;
 
        type_t *type  = parse_typename();
 
        expect(')');
+
+       if(token.type == '{') {
+               return parse_compound_literal(type);
+       }
+
+       expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
+       cast->base.source_position = source_position;
+
        expression_t *value = parse_sub_expression(20);
 
        check_cast_allowed(value, type);
@@ -3545,7 +3805,8 @@ static expression_t *parse_pretty_function_keyword(void)
 
 static designator_t *parse_designator(void)
 {
-       designator_t *result = allocate_ast_zero(sizeof(result[0]));
+       designator_t *result    = allocate_ast_zero(sizeof(result[0]));
+       result->source_position = HERE;
 
        if(token.type != T_IDENTIFIER) {
                parse_error_expected("while parsing member designator",
@@ -3566,8 +3827,9 @@ static designator_t *parse_designator(void)
                                eat_paren();
                                return NULL;
                        }
-                       designator_t *designator = allocate_ast_zero(sizeof(result[0]));
-                       designator->symbol       = token.v.symbol;
+                       designator_t *designator    = allocate_ast_zero(sizeof(result[0]));
+                       designator->source_position = HERE;
+                       designator->symbol          = token.v.symbol;
                        next_token();
 
                        last_designator->next = designator;
@@ -3576,9 +3838,10 @@ static designator_t *parse_designator(void)
                }
                if(token.type == '[') {
                        next_token();
-                       designator_t *designator = allocate_ast_zero(sizeof(result[0]));
-                       designator->array_access = parse_expression();
-                       if(designator->array_access == NULL) {
+                       designator_t *designator    = allocate_ast_zero(sizeof(result[0]));
+                       designator->source_position = HERE;
+                       designator->array_index     = parse_expression();
+                       if(designator->array_index == NULL) {
                                eat_paren();
                                return NULL;
                        }
@@ -3602,11 +3865,27 @@ static expression_t *parse_offsetof(void)
        expression->base.type    = type_size_t;
 
        expect('(');
-       expression->offsetofe.type = parse_typename();
+       type_t *type = parse_typename();
        expect(',');
-       expression->offsetofe.designator = parse_designator();
+       designator_t *designator = parse_designator();
        expect(')');
 
+       expression->offsetofe.type       = type;
+       expression->offsetofe.designator = designator;
+
+       type_path_t path;
+       memset(&path, 0, sizeof(path));
+       path.top_type = type;
+       path.path     = NEW_ARR_F(type_path_entry_t, 0);
+
+       descend_into_subtype(&path);
+
+       if(!walk_designator(&path, designator, true)) {
+               return create_invalid_expression();
+       }
+
+       DEL_ARR_F(path.path);
+
        return expression;
 }
 
@@ -4761,6 +5040,7 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_VA_START:                  return true;
                case EXPR_VA_ARG:                    return true;
                case EXPR_STATEMENT:                 return true; // TODO
+               case EXPR_COMPOUND_LITERAL:          return false;
 
                case EXPR_UNARY_NEGATE:              return false;
                case EXPR_UNARY_PLUS:                return false;
index 9ea809e..720365d 100644 (file)
--- a/parser.h
+++ b/parser.h
@@ -14,10 +14,4 @@ translation_unit_t *parse(void);
 type_t *revert_automatic_type_conversion(const expression_t *expression);
 declaration_t *expr_is_variable(const expression_t *expression);
 
-/* some builtin types */
-extern type_t *type_wchar_t;
-extern type_t *type_size_t;
-extern type_t *type_ptrdiff_t;
-extern type_t *type_wchar_ptr_t;
-
 #endif
diff --git a/parsetest/compoundlit.c b/parsetest/compoundlit.c
new file mode 100644 (file)
index 0000000..f267b34
--- /dev/null
@@ -0,0 +1,15 @@
+int puts(const char *str);
+
+struct bla {
+       int a;
+       float b;
+       char c[20];
+};
+
+int main(void)
+{
+       struct bla a;
+       a = (struct bla) { 4, 5.2, "Hello" };
+       puts(a.c);
+       return 0;
+}
diff --git a/parsetest/offsetof.c b/parsetest/offsetof.c
new file mode 100644 (file)
index 0000000..794b6f0
--- /dev/null
@@ -0,0 +1,17 @@
+struct A {
+       int k;
+       struct B {
+               int a, b[4];
+       } blup[2];
+       struct C {
+               int a : 5;
+               int b : 3;
+       } c;
+};
+
+int k = __builtin_offsetof(struct A, blup[2].b[3]);
+
+int main(void)
+{
+       return k == 0;
+}
diff --git a/parsetest/shouldfail/offsetof.c b/parsetest/shouldfail/offsetof.c
new file mode 100644 (file)
index 0000000..dc0ef92
--- /dev/null
@@ -0,0 +1,18 @@
+struct A {
+       int k;
+       struct B {
+               int a, b[4];
+       } blup[2];
+       struct C {
+               int a : 5;
+               int b : 3;
+       } c;
+};
+
+int k = __builtin_offsetof(struct A, blup[2].b[3]);
+int k2 = __builtin_offsetof(struct A, c.b);
+
+int main(void)
+{
+       return k == 0;
+}
diff --git a/type.c b/type.c
index e7ceb05..4cf3d74 100644 (file)
--- a/type.c
+++ b/type.c
@@ -190,9 +190,9 @@ static void print_array_type_post(const array_type_t *type)
                fputs("static ", out);
        }
        print_type_qualifiers(type->type.qualifiers);
-       if(type->size != NULL
+       if(type->size_expression != NULL
                        && (print_implicit_array_size || !type->has_implicit_size)) {
-               print_expression(type->size);
+               print_expression(type->size_expression);
        }
        fputc(']', out);
        intern_print_type_post(type->element_type, false);
@@ -708,7 +708,7 @@ bool is_type_incomplete(const type_t *type)
                return true;
 
        case TYPE_ARRAY:
-               return type->array.size == NULL;
+               return type->array.size_expression == NULL;
 
        case TYPE_ATOMIC:
                return type->atomic.akind == ATOMIC_TYPE_VOID;
@@ -780,12 +780,10 @@ static bool array_types_compatible(const array_type_t *array1,
        if(!types_compatible(element_type1, element_type2))
                return false;
 
-       if(array1->size != NULL && array2->size != NULL) {
-               /* TODO: check if size expression evaluate to the same value
-                * if they are constant */
-       }
+       if(!array1->size_constant || !array2->size_constant)
+               return true;
 
-       return true;
+       return array1->size == array2->size;
 }
 
 /**
index f745e4f..e72dd38 100644 (file)
--- a/type_t.h
+++ b/type_t.h
@@ -97,10 +97,12 @@ struct pointer_type_t {
 struct array_type_t {
        type_base_t   type;
        type_t       *element_type;
-       expression_t *size;
+       expression_t *size_expression;
+       size_t        size;
        unsigned      is_static         : 1;
        unsigned      is_variable       : 1;
        unsigned      has_implicit_size : 1;
+       unsigned      size_constant     : 1;
 };
 
 struct function_parameter_t {
@@ -205,6 +207,24 @@ static inline bool is_type_function(const type_t *type)
        return type->kind == TYPE_FUNCTION;
 }
 
+static inline bool is_type_union(const type_t *type)
+{
+       assert(!is_typeref(type));
+       return type->kind == TYPE_COMPOUND_UNION;
+}
+
+static inline bool is_type_struct(const type_t *type)
+{
+       assert(!is_typeref(type));
+       return type->kind == TYPE_COMPOUND_STRUCT;
+}
+
+static inline bool is_type_builtin(const type_t *type)
+{
+       assert(!is_typeref(type));
+       return type->kind == TYPE_BUILTIN;
+}
+
 static inline bool is_type_compound(const type_t *type)
 {
        assert(!is_typeref(type));
diff --git a/types.h b/types.h
index b51501e..9561ea3 100644 (file)
--- a/types.h
+++ b/types.h
@@ -36,6 +36,7 @@ extern type_t *type_ssize_t;
 extern type_t *type_uintmax_t;
 extern type_t *type_uptrdiff_t;
 extern type_t *type_wchar_t;
+extern type_t *type_wchar_ptr_t;
 extern type_t *type_wint_t;
 
 extern type_t *type_intmax_t_ptr;