removed set_opt_overflow_unsafe_transform(), not needed anymore
[cparser] / parser.c
index b85ac28..3323840 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1,13 +1,33 @@
+/*
+ * This file is part of cparser.
+ * Copyright (C) 2007-2008 Matthias Braun <matze@braunis.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
 #include <config.h>
 
 #include <assert.h>
 #include <stdarg.h>
 #include <stdbool.h>
 
+#include "parser.h"
 #include "diagnostic.h"
 #include "format_check.h"
-#include "parser.h"
 #include "lexer.h"
+#include "symbol_t.h"
 #include "token_t.h"
 #include "types.h"
 #include "type_t.h"
@@ -31,7 +51,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;
@@ -195,31 +215,32 @@ static statement_t *allocate_statement_zero(statement_kind_t kind)
 static size_t get_expression_struct_size(expression_kind_t kind)
 {
        static const size_t sizes[] = {
-               [EXPR_INVALID]             = sizeof(expression_base_t),
-               [EXPR_REFERENCE]           = sizeof(reference_expression_t),
-               [EXPR_CONST]               = sizeof(const_expression_t),
-               [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),
-               [EXPR_CONDITIONAL]         = sizeof(conditional_expression_t),
-               [EXPR_SELECT]              = sizeof(select_expression_t),
-               [EXPR_ARRAY_ACCESS]        = sizeof(array_access_expression_t),
-               [EXPR_SIZEOF]              = sizeof(typeprop_expression_t),
-               [EXPR_ALIGNOF]             = sizeof(typeprop_expression_t),
-               [EXPR_CLASSIFY_TYPE]       = sizeof(classify_type_expression_t),
-               [EXPR_FUNCTION]            = sizeof(string_literal_expression_t),
-               [EXPR_PRETTY_FUNCTION]     = sizeof(string_literal_expression_t),
-               [EXPR_BUILTIN_SYMBOL]      = sizeof(builtin_symbol_expression_t),
-               [EXPR_BUILTIN_CONSTANT_P]  = sizeof(builtin_constant_expression_t),
-               [EXPR_BUILTIN_PREFETCH]    = sizeof(builtin_prefetch_expression_t),
-               [EXPR_OFFSETOF]            = sizeof(offsetof_expression_t),
-               [EXPR_VA_START]            = sizeof(va_start_expression_t),
-               [EXPR_VA_ARG]              = sizeof(va_arg_expression_t),
-               [EXPR_STATEMENT]           = sizeof(statement_expression_t),
+               [EXPR_INVALID]                 = sizeof(expression_base_t),
+               [EXPR_REFERENCE]               = sizeof(reference_expression_t),
+               [EXPR_CONST]                   = sizeof(const_expression_t),
+               [EXPR_CHARACTER_CONSTANT]      = sizeof(const_expression_t),
+               [EXPR_WIDE_CHARACTER_CONSTANT] = 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),
+               [EXPR_CONDITIONAL]             = sizeof(conditional_expression_t),
+               [EXPR_SELECT]                  = sizeof(select_expression_t),
+               [EXPR_ARRAY_ACCESS]            = sizeof(array_access_expression_t),
+               [EXPR_SIZEOF]                  = sizeof(typeprop_expression_t),
+               [EXPR_ALIGNOF]                 = sizeof(typeprop_expression_t),
+               [EXPR_CLASSIFY_TYPE]           = sizeof(classify_type_expression_t),
+               [EXPR_FUNCTION]                = sizeof(string_literal_expression_t),
+               [EXPR_PRETTY_FUNCTION]         = sizeof(string_literal_expression_t),
+               [EXPR_BUILTIN_SYMBOL]          = sizeof(builtin_symbol_expression_t),
+               [EXPR_BUILTIN_CONSTANT_P]      = sizeof(builtin_constant_expression_t),
+               [EXPR_BUILTIN_PREFETCH]        = sizeof(builtin_prefetch_expression_t),
+               [EXPR_OFFSETOF]                = sizeof(offsetof_expression_t),
+               [EXPR_VA_START]                = sizeof(va_start_expression_t),
+               [EXPR_VA_ARG]                  = sizeof(va_arg_expression_t),
+               [EXPR_STATEMENT]               = sizeof(statement_expression_t),
        };
        if(kind >= EXPR_UNARY_FIRST && kind <= EXPR_UNARY_LAST) {
                return sizes[EXPR_UNARY_FIRST];
@@ -457,6 +478,10 @@ static void eat_paren(void)
                if(token.type == ')' || token.type == ';' || token.type == '}') {
                        return;
                }
+               if(token.type == ')') {
+                       next_token();
+                       return;
+               }
                if(token.type == '(') {
                        eat_paren();
                        continue;
@@ -467,7 +492,6 @@ static void eat_paren(void)
                }
                next_token();
        }
-       eat(')');
 }
 
 #define expect(expected)                           \
@@ -514,7 +538,8 @@ static void set_scope(scope_t *new_scope)
  * Search a symbol in a given namespace and returns its declaration or
  * NULL if this symbol was not found.
  */
