Make diagnosticvf() slightly more efficient by using fwrite() instead of printing...
[cparser] / parser.c
index cc6d550..9dadbf6 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -252,11 +252,8 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_MINUSMINUS:                \
        case T_PLUSPLUS:                  \
        case T_STRING_LITERAL:            \
-       case T_WIDE_CHARACTER_CONSTANT:   \
-       case T_WIDE_STRING_LITERAL:       \
        case T___FUNCDNAME__:             \
        case T___FUNCSIG__:               \
-       case T___FUNCTION__:              \
        case T___PRETTY_FUNCTION__:       \
        case T___alignof__:               \
        case T___builtin_classify_type:   \
@@ -328,10 +325,8 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_LITERAL_BOOLEAN]            = sizeof(literal_expression_t),
                [EXPR_LITERAL_INTEGER]            = sizeof(literal_expression_t),
                [EXPR_LITERAL_FLOATINGPOINT]      = sizeof(literal_expression_t),
-               [EXPR_LITERAL_CHARACTER]          = sizeof(literal_expression_t),
-               [EXPR_LITERAL_WIDE_CHARACTER]     = sizeof(literal_expression_t),
+               [EXPR_LITERAL_CHARACTER]          = sizeof(string_literal_expression_t),
                [EXPR_STRING_LITERAL]             = sizeof(string_literal_expression_t),
-               [EXPR_WIDE_STRING_LITERAL]        = sizeof(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),
@@ -631,33 +626,33 @@ static void type_error_incompatible(const char *msg,
               msg, type1, type2);
 }
 
-/**
- * Expect the current token is the expected token.
- * If not, generate an error and skip until the next anchor.
- */
-static void expect(token_kind_t const expected)
+static bool skip_till(token_kind_t const expected, char const *const context)
 {
        if (UNLIKELY(token.kind != expected)) {
-               parse_error_expected(NULL, expected, NULL);
+               parse_error_expected(context, expected, NULL);
                add_anchor_token(expected);
                eat_until_anchor();
                rem_anchor_token(expected);
                if (token.kind != expected)
-                       return;
+                       return false;
        }
-       eat(expected);
+       return true;
+}
+
+/**
+ * Expect the current token is the expected token.
+ * If not, generate an error and skip until the next anchor.
+ */
+static void expect(token_kind_t const expected)
+{
+       if (skip_till(expected, NULL))
+               eat(expected);
 }
 
 static symbol_t *expect_identifier(char const *const context, source_position_t *const pos)
 {
-       if (token.kind != T_IDENTIFIER) {
-               parse_error_expected(context, T_IDENTIFIER, NULL);
-               add_anchor_token(T_IDENTIFIER);
-               eat_until_anchor();
-               rem_anchor_token(T_IDENTIFIER);
-               if (token.kind != T_IDENTIFIER)
-                       return NULL;
-       }
+       if (!skip_till(T_IDENTIFIER, context))
+               return NULL;
        symbol_t *const sym = token.base.symbol;
        if (pos)
                *pos = *HERE;
@@ -1037,27 +1032,64 @@ static expression_t *parse_assignment_expression(void)
        return parse_subexpression(PREC_ASSIGNMENT);
 }
 
-static void warn_string_concat(const source_position_t *pos)
+static void append_string(string_t const *const s)
 {
-       warningf(WARN_TRADITIONAL, pos, "traditional C rejects string constant concatenation");
+       /* FIXME Using the ast_obstack is a hack.  Using the symbol_obstack is not
+        * possible, because other tokens are grown there alongside. */
+       obstack_grow(&ast_obstack, s->begin, s->size);
 }
 
-static string_t parse_string_literals(void)
+static string_t finish_string(void)
 {
-       assert(token.kind == T_STRING_LITERAL);
-       string_t result = token.string.string;
+       obstack_1grow(&ast_obstack, '\0');
+       size_t      const size   = obstack_object_size(&ast_obstack) - 1;
+       char const *const string = obstack_finish(&ast_obstack);
+       return (string_t){ string, size };
+}
 