-static declaration_t *get_declaration(const symbol_t *const symbol, const namespace_t namespc)
+static declaration_t *get_declaration(const symbol_t *const symbol,
+                                      const namespace_t namespc)
 {
        declaration_t *declaration = symbol->declaration;
        for( ; declaration != NULL; declaration = declaration->symbol_next) {
@@ -809,11 +834,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,7 +1029,14 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
        return result;
 }
 
-static initializer_t *parse_scalar_initializer(type_t *type)
+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)
 {
        /* there might be extra {} hierarchies */
        int braces = 0;
@@ -1015,7 +1048,13 @@ static initializer_t *parse_scalar_initializer(type_t *type)
                braces++;
        }
 
-       expression_t  *expression  = parse_assignment_expression();
+       expression_t *expression = parse_assignment_expression();
+       if(must_be_constant && !is_initializer_constant(expression)) {
+               errorf(expression->base.source_position,
+                      "Initialisation expression '%E' is not constant\n",
+                      expression);
+       }
+
        initializer_t *initializer = initializer_from_expression(type, expression);
 
        if(initializer == NULL) {
@@ -1056,11 +1095,13 @@ struct type_path_entry_t {
 typedef struct type_path_t type_path_t;
 struct type_path_t {
        type_path_entry_t *path;
-       type_t            *top_type;
+       type_t            *top_type;     /**< type of the element the path points */
+       size_t             max_index;    /**< largest index in outermost array */
        bool               invalid;
 };
 
-static __attribute__((unused)) void debug_print_type_path(const type_path_t *path)
+static __attribute__((unused)) void debug_print_type_path(
+               const type_path_t *path)
 {
        size_t len = ARR_LEN(path->path);
 
@@ -1304,7 +1345,7 @@ static void skip_initializers(void)
 }
 
 static initializer_t *parse_sub_initializer(type_path_t *path,
-               type_t *outer_type, size_t top_path_level)
+               type_t *outer_type, size_t top_path_level, bool must_be_constant)
 {
        type_t *orig_type = path->top_type;
        type_t *type      = skip_typeref(orig_type);
@@ -1340,12 +1381,13 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
 
                if(token.type == '{') {
                        if(is_type_scalar(type)) {
-                               sub = parse_scalar_initializer(type);
+                               sub = parse_scalar_initializer(type, must_be_constant);
                        } else {
                                eat('{');
                                descend_into_subtype(path);
 
-                               sub = parse_sub_initializer(path, orig_type, top_path_level+1);
+                               sub = parse_sub_initializer(path, orig_type, top_path_level+1,
+                                                           must_be_constant);
 
                                ascend_from_subtype(path);
 
@@ -1355,6 +1397,12 @@ 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_initializer_constant(expression)) {
+                               errorf(expression->base.source_position,
+                                      "Initialisation expression '%E' is not constant\n",
+                                      expression);
+                       }
+
                        /* handle { "string" } special case */
                        if((expression->kind == EXPR_STRING_LITERAL
                                        || expression->kind == EXPR_WIDE_STRING_LITERAL)
@@ -1395,6 +1443,18 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                                descend_into_subtype(path);
                        }
                }
+
+               /* update largest index of top array */
+               const type_path_entry_t *first      = &path->path[0];
+               type_t                  *first_type = first->type;
+               first_type                          = skip_typeref(first_type);
+               if(is_type_array(first_type)) {
+                       size_t index = first->v.index;
+                       if(index > path->max_index)
+                               path->max_index = index;
+               }
+
+               /* append to initializers list */
                ARR_APP1(initializer_t*, initializers, sub);
 
                if(token.type == '}') {
@@ -1404,7 +1464,10 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                if(token.type == '}') {
                        break;
                }
+
                advance_current_object(path, top_path_level);
+               orig_type = path->top_type;
+               type      = skip_typeref(orig_type);
        }
 
        size_t len  = ARR_LEN(initializers);
@@ -1417,8 +1480,6 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
 
        ascend_to(path, top_path_level);
 
-       /* TODO: if(is_global && !is_constant(...)) { error } */
-
        return result;
 
 end_error:
@@ -1428,52 +1489,81 @@ end_error:
        return NULL;
 }
 
-static initializer_t *parse_initializer(type_t *const orig_type)
-{
-       initializer_t *result;
-
-       type_t *const type = skip_typeref(orig_type);
+typedef struct parse_initializer_env_t {
+       type_t        *type;        /* the type of the initializer. In case of an
+                                      array type with unspecified size this gets
+                                      adjusted to the actual size. */
+       initializer_t *initializer; /* initializer will be filled in here */
+       bool           must_be_constant;
+} parse_initializer_env_t;
 
-       if(token.type != '{') {
-               expression_t  *expression  = parse_assignment_expression();
-               initializer_t *initializer = initializer_from_expression(type, expression);
-               if(initializer == NULL) {
-                       errorf(HERE,
-                               "initializer expression '%E' of type '%T' is incompatible with type '%T'",
-                               expression, expression->base.type, orig_type);
-               }
-               return initializer;
-       }
+static void parse_initializer(parse_initializer_env_t *env)
+{
+       type_t        *type   = skip_typeref(env->type);
+       initializer_t *result = NULL;
+       size_t         max_index;
 
        if(is_type_scalar(type)) {
                /* TODO: § 6.7.8.11; eat {} without warning */
-
-               result = parse_scalar_initializer(type);
-
-               if(token.type == ',')
-                       next_token();
-
-               return result;
+               result = parse_scalar_initializer(type, env->must_be_constant);
        } else if(token.type == '{') {
-               next_token();
+               eat('{');
 
                type_path_t path;
                memset(&path, 0, sizeof(path));
-               path.top_type = orig_type;
+               path.top_type = env->type;
                path.path     = NEW_ARR_F(type_path_entry_t, 0);
 
                descend_into_subtype(&path);
 
-               result = parse_sub_initializer(&path, orig_type, 1);
+               result = parse_sub_initializer(&path, env->type, 1,
+                                              env->must_be_constant);
 
+               max_index = path.max_index;
                DEL_ARR_F(path.path);
 
-               expect('}');
+               expect_void('}');
        } else {
-               /* 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);
        }
 
-       return result;
+       /* § 6.7.5 (22)  array initializers for arrays with unknown size determine
+        * the array type size */
+       if(is_type_array(type) && type->array.size_expression == NULL
+                       && result != NULL) {
+               size_t size;
+               switch (result->kind) {
+               case INITIALIZER_LIST:
+                       size = max_index + 1;
+                       break;
+
+               case INITIALIZER_STRING:
+                       size = result->string.string.size;
+                       break;
+
+               case INITIALIZER_WIDE_STRING:
+                       size = result->wide_string.string.size;
+                       break;
+
+               default:
+                       panic("invalid initializer type");
+               }
+
+               expression_t *cnst       = allocate_expression_zero(EXPR_CONST);
+               cnst->base.type          = type_size_t;
+               cnst->conste.v.int_value = size;
+
+               type_t *new_type = duplicate_type(type);
+
+               new_type->array.size_expression = cnst;
+               new_type->array.size_constant   = true;
+               new_type->array.size            = size;
+               env->type = new_type;
+       }
+
+       env->initializer = result;
 }
 
 static declaration_t *append_declaration(declaration_t *declaration);
@@ -1756,13 +1846,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)
@@ -1772,22 +1862,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;
@@ -2081,10 +2171,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");
        }
 
@@ -2437,6 +2527,10 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                        type_t         *array_type    = allocate_type_zero(TYPE_ARRAY, (source_position_t){NULL, 0});
 
                        expression_t *size_expression = parsed_array->size;
+                       if(size_expression != NULL) {
+                               size_expression
+                                       = create_implicit_cast(size_expression, type_size_t);
+                       }
 
                        array_type->base.qualifiers       = parsed_array->type_qualifiers;
                        array_type->array.element_type    = type;
@@ -2444,11 +2538,14 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                        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);
+                       if(size_expression != NULL) {
+                               if(is_constant_expression(size_expression)) {
+                                       array_type->array.size_constant = true;
+                                       array_type->array.size
+                                               = fold_constant(size_expression);
+                               } else {
+                                       array_type->array.is_vla = true;
+                               }
                        }
 
                        type_t *skipped_type = skip_typeref(type);
@@ -2479,10 +2576,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);
@@ -2674,6 +2777,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 {
@@ -2764,52 +2868,28 @@ static void parse_init_declarator_rest(declaration_t *declaration)
        eat('=');
 
        type_t *orig_type = declaration->type;
-       type_t *type      = type = skip_typeref(orig_type);
+       type_t *type      = skip_typeref(orig_type);
 
        if(declaration->init.initializer != NULL) {
                parser_error_multiple_definition(declaration, token.source_position);
        }
 
-       initializer_t *initializer = parse_initializer(type);
-
-       /* § 6.7.5 (22)  array initializers for arrays with unknown size determine
-        * the array type size */
-       if(is_type_array(type) && initializer != NULL) {
-               array_type_t *array_type = &type->array;
-
-               if(array_type->size_expression == NULL) {
-                       size_t size;
-                       switch (initializer->kind) {
-                               case INITIALIZER_LIST: {
-                                       /* TODO */
-                                       size = initializer->list.len;
-                                       break;
-                               }
-
-                               case INITIALIZER_STRING: {
-                                       size = initializer->string.string.size;
-                                       break;
-                               }
-
-                               case INITIALIZER_WIDE_STRING: {
-                                       size = initializer->wide_string.string.size;
-                                       break;
-                               }
-
-                               default: {
-                                       panic("invalid initializer type");
-                                       break;
-                               }
-                       }
+       bool must_be_constant = false;
+       if(declaration->storage_class == STORAGE_CLASS_STATIC
+                       || declaration->storage_class == STORAGE_CLASS_THREAD_STATIC
+                       || declaration->parent_scope == global_scope) {
+               must_be_constant = true;
+       }
 
-                       expression_t *cnst       = allocate_expression_zero(EXPR_CONST);
-                       cnst->base.type          = type_size_t;
-                       cnst->conste.v.int_value = size;
+       parse_initializer_env_t env;
+       env.type             = orig_type;
+       env.must_be_constant = must_be_constant;
+       parse_initializer(&env);
 
-                       array_type->size_expression = cnst;
-                       array_type->size_constant   = true;
-                       array_type->size            = size;
-               }
+       if(env.type != orig_type) {
+               orig_type         = env.type;
+               type              = skip_typeref(orig_type);
+               declaration->type = env.type;
        }
 
        if(is_type_function(type)) {
@@ -2817,7 +2897,7 @@ static void parse_init_declarator_rest(declaration_t *declaration)
                       "initializers not allowed for function types at declator '%Y' (type '%T')",
                       declaration->symbol, orig_type);
        } else {
-               declaration->init.initializer = initializer;
+               declaration->init.initializer = env.initializer;
        }
 }
 