-       eat(T_STRING_LITERAL);
+static string_t concat_string_literals(string_encoding_t *const out_enc)
+{
+       assert(token.kind == T_STRING_LITERAL);
 
-       while (token.kind == T_STRING_LITERAL) {
-               warn_string_concat(HERE);
-               result = concat_strings(&result, &token.string.string);
+       string_t          result;
+       string_encoding_t enc = token.string.encoding;
+       if (look_ahead(1)->kind == T_STRING_LITERAL) {
+               append_string(&token.string.string);
+               eat(T_STRING_LITERAL);
+               warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation");
+               do {
+                       if (token.string.encoding != STRING_ENCODING_CHAR) {
+                               enc = token.string.encoding;
+                       }
+                       append_string(&token.string.string);
+                       eat(T_STRING_LITERAL);
+               } while (token.kind == T_STRING_LITERAL);
+               result = finish_string();
+       } else {
+               result = token.string.string;
                eat(T_STRING_LITERAL);
        }
 
+       *out_enc = enc;
        return result;
 }
 
+static string_t parse_string_literals(char const *const context)
+{
+       if (!skip_till(T_STRING_LITERAL, context))
+               return (string_t){ "", 0 };
+
+       string_encoding_t       enc;
+       source_position_t const pos = *HERE;
+       string_t          const res = concat_string_literals(&enc);
+
+       if (enc != STRING_ENCODING_CHAR) {
+               errorf(&pos, "expected plain string literal, got wide string literal");
+       }
+
+       return res;
+}
+
 static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
 {
        attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
@@ -1172,11 +1204,11 @@ static attribute_t *parse_attribute_gnu(void)
        attribute_t **anchor = &first;
 
        eat(T___attribute__);
+       add_anchor_token(')');
+       add_anchor_token(',');
        expect('(');
        expect('(');
 
-       add_anchor_token(')');
-       add_anchor_token(',');
        if (token.kind != ')') do {
                attribute_t *attribute = parse_attribute_gnu_single();
                if (attribute) {
@@ -1456,9 +1488,9 @@ unary:
                        return;
 
                case EXPR_LITERAL_CASES:
+               case EXPR_LITERAL_CHARACTER:
                case EXPR_ERROR:
                case EXPR_STRING_LITERAL:
-               case EXPR_WIDE_STRING_LITERAL:
                case EXPR_COMPOUND_LITERAL: // TODO init?
                case EXPR_SIZEOF:
                case EXPR_CLASSIFY_TYPE:
@@ -1554,10 +1586,10 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
                array_type_t *const array_type   = &type->array;
                type_t       *const element_type = skip_typeref(array_type->element_type);
 
-               if (element_type->kind == TYPE_ATOMIC) {
-                       atomic_type_kind_t akind = element_type->atomic.akind;
-                       switch (expression->kind) {
-                       case EXPR_STRING_LITERAL:
+               if (element_type->kind == TYPE_ATOMIC && expression->kind == EXPR_STRING_LITERAL) {
+                       switch (expression->string_literal.encoding) {
+                       case STRING_ENCODING_CHAR: {
+                               atomic_type_kind_t const akind = element_type->atomic.akind;
                                if (akind == ATOMIC_TYPE_CHAR
                                                || akind == ATOMIC_TYPE_SCHAR
                                                || akind == ATOMIC_TYPE_UCHAR) {
@@ -1565,8 +1597,9 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
                                                        &expression->string_literal.value);
                                }
                                break;
+                       }
 
-                       case EXPR_WIDE_STRING_LITERAL: {
+                       case STRING_ENCODING_WIDE: {
                                type_t *bare_wchar_type = skip_typeref(type_wchar_t);
                                if (get_unqualified_type(element_type) == bare_wchar_type) {
                                        return initializer_from_wide_string(array_type,
@@ -1574,9 +1607,6 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
                                }
                                break;
                        }
-
-                       default:
-                               break;
                        }
                }
        }
@@ -1829,7 +1859,8 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                        }
                } else {
                        expression_t *array_index = designator->array_index;
-                       assert(designator->array_index != NULL);
+                       if (is_constant_expression(array_index) != EXPR_CLASS_CONSTANT)
+                               return true;
 
                        if (!is_type_array(type)) {
                                if (is_type_valid(type)) {
@@ -2056,9 +2087,7 @@ finish_designator:
                        }
 
                        /* handle { "string" } special case */
-                       if ((expression->kind == EXPR_STRING_LITERAL
-                                       || expression->kind == EXPR_WIDE_STRING_LITERAL)
-                                       && outer_type != NULL) {
+                       if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
                                sub = initializer_from_expression(outer_type, expression);
                                if (sub != NULL) {
                                        next_if(',');
@@ -2208,7 +2237,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env)
                        break;
 
                case INITIALIZER_STRING:
-                       size = result->string.string.size;
+                       size = result->string.string.size + 1;
                        break;
 
                case INITIALIZER_WIDE_STRING:
@@ -2438,8 +2467,8 @@ static type_t *parse_typeof(void)
 
        type_t *type;
 
-       expect('(');
        add_anchor_token(')');
+       expect('(');
 
        expression_t *expression  = NULL;
 
@@ -2504,10 +2533,10 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
 {
        attribute_property_argument_t *const property = allocate_ast_zero(sizeof(*property));
 
-       expect('(');
-
        add_anchor_token(')');
        add_anchor_token(',');
+       expect('(');
+
        do {
                add_anchor_token('=');
                source_position_t pos;
@@ -2584,10 +2613,9 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
 {
        eat(T__declspec);
 
+       add_anchor_token(')');
        expect('(');
        if (token.kind != ')') {
-               add_anchor_token(')');
-
                attribute_t **anchor = &first;
                do {
                        while (*anchor != NULL)
@@ -2601,9 +2629,8 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
                        *anchor = attribute;
                        anchor  = &attribute->next;
                } while (next_if(','));
-
-               rem_anchor_token(')');
        }
+       rem_anchor_token(')');
        expect(')');
        return first;
 }
@@ -3141,8 +3168,8 @@ static bool has_parameters(void)
  */
 static void parse_parameters(function_type_t *type, scope_t *scope)
 {
-       eat('(');
        add_anchor_token(')');
+       eat('(');
 
        if (token.kind == T_IDENTIFIER            &&
            !is_typedef_symbol(token.base.symbol) &&
@@ -4623,8 +4650,8 @@ static bool expression_returns(expression_t const *const expr)
                case EXPR_REFERENCE:
                case EXPR_ENUM_CONSTANT:
                case EXPR_LITERAL_CASES:
+               case EXPR_LITERAL_CHARACTER:
                case EXPR_STRING_LITERAL:
-               case EXPR_WIDE_STRING_LITERAL:
                case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
                case EXPR_LABEL_ADDRESS:
                case EXPR_CLASSIFY_TYPE:
@@ -5682,14 +5709,14 @@ struct expression_parser_function_t {
 
 static expression_parser_function_t expression_parsers[T_LAST_TOKEN];
 
-static type_t *get_string_type(void)
+static type_t *get_string_type(string_encoding_t const enc)
 {
-       return is_warn_on(WARN_WRITE_STRINGS) ? type_const_char_ptr : type_char_ptr;
-}
-
-static type_t *get_wide_string_type(void)
-{
-       return is_warn_on(WARN_WRITE_STRINGS) ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+       bool const warn = is_warn_on(WARN_WRITE_STRINGS);
+       switch (enc) {
+       case STRING_ENCODING_CHAR: return warn ? type_const_char_ptr    : type_char_ptr;
+       case STRING_ENCODING_WIDE: return warn ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+       }
+       panic("invalid string encoding");
 }
 
 /**
@@ -5697,31 +5724,10 @@ static type_t *get_wide_string_type(void)
  */
 static expression_t *parse_string_literal(void)
 {
-       source_position_t begin   = *HERE;
-       string_t          res     = token.string.string;
-       bool              is_wide = (token.kind == T_WIDE_STRING_LITERAL);
-
-       next_token();
-       while (token.kind == T_STRING_LITERAL
-                       || token.kind == T_WIDE_STRING_LITERAL) {
-               warn_string_concat(HERE);
-               res = concat_strings(&res, &token.string.string);
-               next_token();
-               is_wide |= token.kind == T_WIDE_STRING_LITERAL;
-       }
-
-       expression_t *literal;
-       if (is_wide) {
-               literal = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
-               literal->base.type = get_wide_string_type();
-       } else {
-               literal = allocate_expression_zero(EXPR_STRING_LITERAL);
-               literal->base.type = get_string_type();
-       }
-       literal->base.source_position = begin;
-       literal->literal.value        = res;
-
-       return literal;
+       expression_t *const expr = allocate_expression_zero(EXPR_STRING_LITERAL);
+       expr->string_literal.value = concat_string_literals(&expr->string_literal.encoding);
+       expr->base.type            = get_string_type(expr->string_literal.encoding);
+       return expr;
 }
 
 /**
@@ -5849,42 +5855,35 @@ static expression_t *parse_number_literal(void)
  */
 static expression_t *parse_character_constant(void)
 {
-       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
-       literal->base.type     = c_mode & _CXX ? type_char : type_int;
-       literal->literal.value = token.string.string;
+       expression_t *const literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
+       literal->string_literal.encoding = token.string.encoding;
+       literal->string_literal.value    = token.string.string;
 
-       size_t len = literal->literal.value.size;
-       if (len > 1) {
-               if (!GNU_MODE && !(c_mode & _C99)) {
-                       errorf(HERE, "more than 1 character in character constant");
-               } else {
-                       literal->base.type = type_int;
+       switch (token.string.encoding) {
+       case STRING_ENCODING_CHAR:
+               literal->base.type = c_mode & _CXX ? type_char : type_int;
+               if (literal->string_literal.value.size > 1) {
+                       if (!GNU_MODE && !(c_mode & _C99)) {
+                               errorf(HERE, "more than 1 character in character constant");
+                       } else {
+                               literal->base.type = type_int;
+                               warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
+                       }
+               }
+               break;
+
+       case STRING_ENCODING_WIDE:
+               literal->base.type = type_int;
+               if (wstrlen(&literal->string_literal.value) > 1) {
                        warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
                }
+               break;
        }
 
        eat(T_CHARACTER_CONSTANT);
        return literal;
 }
 
-/**
- * Parse a wide character constant.
- */
-static expression_t *parse_wide_character_constant(void)
-{
-       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER);
-       literal->base.type     = type_int;
-       literal->literal.value = token.string.string;
-
-       size_t len = wstrlen(&literal->literal.value);
-       if (len > 1) {
-               warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
-       }
-
-       eat(T_WIDE_CHARACTER_CONSTANT);
-       return literal;
-}
-
 static entity_t *create_implicit_function(symbol_t *symbol, source_position_t const *const pos)
 {
        type_t *ntype                          = allocate_type_zero(TYPE_FUNCTION);
@@ -5970,13 +5969,9 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
        }
 
        case EXPR_STRING_LITERAL: {
-               size_t size = expression->string_literal.value.size;
-               return make_array_type(type_char, size, TYPE_QUALIFIER_NONE);
-       }
-
-       case EXPR_WIDE_STRING_LITERAL: {
-               size_t size = wstrlen(&expression->string_literal.value);
-               return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE);
+               size_t  const size = expression->string_literal.value.size + 1;
+               type_t *const elem = get_unqualified_type(expression->base.type->pointer.points_to);
+               return make_array_type(elem, size, TYPE_QUALIFIER_NONE);
        }
 
        case EXPR_COMPOUND_LITERAL:
@@ -6272,68 +6267,21 @@ static expression_t *parse_parenthesized_expression(void)
        return result;
 }
 
-static expression_t *parse_function_keyword(void)
+static expression_t *parse_function_keyword(funcname_kind_t const kind)
 {
-       /* TODO */
-
        if (current_function == NULL) {
-               errorf(HERE, "'__func__' used outside of a function");
+               errorf(HERE, "'%K' used outside of a function", &token);
        }
 
        expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
        expression->base.type     = type_char_ptr;
-       expression->funcname.kind = FUNCNAME_FUNCTION;
+       expression->funcname.kind = kind;
 
        next_token();
 
        return expression;
 }
 
-static expression_t *parse_pretty_function_keyword(void)
-{
-       if (current_function == NULL) {
-               errorf(HERE, "'__PRETTY_FUNCTION__' used outside of a function");
-       }
-
-       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
-       expression->base.type     = type_char_ptr;
-       expression->funcname.kind = FUNCNAME_PRETTY_FUNCTION;
-
-       eat(T___PRETTY_FUNCTION__);
-
-       return expression;
-}
-
-static expression_t *parse_funcsig_keyword(void)
-{
-       if (current_function == NULL) {
-               errorf(HERE, "'__FUNCSIG__' used outside of a function");
-       }
-
-       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
-       expression->base.type     = type_char_ptr;
-       expression->funcname.kind = FUNCNAME_FUNCSIG;
-
-       eat(T___FUNCSIG__);
-
-       return expression;
-}
-
-static expression_t *parse_funcdname_keyword(void)
-{
-       if (current_function == NULL) {
-               errorf(HERE, "'__FUNCDNAME__' used outside of a function");
-       }
-
-       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
-       expression->base.type     = type_char_ptr;
-       expression->funcname.kind = FUNCNAME_FUNCDNAME;
-
-       eat(T___FUNCDNAME__);
-
-       return expression;
-}
-
 static designator_t *parse_designator(void)
 {
        designator_t *const result = allocate_ast_zero(sizeof(result[0]));
@@ -6384,9 +6332,9 @@ static expression_t *parse_offsetof(void)
 
        eat(T___builtin_offsetof);
 
-       expect('(');
        add_anchor_token(')');
        add_anchor_token(',');
+       expect('(');
        type_t *type = parse_typename();
        rem_anchor_token(',');
        expect(',');
@@ -6439,9 +6387,9 @@ static expression_t *parse_va_start(void)
 
        eat(T___builtin_va_start);
 
-       expect('(');
        add_anchor_token(')');
        add_anchor_token(',');
+       expect('(');
        expression->va_starte.ap = parse_assignment_expression();
        rem_anchor_token(',');
        expect(',');
@@ -6470,9 +6418,9 @@ static expression_t *parse_va_arg(void)
 
        eat(T___builtin_va_arg);
 
-       expect('(');
        add_anchor_token(')');
        add_anchor_token(',');
+       expect('(');
        call_argument_t ap;
        ap.expression = parse_assignment_expression();
        expression->va_arge.ap = ap.expression;
@@ -6496,9 +6444,9 @@ static expression_t *parse_va_copy(void)
 
        eat(T___builtin_va_copy);
 
-       expect('(');
        add_anchor_token(')');
        add_anchor_token(',');
+       expect('(');
        expression_t *dst = parse_assignment_expression();
        assign_error_t error = semantic_assign(type_valist, dst);
        report_assign_error(error, type_valist, dst, "call argument 1",
@@ -6527,8 +6475,8 @@ static expression_t *parse_builtin_constant(void)
 
        eat(T___builtin_constant_p);
 
-       expect('(');
        add_anchor_token(')');
+       expect('(');
        expression->builtin_constant.value = parse_assignment_expression();
        rem_anchor_token(')');
        expect(')');
@@ -6546,9 +6494,9 @@ static expression_t *parse_builtin_types_compatible(void)
 
        eat(T___builtin_types_compatible_p);
 
-       expect('(');
        add_anchor_token(')');
        add_anchor_token(',');
+       expect('(');
        expression->builtin_types_compatible.left = parse_typename();
        rem_anchor_token(',');
        expect(',');
@@ -6565,36 +6513,22 @@ static expression_t *parse_builtin_types_compatible(void)
  */
 static expression_t *parse_compare_builtin(void)
 {
-       expression_t *expression;
-
+       expression_kind_t kind;
        switch (token.kind) {
-       case T___builtin_isgreater:
-               expression = allocate_expression_zero(EXPR_BINARY_ISGREATER);
-               break;
-       case T___builtin_isgreaterequal:
-               expression = allocate_expression_zero(EXPR_BINARY_ISGREATEREQUAL);
-               break;
-       case T___builtin_isless:
-               expression = allocate_expression_zero(EXPR_BINARY_ISLESS);
-               break;
-       case T___builtin_islessequal:
-               expression = allocate_expression_zero(EXPR_BINARY_ISLESSEQUAL);
-               break;
-       case T___builtin_islessgreater:
-               expression = allocate_expression_zero(EXPR_BINARY_ISLESSGREATER);
-               break;
-       case T___builtin_isunordered:
-               expression = allocate_expression_zero(EXPR_BINARY_ISUNORDERED);
-               break;
-       default:
-               internal_errorf(HERE, "invalid compare builtin found");
-       }
-       expression->base.source_position = *HERE;
+       case T___builtin_isgreater:      kind = EXPR_BINARY_ISGREATER;      break;
+       case T___builtin_isgreaterequal: kind = EXPR_BINARY_ISGREATEREQUAL; break;
+       case T___builtin_isless:         kind = EXPR_BINARY_ISLESS;         break;
+       case T___builtin_islessequal:    kind = EXPR_BINARY_ISLESSEQUAL;    break;
+       case T___builtin_islessgreater:  kind = EXPR_BINARY_ISLESSGREATER;  break;
+       case T___builtin_isunordered:    kind = EXPR_BINARY_ISUNORDERED;    break;
+       default: internal_errorf(HERE, "invalid compare builtin found");
+       }
+       expression_t *const expression = allocate_expression_zero(kind);
        next_token();
 
-       expect('(');
        add_anchor_token(')');
        add_anchor_token(',');
+       expect('(');
        expression->binary.left = parse_assignment_expression();
        rem_anchor_token(',');
        expect(',');
@@ -6628,8 +6562,8 @@ static expression_t *parse_assume(void)
 
        eat(T__assume);
 
-       expect('(');
        add_anchor_token(')');
+       expect('(');
        expression->unary.value = parse_assignment_expression();
        rem_anchor_token(')');
        expect(')');
@@ -6641,12 +6575,15 @@ static expression_t *parse_assume(void)
 /**
  * Return the label for the current symbol or create a new one.
  */
-static label_t *get_label(void)
+static label_t *get_label(char const *const context)
 {
-       assert(token.kind == T_IDENTIFIER);
        assert(current_function != NULL);
 
-       entity_t *label = get_entity(token.base.symbol, NAMESPACE_LABEL);
+       symbol_t *const sym = expect_identifier(context, NULL);
+       if (!sym)
+               return NULL;
+
+       entity_t *label = get_entity(sym, NAMESPACE_LABEL);
        /* If we find a local label, we already created the declaration. */
        if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) {
                if (label->base.parent_scope != current_scope) {
@@ -6656,11 +6593,10 @@ static label_t *get_label(void)
        } else if (label == NULL || label->base.parent_scope != &current_function->parameters) {
                /* There is no matching label in the same function, so create a new one. */
                source_position_t const nowhere = { NULL, 0, 0, false };
-               label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.base.symbol, &nowhere);
+               label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym, &nowhere);
                label_push(label);
        }
 
-       eat(T_IDENTIFIER);
        return &label->label;
 }
 
@@ -6671,12 +6607,11 @@ static expression_t *parse_label_address(void)
 {
        source_position_t const source_position = *HERE;
        eat(T_ANDAND);
-       if (token.kind != T_IDENTIFIER) {
-               parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
+
+       label_t *const label = get_label("while parsing label address");
+       if (!label)
                return create_error_expression();
-       }
 
-       label_t *const label = get_label();
        label->used          = true;
        label->address_taken = true;
 
@@ -6731,14 +6666,11 @@ static expression_t *parse_primary_expression(void)
        case T_INTEGER:
        case T_FLOATINGPOINT:                return parse_number_literal();
        case T_CHARACTER_CONSTANT:           return parse_character_constant();
-       case T_WIDE_CHARACTER_CONSTANT:      return parse_wide_character_constant();
-       case T_STRING_LITERAL:
-       case T_WIDE_STRING_LITERAL:          return parse_string_literal();
-       case T___FUNCTION__:
-       case T___func__:                     return parse_function_keyword();
-       case T___PRETTY_FUNCTION__:          return parse_pretty_function_keyword();
-       case T___FUNCSIG__:                  return parse_funcsig_keyword();
-       case T___FUNCDNAME__:                return parse_funcdname_keyword();
+       case T_STRING_LITERAL:               return parse_string_literal();
+       case T___func__:                     return parse_function_keyword(FUNCNAME_FUNCTION);
+       case T___PRETTY_FUNCTION__:          return parse_function_keyword(FUNCNAME_PRETTY_FUNCTION);
+       case T___FUNCSIG__:                  return parse_function_keyword(FUNCNAME_FUNCSIG);
+       case T___FUNCDNAME__:                return parse_function_keyword(FUNCNAME_FUNCDNAME);
        case T___builtin_offsetof:           return parse_offsetof();
        case T___builtin_va_start:           return parse_va_start();
        case T___builtin_va_arg:             return parse_va_arg();
@@ -7410,8 +7342,8 @@ static expression_t *parse_builtin_classify_type(void)
 
        eat(T___builtin_classify_type);
 
-       expect('(');
        add_anchor_token(')');
+       expect('(');
        expression_t *expression = parse_expression();
        rem_anchor_token(')');
        expect(')');
@@ -8031,8 +7963,7 @@ static void warn_string_literal_address(expression_t const* expr)
                expr = expr->unary.value;
        }
 
-       if (expr->kind == EXPR_STRING_LITERAL
-                       || expr->kind == EXPR_WIDE_STRING_LITERAL) {
+       if (expr->kind == EXPR_STRING_LITERAL) {
                source_position_t const *const pos = &expr->base.source_position;
                warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour");
        }
@@ -8370,11 +8301,9 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_LITERAL_MS_NOOP:            return true;
                case EXPR_LITERAL_BOOLEAN:
                case EXPR_LITERAL_CHARACTER:
-               case EXPR_LITERAL_WIDE_CHARACTER:
                case EXPR_LITERAL_INTEGER:
                case EXPR_LITERAL_FLOATINGPOINT:
                case EXPR_STRING_LITERAL:             return false;
-               case EXPR_WIDE_STRING_LITERAL:        return false;
 
                case EXPR_CALL: {
                        const call_expression_t *const call = &expr->call;
@@ -8701,9 +8630,9 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                                return NULL;
                }
 
-               argument->constraints = parse_string_literals();
-               expect('(');
+               argument->constraints = parse_string_literals("asm argument");
                add_anchor_token(')');
+               expect('(');
                expression_t *expression = parse_expression();
                rem_anchor_token(')');
                if (is_out) {
@@ -8788,7 +8717,7 @@ static asm_clobber_t *parse_asm_clobbers(void)
 
        while (token.kind == T_STRING_LITERAL) {
                asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
-               clobber->clobber       = parse_string_literals();
+               clobber->clobber       = parse_string_literals(NULL);
 
                *anchor = clobber;
                anchor  = &clobber->next;
@@ -8809,40 +8738,27 @@ static statement_t *parse_asm_statement(void)
        asm_statement_t *asm_statement = &statement->asms;
 
        eat(T_asm);
+       add_anchor_token(')');
+       add_anchor_token(':');
+       add_anchor_token(T_STRING_LITERAL);
 
        if (next_if(T_volatile))
                asm_statement->is_volatile = true;
 
        expect('(');
-       add_anchor_token(')');
-       if (token.kind != T_STRING_LITERAL) {
-               parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
-               goto end_of_asm;
-       }
-       asm_statement->asm_text = parse_string_literals();
+       rem_anchor_token(T_STRING_LITERAL);
+       asm_statement->asm_text = parse_string_literals("asm statement");
 
-       add_anchor_token(':');
-       if (!next_if(':')) {
-               rem_anchor_token(':');
-               goto end_of_asm;
-       }
+       if (next_if(':'))
+               asm_statement->outputs = parse_asm_arguments(true);
 
-       asm_statement->outputs = parse_asm_arguments(true);
-       if (!next_if(':')) {
-               rem_anchor_token(':');
-               goto end_of_asm;
-       }
+       if (next_if(':'))
+               asm_statement->inputs = parse_asm_arguments(false);
 
-       asm_statement->inputs = parse_asm_arguments(false);
-       if (!next_if(':')) {
-               rem_anchor_token(':');
-               goto end_of_asm;
-       }
        rem_anchor_token(':');
+       if (next_if(':'))
+               asm_statement->clobbers = parse_asm_clobbers();
 
-       asm_statement->clobbers = parse_asm_clobbers();
-
-end_of_asm:
        rem_anchor_token(')');
        expect(')');
        expect(';');
@@ -9041,7 +8957,7 @@ static statement_t *parse_default_statement(void)
 static statement_t *parse_label_statement(void)
 {
        statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
-       label_t     *const label     = get_label();
+       label_t     *const label     = get_label(NULL /* Cannot fail, token is T_IDENTIFIER. */);
        statement->label.label = label;
 
        PUSH_PARENT(statement);
@@ -9089,8 +9005,8 @@ static statement_t *parse_inner_statement(void)
  */
 static expression_t *parse_condition(void)
 {
-       expect('(');
        add_anchor_token(')');
+       expect('(');
        expression_t *const expr = parse_expression();
        mark_vars_read(expr, NULL);
        rem_anchor_token(')');
@@ -9306,8 +9222,8 @@ static statement_t *parse_for(void)
        PUSH_PARENT(statement);
        PUSH_SCOPE_STATEMENT(&statement->fors.scope);
 
-       expect('(');
        add_anchor_token(')');
+       expect('(');
 
        PUSH_EXTENSION();
 
@@ -9388,8 +9304,9 @@ static statement_t *parse_goto(void)
        } else {
                statement = allocate_statement_zero(STATEMENT_GOTO);
                eat(T_goto);
-               if (token.kind == T_IDENTIFIER) {
-                       label_t *const label = get_label();
+
+               label_t *const label = get_label("while parsing goto");
+               if (label) {
                        label->used            = true;
                        statement->gotos.label = label;
 
@@ -9397,11 +9314,6 @@ static statement_t *parse_goto(void)
                        *goto_anchor = &statement->gotos;
                        goto_anchor  = &statement->gotos.next;
                } else {
-                       if (GNU_MODE)
-                               parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
-                       else
-                               parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
-                       eat_until_anchor();
                        statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_source_position)->label;
                }
        }
@@ -9493,22 +9405,6 @@ static bool expression_is_local_variable(const expression_t *expression)
        return is_local_variable(entity);
 }
 
-/**
- * Check if a given expression represents a local variable and
- * return its declaration then, else return NULL.
- */
-entity_t *expression_is_variable(const expression_t *expression)
-{
-       if (expression->base.kind != EXPR_REFERENCE) {
-               return NULL;
-       }
-       entity_t *entity = expression->reference.entity;
-       if (entity->kind != ENTITY_VARIABLE)
-               return NULL;
-
-       return entity;
-}
-
 static void err_or_warn(source_position_t const *const pos, char const *const msg)
 {
        if (c_mode & _CXX || strict_mode) {
@@ -9663,29 +9559,31 @@ static statement_t *parse_local_label_declaration(void)
        entity_t *begin   = NULL;
        entity_t *end     = NULL;
        entity_t **anchor = &begin;
+       add_anchor_token(';');
+       add_anchor_token(',');
        do {
                source_position_t pos;
                symbol_t *const symbol = expect_identifier("while parsing local label declaration", &pos);
-               if (!symbol)
-                       goto end_error;
-
-               entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
-               if (entity != NULL && entity->base.parent_scope == current_scope) {
-                       source_position_t const *const ppos = &entity->base.source_position;
-                       errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
-               } else {
-                       entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos);
-                       entity->base.parent_scope = current_scope;
+               if (symbol) {
+                       entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
+                       if (entity != NULL && entity->base.parent_scope == current_scope) {
+                               source_position_t const *const ppos = &entity->base.source_position;
+                               errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
+                       } else {
+                               entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos);
+                               entity->base.parent_scope = current_scope;
 
-                       *anchor = entity;
-                       anchor  = &entity->base.next;
-                       end     = entity;
+                               *anchor = entity;
+                               anchor  = &entity->base.next;
+                               end     = entity;
 
-                       environment_push(entity);
+                               environment_push(entity);
+                       }
                }
        } while (next_if(','));
+       rem_anchor_token(',');
+       rem_anchor_token(';');
        expect(';');
-end_error:
        statement->declaration.declarations_begin = begin;
        statement->declaration.declarations_end   = end;
        return statement;
@@ -9700,17 +9598,14 @@ static void parse_namespace_definition(void)
 
        if (token.kind == T_IDENTIFIER) {
                symbol = token.base.symbol;
-               next_token();
-
                entity = get_entity(symbol, NAMESPACE_NORMAL);
-               if (entity != NULL
-                               && entity->kind != ENTITY_NAMESPACE
-                               && entity->base.parent_scope == current_scope) {
-                       if (is_entity_valid(entity)) {
+               if (entity && entity->kind != ENTITY_NAMESPACE) {
+                       entity = NULL;
+                       if (entity->base.parent_scope == current_scope && is_entity_valid(entity)) {
                                error_redefined_as_different_kind(HERE, entity, ENTITY_NAMESPACE);
                        }
-                       entity = NULL;
                }
+               eat(T_IDENTIFIER);
        }
 
        if (entity == NULL) {
@@ -9876,12 +9771,9 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token(T_MINUSMINUS);
        add_anchor_token(T_PLUSPLUS);
        add_anchor_token(T_STRING_LITERAL);
-       add_anchor_token(T_WIDE_CHARACTER_CONSTANT);
-       add_anchor_token(T_WIDE_STRING_LITERAL);
        add_anchor_token(T__Bool);
        add_anchor_token(T__Complex);
        add_anchor_token(T__Imaginary);
-       add_anchor_token(T___FUNCTION__);
        add_anchor_token(T___PRETTY_FUNCTION__);
        add_anchor_token(T___alignof__);
        add_anchor_token(T___attribute__);
@@ -10049,12 +9941,9 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        rem_anchor_token(T___attribute__);
        rem_anchor_token(T___alignof__);
        rem_anchor_token(T___PRETTY_FUNCTION__);
-       rem_anchor_token(T___FUNCTION__);
        rem_anchor_token(T__Imaginary);
        rem_anchor_token(T__Complex);
        rem_anchor_token(T__Bool);
-       rem_anchor_token(T_WIDE_STRING_LITERAL);
-       rem_anchor_token(T_WIDE_CHARACTER_CONSTANT);
        rem_anchor_token(T_STRING_LITERAL);
        rem_anchor_token(T_PLUSPLUS);
        rem_anchor_token(T_MINUSMINUS);
@@ -10128,7 +10017,7 @@ static void parse_global_asm(void)
        expect('(');
 
        rem_anchor_token(T_STRING_LITERAL);
-       statement->asms.asm_text = parse_string_literals();
+       statement->asms.asm_text = parse_string_literals("global asm");
        statement->base.next     = unit->global_asm;
        unit->global_asm         = statement;
 
@@ -10143,7 +10032,7 @@ static void parse_linkage_specification(void)
        eat(T_extern);
 
        source_position_t const pos     = *HERE;
-       char const       *const linkage = parse_string_literals().begin;
+       char const       *const linkage = parse_string_literals(NULL).begin;
 
        linkage_kind_t old_linkage = current_linkage;
        linkage_kind_t new_linkage;