@@ -2828,14 +2908,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) {
@@ -2910,6 +2991,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;
@@ -3255,12 +3337,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);
 
@@ -3345,7 +3428,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...
                 */
@@ -3413,6 +3496,9 @@ static expression_t *parse_string_const(void)
                }
                if (token.type != T_WIDE_STRING_LITERAL) {
                        expression_t *const cnst = allocate_expression_zero(EXPR_STRING_LITERAL);
+                       /* note: that we use type_char_ptr here, which is already the
+                        * automatic converted type. revert_automatic_type_conversion
+                        * will construct the array type */
                        cnst->base.type    = type_char_ptr;
                        cnst->string.value = res;
                        return cnst;
@@ -3463,15 +3549,39 @@ static expression_t *parse_int_const(void)
 /**
  * Parse a character constant.
  */
-static expression_t *parse_char_const(void)
+static expression_t *parse_character_constant(void)
 {
-       expression_t *cnst         = allocate_expression_zero(EXPR_CHAR_CONST);
+       expression_t *cnst = allocate_expression_zero(EXPR_CHARACTER_CONSTANT);
+
        cnst->base.source_position = HERE;
        cnst->base.type            = token.datatype;
-       cnst->conste.v.chars.begin = token.v.string.begin;
-       cnst->conste.v.chars.size  = token.v.string.size;
+       cnst->conste.v.character   = token.v.string;
+
+       if (cnst->conste.v.character.size != 1) {
+               if (warning.multichar && (c_mode & _GNUC)) {
+                       /* TODO */
+                       warningf(HERE, "multi-character character constant");
+               } else {
+                       errorf(HERE, "more than 1 characters in character constant");
+               }
+       }
+       next_token();
+
+       return cnst;
+}
+
+/**
+ * Parse a wide character constant.
+ */
+static expression_t *parse_wide_character_constant(void)
+{
+       expression_t *cnst = allocate_expression_zero(EXPR_WIDE_CHARACTER_CONSTANT);
+
+       cnst->base.source_position    = HERE;
+       cnst->base.type               = token.datatype;
+       cnst->conste.v.wide_character = token.v.wide_string;
 
-       if (cnst->conste.v.chars.size != 1) {
+       if (cnst->conste.v.wide_character.size != 1) {
                if (warning.multichar && (c_mode & _GNUC)) {
                        /* TODO */
                        warningf(HERE, "multi-character character constant");
@@ -3510,12 +3620,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);
@@ -3632,6 +3743,19 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
                        return type_left->pointer.points_to;
                }
 
+               case EXPR_STRING_LITERAL: {
+                       size_t size = expression->string.value.size;
+                       return make_array_type(type_char, size, TYPE_QUALIFIER_NONE);
+               }
+
+               case EXPR_WIDE_STRING_LITERAL: {
+                       size_t size = expression->wide_string.value.size;
+                       return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE);
+               }
+
+               case EXPR_COMPOUND_LITERAL:
+                       return expression->compound_literal.type;
+
                default: break;
        }
 
@@ -3692,8 +3816,14 @@ static expression_t *parse_compound_literal(type_t *type)
 {
        expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
 
+       parse_initializer_env_t env;
+       env.type             = type;
+       env.must_be_constant = false;
+       parse_initializer(&env);
+       type = env.type;
+
        expression->compound_literal.type        = type;
-       expression->compound_literal.initializer = parse_initializer(type);
+       expression->compound_literal.initializer = env.initializer;
        expression->base.type                    = automatic_type_conversion(type);
 
        return expression;
@@ -4074,7 +4204,8 @@ static expression_t *parse_primary_expression(void)
 {
        switch (token.type) {
                case T_INTEGER:                  return parse_int_const();
-               case T_CHARS:                    return parse_char_const();
+               case T_CHARACTER_CONSTANT:       return parse_character_constant();
+               case T_WIDE_CHARACTER_CONSTANT:  return parse_wide_character_constant();
                case T_FLOATINGPOINT:            return parse_float_const();
                case T_STRING_LITERAL:
                case T_WIDE_STRING_LITERAL:      return parse_string_const();
@@ -5002,6 +5133,18 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
        expression->base.type = orig_type_left;
 }
 
+/**
+ * Determine if the outermost operation (or parts thereof) of the given
+ * expression has no effect in order to generate a warning about this fact.
+ * Therefore in some cases this only examines some of the operands of the
+ * expression (see comments in the function and examples below).
+ * Examples:
+ *   f() + 23;    // warning, because + has no effect
+ *   x || f();    // no warning, because x controls execution of f()
+ *   x ? y : f(); // warning, because y has no effect
+ *   (void)x;     // no warning to be able to suppress the warning
+ * This function can NOT be used for an "expression has definitely no effect"-
+ * analysis. */
 static bool expression_has_effect(const expression_t *const expr)
 {
        switch (expr->kind) {
@@ -5009,9 +5152,11 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_INVALID:                   break;
                case EXPR_REFERENCE:                 return false;
                case EXPR_CONST:                     return false;
-               case EXPR_CHAR_CONST:                return false;
+               case EXPR_CHARACTER_CONSTANT:        return false;
+               case EXPR_WIDE_CHARACTER_CONSTANT:   return false;
                case EXPR_STRING_LITERAL:            return false;
                case EXPR_WIDE_STRING_LITERAL:       return false;
+
                case EXPR_CALL: {
                        const call_expression_t *const call = &expr->call;
                        if (call->function->kind != EXPR_BUILTIN_SYMBOL)
@@ -5022,12 +5167,16 @@ static bool expression_has_effect(const expression_t *const expr)
                                default:                 return false;
                        }
                }
+
+               /* Generate the warning if either the left or right hand side of a
+                * conditional expression has no effect */
                case EXPR_CONDITIONAL: {
                        const conditional_expression_t *const cond = &expr->conditional;
                        return
                                expression_has_effect(cond->true_expression) &&
                                expression_has_effect(cond->false_expression);
                }
+
                case EXPR_SELECT:                    return false;
                case EXPR_ARRAY_ACCESS:              return false;
                case EXPR_SIZEOF:                    return false;
@@ -5055,10 +5204,14 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_UNARY_POSTFIX_DECREMENT:   return true;
                case EXPR_UNARY_PREFIX_INCREMENT:    return true;
                case EXPR_UNARY_PREFIX_DECREMENT:    return true;
+
+               /* Treat void casts as if they have an effect in order to being able to
+                * suppress the warning */
                case EXPR_UNARY_CAST: {
-                       type_t *type = skip_typeref(expr->base.type);
+                       type_t *const type = skip_typeref(expr->base.type);
                        return is_type_atomic(type, ATOMIC_TYPE_VOID);
                }
+
                case EXPR_UNARY_CAST_IMPLICIT:       return true;
                case EXPR_UNARY_ASSUME:              return true;
                case EXPR_UNARY_BITFIELD_EXTRACT:    return false;
@@ -5090,8 +5243,14 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_BINARY_BITWISE_AND_ASSIGN: return true;
                case EXPR_BINARY_BITWISE_XOR_ASSIGN: return true;
                case EXPR_BINARY_BITWISE_OR_ASSIGN:  return true;
+
+               /* Only examine the right hand side of && and ||, because the left hand
+                * side already has the effect of controlling the execution of the right
+                * hand side */
                case EXPR_BINARY_LOGICAL_AND:
                case EXPR_BINARY_LOGICAL_OR:
+               /* Only examine the right hand side of a comma expression, because the left
+                * hand side has a separate warning */
                case EXPR_BINARY_COMMA:
                        return expression_has_effect(expr->binary.right);
 
@@ -5881,7 +6040,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);
@@ -5900,25 +6058,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);
 }
 
 /**