static struct obstack temp_obst;
static entity_t *anonymous_entity;
static declaration_t **incomplete_arrays;
+static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
#define PUSH_PARENT(stmt) \
TYPE_QUALIFIERS \
TYPE_SPECIFIERS
-#define TYPENAME_START \
- TYPE_QUALIFIERS \
- TYPE_SPECIFIERS
-
#define EXPRESSION_START \
case '!': \
case '&': \
[STATEMENT_MS_TRY] = sizeof(ms_try_statement_t),
[STATEMENT_LEAVE] = sizeof(leave_statement_t)
};
- assert(kind < lengthof(sizes));
+ assert((size_t)kind < lengthof(sizes));
assert(sizes[kind] != 0);
return sizes[kind];
}
[EXPR_INVALID] = sizeof(expression_base_t),
[EXPR_REFERENCE] = sizeof(reference_expression_t),
[EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t),
+ [EXPR_LITERAL_BOOLEAN] = sizeof(literal_expression_t),
[EXPR_LITERAL_INTEGER] = sizeof(literal_expression_t),
[EXPR_LITERAL_INTEGER_OCTAL] = sizeof(literal_expression_t),
[EXPR_LITERAL_INTEGER_HEXADECIMAL]= sizeof(literal_expression_t),
if (kind >= EXPR_BINARY_FIRST && kind <= EXPR_BINARY_LAST) {
return sizes[EXPR_BINARY_FIRST];
}
- assert(kind < lengthof(sizes));
+ assert((size_t)kind < lengthof(sizes));
assert(sizes[kind] != 0);
return sizes[kind];
}
[INITIALIZER_LIST] = sizeof(initializer_list_t),
[INITIALIZER_DESIGNATOR] = sizeof(initializer_designator_t)
};
- assert(kind < lengthof(sizes));
+ assert((size_t)kind < lengthof(sizes));
assert(sizes[kind] != 0);
return sizes[kind];
}
static entity_t *get_entity(const symbol_t *const symbol,
namespace_tag_t namespc)
{
+ assert(namespc != NAMESPACE_INVALID);
entity_t *entity = symbol->entity;
for (; entity != NULL; entity = entity->base.symbol_next) {
- if (entity->base.namespc == namespc)
+ if ((namespace_tag_t)entity->base.namespc == namespc)
return entity;
}
entity_kind_tag_t const kind)
{
entity_t *entity = get_entity(symbol, NAMESPACE_TAG);
- if (entity != NULL && entity->kind != kind) {
+ if (entity != NULL && (entity_kind_tag_t)entity->kind != kind) {
errorf(HERE,
"'%Y' defined as wrong kind of tag (previous definition %P)",
symbol, &entity->base.source_position);
}
type_t *const type = skip_typeref(expression->base.type);
- return
- is_type_integer(type) &&
- is_constant_expression(expression) &&
- !fold_constant_to_bool(expression);
+ if (!is_type_integer(type))
+ return false;
+ switch (is_constant_expression(expression)) {
+ case EXPR_CLASS_ERROR: return true;
+ case EXPR_CLASS_CONSTANT: return !fold_constant_to_bool(expression);
+ default: return false;
+ }
}
/**
(is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
&& is_type_pointer(type_right))) {
return ASSIGN_SUCCESS;
- } else if ((is_type_compound(type_left) && is_type_compound(type_right))
- || (is_type_builtin(type_left) && is_type_builtin(type_right))) {
+ } else if (is_type_compound(type_left) && is_type_compound(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)) {
{
expression_t *result = parse_subexpression(PREC_CONDITIONAL);
- if (!is_constant_expression(result)) {
+ if (is_constant_expression(result) == EXPR_CLASS_VARIABLE) {
errorf(&result->base.source_position,
"expression '%E' is not constant", result);
}
return NULL;
}
- const char *name = symbol->string;
- next_token();
+ attribute_kind_t kind;
+ char const *const name = symbol->string;
+ for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) {
+ if (kind > ATTRIBUTE_GNU_LAST) {
+ if (warning.attribute) {
+ warningf(HERE, "unknown attribute '%s' ignored", name);
+ }
+ /* TODO: we should still save the attribute in the list... */
+ kind = ATTRIBUTE_UNKNOWN;
+ break;
+ }
- attribute_kind_t kind;
- for (kind = ATTRIBUTE_GNU_FIRST; kind <= ATTRIBUTE_GNU_LAST; ++kind) {
const char *attribute_name = get_attribute_name(kind);
if (attribute_name != NULL
&& strcmp_underscore(attribute_name, name) == 0)
break;
}
- if (kind >= ATTRIBUTE_GNU_LAST) {
- if (warning.attribute) {
- warningf(HERE, "unknown attribute '%s' ignored", name);
- }
- /* TODO: we should still save the attribute in the list... */
- kind = ATTRIBUTE_UNKNOWN;
- }
+ next_token();
attribute_t *attribute = allocate_attribute_zero(kind);
switch (token.type) {
case T___attribute__:
attribute = parse_attribute_gnu();
+ if (attribute == NULL)
+ continue;
break;
case T_asm:
break;
case T___thiscall:
- next_token();
/* TODO record modifier */
if (warning.other)
warningf(HERE, "Ignoring declaration modifier %K", &token);
+ eat(T___thiscall);
attribute = allocate_attribute_zero(ATTRIBUTE_MS_THISCALL);
break;
}
/**
- * Checks if a given expression can be used as an constant initializer.
+ * Checks if a given expression can be used as a constant initializer.
*/
static bool is_initializer_constant(const expression_t *expression)
{
- return is_constant_expression(expression)
- || is_address_constant(expression);
+ return is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
+ is_linker_constant(expression) != EXPR_CLASS_VARIABLE;
}
/**
{
/* there might be extra {} hierarchies */
int braces = 0;
- if (next_if('{')) {
+ if (token.type == '{') {
if (warning.other)
warningf(HERE, "extra curly braces around scalar initializer");
do {
+ eat('{');
++braces;
- } while (next_if('{'));
+ } while (token.type == '{');
}
expression_t *expression = parse_assignment_expression();
if (iter == NULL) {
errorf(&designator->source_position,
"'%T' has no member named '%Y'", orig_type, symbol);
- goto failed;
+ return false;
}
assert(iter->kind == ENTITY_COMPOUND_MEMBER);
if (used_in_offsetof) {
errorf(&designator->source_position,
"offsetof designator '%Y' must not specify bitfield",
symbol);
- goto failed;
+ return false;
}
}
"[%E] designator used for non-array type '%T'",
array_index, orig_type);
}
- goto failed;
+ return false;
}
long index = fold_constant_to_int(array_index);
}
}
return true;
-
-failed:
- return false;
}
static void advance_current_object(type_path_t *path, size_t top_path_level)
if (type != NULL && is_type_scalar(type)) {
sub = parse_scalar_initializer(type, env->must_be_constant);
} else {
- eat('{');
if (type == NULL) {
if (env->entity != NULL) {
errorf(HERE,
} else {
errorf(HERE, "extra brace group at end of initializer");
}
- } else
+ eat('{');
+ } else {
+ eat('{');
descend_into_subtype(path);
+ }
add_anchor_token('}');
sub = parse_sub_initializer(path, orig_type, top_path_level+1,
goto error_parse_next;
type_t *const outer_type_skip = skip_typeref(outer_type);
if (is_type_compound(outer_type_skip) &&
- !outer_type_skip->compound.compound->complete) {
+ !outer_type_skip->compound.compound->complete) {
goto error_parse_next;
}
- goto error_excess;
+
+ if (warning.other) {
+ source_position_t const* const pos = &expression->base.source_position;
+ if (env->entity != NULL) {
+ warningf(pos, "excess elements in initializer for '%Y'", env->entity->base.symbol);
+ } else {
+ warningf(pos, "excess elements in initializer");
+ }
+ }
+ goto error_parse_next;
}
/* handle { "string" } special case */
path->max_index = index;
}
- if (type != NULL) {
- /* append to initializers list */
- ARR_APP1(initializer_t*, initializers, sub);
- } else {
-error_excess:
- if (warning.other) {
- if (env->entity != NULL) {
- warningf(HERE, "excess elements in initializer for '%Y'",
- env->entity->base.symbol);
- } else {
- warningf(HERE, "excess elements in initializer");
- }
- }
- }
+ /* append to initializers list */
+ ARR_APP1(initializer_t*, initializers, sub);
error_parse_next:
if (token.type == '}') {
DEL_ARR_F(path.path);
expect('}', end_error);
+end_error:;
} else {
/* parse_scalar_initializer() also works in this case: we simply
* have an expression without {} around it */
}
return result;
-end_error:
- return NULL;
}
static void append_entity(scope_t *scope, entity_t *entity)
static compound_t *parse_compound_type_specifier(bool is_struct)
{
+ source_position_t const pos = *HERE;
eat(is_struct ? T_struct : T_union);
- symbol_t *symbol = NULL;
- compound_t *compound = NULL;
+ symbol_t *symbol = NULL;
+ entity_t *entity = NULL;
attribute_t *attributes = NULL;
if (token.type == T___attribute__) {
if (token.type == T_IDENTIFIER) {
/* the compound has a name, check if we have seen it already */
symbol = token.symbol;
+ entity = get_tag(symbol, kind);
next_token();
- entity_t *entity = get_tag(symbol, kind);
if (entity != NULL) {
- compound = &entity->compound;
- if (compound->base.parent_scope != current_scope &&
+ if (entity->base.parent_scope != current_scope &&
(token.type == '{' || token.type == ';')) {
/* we're in an inner scope and have a definition. Shadow
* existing definition in outer scope */
- compound = NULL;
- } else if (compound->complete && token.type == '{') {
- assert(symbol != NULL);
- errorf(HERE, "multiple definitions of '%s %Y' (previous definition %P)",
- is_struct ? "struct" : "union", symbol,
- &compound->base.source_position);
+ entity = NULL;
+ } else if (entity->compound.complete && token.type == '{') {
+ source_position_t const *const ppos = &entity->base.source_position;
+ errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
/* clear members in the hope to avoid further errors */
- compound->members.entities = NULL;
+ entity->compound.members.entities = NULL;
}
}
} else if (token.type != '{') {
- if (is_struct) {
- parse_error_expected("while parsing struct type specifier",
- T_IDENTIFIER, '{', NULL);
- } else {
- parse_error_expected("while parsing union type specifier",
- T_IDENTIFIER, '{', NULL);
- }
+ char const *const msg =
+ is_struct ? "while parsing struct type specifier" :
+ "while parsing union type specifier";
+ parse_error_expected(msg, T_IDENTIFIER, '{', NULL);
return NULL;
}
- if (compound == NULL) {
- entity_t *entity = allocate_entity_zero(kind);
- compound = &entity->compound;
-
- compound->alignment = 1;
- compound->base.namespc = NAMESPACE_TAG;
- compound->base.source_position = token.source_position;
- compound->base.symbol = symbol;
- compound->base.parent_scope = current_scope;
+ if (entity == NULL) {
+ entity = allocate_entity_zero(kind, NAMESPACE_TAG, symbol);
+ entity->compound.alignment = 1;
+ entity->base.source_position = pos;
+ entity->base.parent_scope = current_scope;
if (symbol != NULL) {
environment_push(entity);
}
}
if (token.type == '{') {
- parse_compound_type_entries(compound);
+ parse_compound_type_entries(&entity->compound);
/* ISO/IEC 14882:1998(E) §7.1.3:5 */
if (symbol == NULL) {
assert(anonymous_entity == NULL);
- anonymous_entity = (entity_t*)compound;
+ anonymous_entity = entity;
}
}
if (attributes != NULL) {
- handle_entity_attributes(attributes, (entity_t*) compound);
+ handle_entity_attributes(attributes, entity);
}
- return compound;
+ return &entity->compound;
}
static void parse_enum_entries(type_t *const enum_type)
return;
}
- entity_t *entity = allocate_entity_zero(ENTITY_ENUM_VALUE);
+ entity_t *const entity = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, token.symbol);
entity->enum_value.enum_type = enum_type;
- entity->base.symbol = token.symbol;
entity->base.source_position = token.source_position;
next_token();
static type_t *parse_enum_specifier(void)
{
- entity_t *entity;
- symbol_t *symbol;
+ source_position_t const pos = *HERE;
+ entity_t *entity;
+ symbol_t *symbol;
eat(T_enum);
switch (token.type) {
case T_IDENTIFIER:
symbol = token.symbol;
+ entity = get_tag(symbol, ENTITY_ENUM);
next_token();
- entity = get_tag(symbol, ENTITY_ENUM);
if (entity != NULL) {
if (entity->base.parent_scope != current_scope &&
(token.type == '{' || token.type == ';')) {
* existing definition in outer scope */
entity = NULL;
} else if (entity->enume.complete && token.type == '{') {
- errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
- symbol, &entity->base.source_position);
+ source_position_t const *const ppos = &entity->base.source_position;
+ errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
}
}
break;
}
if (entity == NULL) {
- entity = allocate_entity_zero(ENTITY_ENUM);
- entity->base.namespc = NAMESPACE_TAG;
- entity->base.source_position = token.source_position;
- entity->base.symbol = symbol;
+ entity = allocate_entity_zero(ENTITY_ENUM, NAMESPACE_TAG, symbol);
+ entity->base.source_position = pos;
entity->base.parent_scope = current_scope;
}
anonymous_entity = entity;
}
} else if (!entity->enume.complete && !(c_mode & _GNUC)) {
- errorf(HERE, "'enum %Y' used before definition (incomplete enums are a GNU extension)",
- symbol);
+ errorf(HERE, "'%T' used before definition (incomplete enums are a GNU extension)", type);
}
return type;
switch (token.type) {
case T_IDENTIFIER:
if (is_typedef_symbol(token.symbol)) {
- TYPENAME_START
+ DECLARATION_START
type = parse_typename();
} else {
default:
SPECIFIER_IMAGINARY = 1 << 18,
} specifiers_t;
-static type_t *create_builtin_type(symbol_t *const symbol,
- type_t *const real_type)
-{
- type_t *type = allocate_type_zero(TYPE_BUILTIN);
- type->builtin.symbol = symbol;
- type->builtin.real_type = real_type;
- return identify_new_type(type);
-}
-
static type_t *get_typedef_type(symbol_t *symbol)
{
entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
goto end_error;
}
- bool is_put;
- symbol_t *symbol = token.symbol;
- next_token();
+ symbol_t **prop;
+ symbol_t *symbol = token.symbol;
if (strcmp(symbol->string, "put") == 0) {
- is_put = true;
+ prop = &property->put_symbol;
} else if (strcmp(symbol->string, "get") == 0) {
- is_put = false;
+ prop = &property->get_symbol;
} else {
errorf(HERE, "expected put or get in property declspec");
- goto end_error;
+ prop = NULL;
}
+ eat(T_IDENTIFIER);
expect('=', end_error);
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing property declspec",
T_IDENTIFIER, NULL);
goto end_error;
}
- if (is_put) {
- property->put_symbol = token.symbol;
- } else {
- property->get_symbol = token.symbol;
- }
+ if (prop != NULL)
+ *prop = token.symbol;
next_token();
} while (next_if(','));
kind = ATTRIBUTE_MS_RESTRICT;
} else if (token.type == T_IDENTIFIER) {
const char *name = token.symbol->string;
- next_token();
for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
++k) {
const char *attribute_name = get_attribute_name(k);
if (kind == ATTRIBUTE_UNKNOWN && warning.attribute) {
warningf(HERE, "unknown __declspec '%s' ignored", name);
}
+ eat(T_IDENTIFIER);
} else {
parse_error_expected("while parsing __declspec", T_IDENTIFIER, NULL);
return NULL;
static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
{
- entity_t *entity = allocate_entity_zero(kind);
+ entity_t *const entity = allocate_entity_zero(kind, NAMESPACE_NORMAL, symbol);
entity->base.source_position = *HERE;
- entity->base.symbol = symbol;
if (is_declaration(entity)) {
entity->declaration.type = type_error_type;
entity->declaration.implicit = true;
bool saw_error = false;
bool old_gcc_extension = in_gcc_extension;
+ memset(specifiers, 0, sizeof(*specifiers));
specifiers->source_position = token.source_position;
while (true) {
case T_long:
if (type_specifiers & SPECIFIER_LONG_LONG) {
- errorf(HERE, "multiple type specifiers given");
+ errorf(HERE, "too many long type specifiers given");
} else if (type_specifiers & SPECIFIER_LONG) {
type_specifiers |= SPECIFIER_LONG_LONG;
} else {
break;
#define CHECK_DOUBLE_TYPE() \
+ do { \
if ( type != NULL) \
- errorf(HERE, "multiple data types in declaration specifiers");
+ errorf(HERE, "multiple data types in declaration specifiers"); \
+ } while(0)
case T_struct:
CHECK_DOUBLE_TYPE();
next_token();
saw_error = true;
- if (la1_type == '&' || la1_type == '*')
- goto finish_specifiers;
continue;
}
case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
break;
- default:
+ default: {
/* invalid specifier combination, give an error message */
+ source_position_t const* const pos = &specifiers->source_position;
if (type_specifiers == 0) {
- if (saw_error)
- goto end_error;
-
- /* ISO/IEC 14882:1998(E) §C.1.5:4 */
- if (!(c_mode & _CXX) && !strict_mode) {
- if (warning.implicit_int) {
- warningf(HERE, "no type specifiers in declaration, using 'int'");
+ if (!saw_error) {
+ /* ISO/IEC 14882:1998(E) §C.1.5:4 */
+ if (!(c_mode & _CXX) && !strict_mode) {
+ if (warning.implicit_int) {
+ warningf(pos, "no type specifiers in declaration, using 'int'");
+ }
+ atomic_type = ATOMIC_TYPE_INT;
+ break;
+ } else {
+ errorf(pos, "no type specifiers given in declaration");
}
- atomic_type = ATOMIC_TYPE_INT;
- break;
- } else {
- errorf(HERE, "no type specifiers given in declaration");
}
} else if ((type_specifiers & SPECIFIER_SIGNED) &&
(type_specifiers & SPECIFIER_UNSIGNED)) {
- errorf(HERE, "signed and unsigned specifiers given");
+ errorf(pos, "signed and unsigned specifiers given");
} else if (type_specifiers & (SPECIFIER_SIGNED | SPECIFIER_UNSIGNED)) {
- errorf(HERE, "only integer types can be signed or unsigned");
+ errorf(pos, "only integer types can be signed or unsigned");
} else {
- errorf(HERE, "multiple datatypes in declaration");
+ errorf(pos, "multiple datatypes in declaration");
}
goto end_error;
}
+ }
if (type_specifiers & SPECIFIER_COMPLEX) {
type = allocate_type_zero(TYPE_COMPLEX);
}
newtype = true;
} else if (type_specifiers != 0) {
- errorf(HERE, "multiple datatypes in declaration");
+ errorf(&specifiers->source_position, "multiple datatypes in declaration");
}
/* FIXME: check type qualifiers here */
static void parse_identifier_list(scope_t *scope)
{
do {
- entity_t *entity = allocate_entity_zero(ENTITY_PARAMETER);
+ entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.symbol);
entity->base.source_position = token.source_position;
- entity->base.namespc = NAMESPACE_NORMAL;
- entity->base.symbol = token.symbol;
/* a K&R parameter has no type, yet */
next_token();
static entity_t *parse_parameter(void)
{
declaration_specifiers_t specifiers;
- memset(&specifiers, 0, sizeof(specifiers));
-
parse_declaration_specifiers(&specifiers);
entity_t *entity = parse_declarator(&specifiers,
* incomplete type. */
type_t *type = skip_typeref(entity->declaration.type);
if (is_type_incomplete(type)) {
- errorf(&entity->base.source_position,
- "parameter '%#T' has incomplete type",
- entity->declaration.type, entity->base.symbol);
+ errorf(&entity->base.source_position, "'%N' has incomplete type", entity);
}
}
/* ISO/IEC 14882:1998(E) §C.1.6:1 */
if (!(c_mode & _CXX))
type->unspecified_parameters = true;
- goto parameters_finished;
- }
-
- if (has_parameters()) {
+ } else if (has_parameters()) {
function_parameter_t **anchor = &type->parameters;
do {
switch (token.type) {
} while (next_if(','));
}
-
parameters_finished:
rem_anchor_token(')');
expect(')', end_error);
typedef struct construct_type_base_t {
construct_type_kind_t kind;
+ source_position_t pos;
construct_type_t *next;
} construct_type_base_t;
{
construct_type_t *const cons = obstack_alloc(&temp_obst, size);
memset(cons, 0, size);
- cons->kind = kind;
+ cons->kind = kind;
+ cons->base.pos = *HERE;
return cons;
}
/* §6.7.5.1 */
static construct_type_t *parse_pointer_declarator(void)
{
- eat('*');
-
construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_POINTER, sizeof(parsed_pointer_t));
+ eat('*');
cons->pointer.type_qualifiers = parse_type_qualifiers();
//cons->pointer.base_variable = base_variable;
/* ISO/IEC 14882:1998(E) §8.3.2 */
static construct_type_t *parse_reference_declarator(void)
{
- eat('&');
-
if (!(c_mode & _CXX))
errorf(HERE, "references are only available for C++");
construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_REFERENCE, sizeof(parsed_reference_t));
+ eat('&');
return cons;
}
/* §6.7.5.2 */
static construct_type_t *parse_array_declarator(void)
{
- eat('[');
- add_anchor_token(']');
-
construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_ARRAY, sizeof(parsed_array_t));
parsed_array_t *const array = &cons->array;
+ eat('[');
+ add_anchor_token(']');
+
bool is_static = next_if(T_static);
type_qualifiers_t type_qualifiers = parse_type_qualifiers();
}
if (is_static && size == NULL)
- errorf(HERE, "static array parameters require a size");
+ errorf(&array->base.pos, "static array parameters require a size");
rem_anchor_token(']');
expect(']', end_error);
/* §6.7.5.3 */
static construct_type_t *parse_function_declarator(scope_t *scope)
{
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t));
+
type_t *type = allocate_type_zero(TYPE_FUNCTION);
function_type_t *ftype = &type->function;
parse_parameters(ftype, scope);
- construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t));
cons->function.function_type = type;
return cons;
}
next_token();
break;
- case '(':
- /* §6.7.6:2 footnote 126: Empty parentheses in a type name are
- * interpreted as ``function with no parameter specification'', rather
- * than redundant parentheses around the omitted identifier. */
- if (look_ahead(1)->type != ')') {
- next_token();
- add_anchor_token(')');
- inner_types = parse_inner_declarator(env);
- if (inner_types != NULL) {
- /* All later declarators only modify the return type */
- env->must_be_abstract = true;
- }
- rem_anchor_token(')');
- expect(')', end_error);
- } else if (!env->may_be_abstract) {
- errorf(HERE, "declarator must have a name");
- goto error_out;
+
+ case '(': {
+ /* Parenthesized declarator or function declarator? */
+ token_t const *const la1 = look_ahead(1);
+ switch (la1->type) {
+ case T_IDENTIFIER:
+ if (is_typedef_symbol(la1->symbol)) {
+ case ')':
+ /* §6.7.6:2 footnote 126: Empty parentheses in a type name are
+ * interpreted as ``function with no parameter specification'', rather
+ * than redundant parentheses around the omitted identifier. */
+ default:
+ /* Function declarator. */
+ if (!env->may_be_abstract) {
+ errorf(HERE, "function declarator must have a name");
+ }
+ } else {
+ case '&':
+ case '(':
+ case '*':
+ case '[':
+ case T___attribute__: /* FIXME __attribute__ might also introduce a parameter of a function declarator. */
+ /* Paranthesized declarator. */
+ next_token();
+ add_anchor_token(')');
+ inner_types = parse_inner_declarator(env);
+ if (inner_types != NULL) {
+ /* All later declarators only modify the return type */
+ env->must_be_abstract = true;
+ }
+ rem_anchor_token(')');
+ expect(')', end_error);
+ }
+ break;
}
break;
+ }
+
default:
if (env->may_be_abstract)
break;
parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
-error_out:
eat_until_anchor();
return NULL;
}
{
construct_type_t *iter = construct_list;
for (; iter != NULL; iter = iter->base.next) {
+ source_position_t const* const pos = &iter->base.pos;
switch (iter->kind) {
case CONSTRUCT_INVALID:
break;
type_t *skipped_return_type = skip_typeref(type);
/* §6.7.5.3:1 */
if (is_type_function(skipped_return_type)) {
- errorf(HERE, "function returning function is not allowed");
+ errorf(pos, "function returning function is not allowed");
} else if (is_type_array(skipped_return_type)) {
- errorf(HERE, "function returning array is not allowed");
+ errorf(pos, "function returning array is not allowed");
} else {
if (skipped_return_type->base.qualifiers != 0 && warning.other) {
- warningf(HERE,
- "type qualifiers in return type of function type are meaningless");
+ warningf(pos, "type qualifiers in return type of function type are meaningless");
}
}
case CONSTRUCT_POINTER: {
if (is_type_reference(skip_typeref(type)))
- errorf(HERE, "cannot declare a pointer to reference");
+ errorf(pos, "cannot declare a pointer to reference");
parsed_pointer_t *pointer = &iter->pointer;
type = make_based_pointer_type(type, pointer->type_qualifiers, pointer->base_variable);
case CONSTRUCT_REFERENCE:
if (is_type_reference(skip_typeref(type)))
- errorf(HERE, "cannot declare a reference to reference");
+ errorf(pos, "cannot declare a reference to reference");
type = make_reference_type(type);
continue;
case CONSTRUCT_ARRAY: {
if (is_type_reference(skip_typeref(type)))
- errorf(HERE, "cannot declare an array of references");
+ errorf(pos, "cannot declare an array of references");
parsed_array_t *array = &iter->array;
type_t *array_type = allocate_type_zero(TYPE_ARRAY);
array_type->array.size_expression = size_expression;
if (size_expression != NULL) {
- if (is_constant_expression(size_expression)) {
- long const size
- = fold_constant_to_int(size_expression);
+ switch (is_constant_expression(size_expression)) {
+ case EXPR_CLASS_CONSTANT: {
+ long const size = fold_constant_to_int(size_expression);
array_type->array.size = size;
array_type->array.size_constant = true;
- /* §6.7.5.2:1 If the expression is a constant expression, it shall
- * have a value greater than zero. */
- if (size <= 0) {
- if (size < 0 || !GNU_MODE) {
- errorf(&size_expression->base.source_position,
- "size of array must be greater than zero");
- } else if (warning.other) {
- warningf(&size_expression->base.source_position,
- "zero length arrays are a GCC extension");
- }
+ /* §6.7.5.2:1 If the expression is a constant expression,
+ * it shall have a value greater than zero. */
+ if (size < 0) {
+ errorf(&size_expression->base.source_position,
+ "size of array must be greater than zero");
+ } else if (size == 0 && !GNU_MODE) {
+ errorf(&size_expression->base.source_position,
+ "size of array must be greater than zero (zero length arrays are a GCC extension)");
}
- } else {
+ break;
+ }
+
+ case EXPR_CLASS_VARIABLE:
array_type->array.is_vla = true;
+ break;
+
+ case EXPR_CLASS_ERROR:
+ break;
}
}
type_t *skipped_type = skip_typeref(type);
/* §6.7.5.2:1 */
if (is_type_incomplete(skipped_type)) {
- errorf(HERE, "array of incomplete type '%T' is not allowed", type);
+ errorf(pos, "array of incomplete type '%T' is not allowed", type);
} else if (is_type_function(skipped_type)) {
- errorf(HERE, "array of functions is not allowed");
+ errorf(pos, "array of functions is not allowed");
}
type = identify_new_type(array_type);
continue;
}
}
- internal_errorf(HERE, "invalid type construction found");
+ internal_errorf(pos, "invalid type construction found");
}
return type;
static type_t *semantic_parameter(const source_position_t *pos,
type_t *type,
const declaration_specifiers_t *specifiers,
- symbol_t *symbol)
+ entity_t const *const param)
{
/* §6.7.5.3:7 A declaration of a parameter as ``array of type''
* shall be adjusted to ``qualified pointer to type'',
type = automatic_type_conversion(type);
if (specifiers->is_inline && is_type_valid(type)) {
- errorf(pos, "parameter '%#T' declared 'inline'", type, symbol);
+ errorf(pos, "'%N' declared 'inline'", param);
}
/* §6.9.1:6 The declarations in the declaration list shall contain
specifiers->storage_class != STORAGE_CLASS_NONE &&
specifiers->storage_class != STORAGE_CLASS_REGISTER)
) {
- errorf(pos, "invalid storage class for parameter '%#T'", type, symbol);
+ errorf(pos, "invalid storage class for '%N'", param);
}
/* delay test for incomplete type, because we might have (void)
entity_t *entity;
if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
- entity = allocate_entity_zero(ENTITY_TYPEDEF);
- entity->base.symbol = env.symbol;
+ entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol);
entity->base.source_position = env.source_position;
entity->typedefe.type = orig_type;
} else {
/* create a declaration type entity */
if (flags & DECL_CREATE_COMPOUND_MEMBER) {
- entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
+ entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol);
if (env.symbol != NULL) {
if (specifiers->is_inline && is_type_valid(type)) {
}
}
} else if (flags & DECL_IS_PARAMETER) {
- orig_type = semantic_parameter(&env.source_position, orig_type,
- specifiers, env.symbol);
-
- entity = allocate_entity_zero(ENTITY_PARAMETER);
+ entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol);
+ orig_type = semantic_parameter(&env.source_position, orig_type, specifiers, entity);
} else if (is_type_function(type)) {
- entity = allocate_entity_zero(ENTITY_FUNCTION);
-
- entity->function.is_inline = specifiers->is_inline;
- entity->function.parameters = env.parameters;
+ entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol);
+ entity->function.is_inline = specifiers->is_inline;
+ entity->function.elf_visibility = default_visibility;
+ entity->function.parameters = env.parameters;
if (env.symbol != NULL) {
/* this needs fixes for C++ */
specifiers->storage_class != STORAGE_CLASS_NONE &&
(in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
)) {
- errorf(&env.source_position,
- "invalid storage class for function '%Y'", env.symbol);
+ errorf(&env.source_position, "invalid storage class for '%N'", entity);
}
}
} else {
- entity = allocate_entity_zero(ENTITY_VARIABLE);
-
- entity->variable.thread_local = specifiers->thread_local;
+ entity = allocate_entity_zero(ENTITY_VARIABLE, NAMESPACE_NORMAL, env.symbol);
+ entity->variable.elf_visibility = default_visibility;
+ entity->variable.thread_local = specifiers->thread_local;
if (env.symbol != NULL) {
if (specifiers->is_inline && is_type_valid(type)) {
- errorf(&env.source_position,
- "variable '%Y' declared 'inline'", env.symbol);
+ errorf(&env.source_position, "'%N' declared 'inline'", entity);
}
bool invalid_storage_class = false;
}
}
if (invalid_storage_class) {
- errorf(&env.source_position,
- "invalid storage class for variable '%Y'", env.symbol);
+ errorf(&env.source_position, "invalid storage class for variable '%N'", entity);
}
}
}
- if (env.symbol != NULL) {
- entity->base.symbol = env.symbol;
- entity->base.source_position = env.source_position;
- } else {
- entity->base.source_position = specifiers->source_position;
- }
- entity->base.namespc = NAMESPACE_NORMAL;
+ entity->base.source_position = env.symbol != NULL ? env.source_position : specifiers->source_position;
entity->declaration.type = orig_type;
entity->declaration.alignment = get_type_alignment(orig_type);
entity->declaration.modifiers = env.modifiers;
storage_class_t storage_class = specifiers->storage_class;
entity->declaration.declared_storage_class = storage_class;
- if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
+ if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
storage_class = STORAGE_CLASS_AUTO;
entity->declaration.storage_class = storage_class;
}
}
const function_parameter_t *parm = func_type->parameters;
if (parm != NULL) {
- type_t *const first_type = parm->type;
- if (!types_compatible(skip_typeref(first_type), type_int)) {
+ type_t *const first_type = skip_typeref(parm->type);
+ type_t *const first_type_unqual = get_unqualified_type(first_type);
+ if (!types_compatible(first_type_unqual, type_int)) {
warningf(pos,
"first argument of 'main' should be 'int', but is '%T'",
- first_type);
+ parm->type);
}
parm = parm->next;
if (parm != NULL) {
- type_t *const second_type = parm->type;
- if (!types_compatible(skip_typeref(second_type), type_char_ptr_ptr)) {
- warningf(pos, "second argument of 'main' should be 'char**', but is '%T'", second_type);
+ type_t *const second_type = skip_typeref(parm->type);
+ type_t *const second_type_unqual
+ = get_unqualified_type(second_type);
+ if (!types_compatible(second_type_unqual, type_char_ptr_ptr)) {
+ warningf(pos, "second argument of 'main' should be 'char**', but is '%T'",
+ parm->type);
}
parm = parm->next;
if (parm != NULL) {
- type_t *const third_type = parm->type;
- if (!types_compatible(skip_typeref(third_type), type_char_ptr_ptr)) {
- warningf(pos, "third argument of 'main' should be 'char**', but is '%T'", third_type);
+ type_t *const third_type = skip_typeref(parm->type);
+ type_t *const third_type_unqual
+ = get_unqualified_type(third_type);
+ if (!types_compatible(third_type_unqual, type_char_ptr_ptr)) {
+ warningf(pos, "third argument of 'main' should be 'char**', but is '%T'",
+ parm->type);
}
parm = parm->next;
if (parm != NULL)
static void error_redefined_as_different_kind(const source_position_t *pos,
const entity_t *old, entity_kind_t new_kind)
{
- errorf(pos, "redeclaration of %s '%Y' as %s (declared %P)",
- get_entity_kind_name(old->kind), old->base.symbol,
- get_entity_kind_name(new_kind), &old->base.source_position);
+ char const *const what = get_entity_kind_name(new_kind);
+ source_position_t const *const ppos = &old->base.source_position;
+ errorf(pos, "redeclaration of '%N' as %s (declared %P)", old, what, ppos);
}
-static bool is_error_entity(entity_t *const ent)
+static bool is_entity_valid(entity_t *const ent)
{
if (is_declaration(ent)) {
return is_type_valid(skip_typeref(ent->declaration.type));
} else if (ent->kind == ENTITY_TYPEDEF) {
return is_type_valid(skip_typeref(ent->typedefe.type));
}
- return false;
+ return true;
}
static bool contains_attribute(const attribute_t *list, const attribute_t *attr)
assert(is_type_function(type));
if (type->function.unspecified_parameters &&
- warning.strict_prototypes &&
- previous_entity == NULL) {
- warningf(pos, "function declaration '%#T' is not a prototype",
- orig_type, symbol);
+ warning.strict_prototypes &&
+ previous_entity == NULL &&
+ !entity->declaration.implicit) {
+ warningf(pos, "function declaration '%#N' is not a prototype", entity);
}
if (warning.main && current_scope == file_scope
}
}
- if (is_declaration(entity) &&
- warning.nested_externs &&
- entity->declaration.storage_class == STORAGE_CLASS_EXTERN &&
- current_scope != file_scope) {
- warningf(pos, "nested extern declaration of '%#T'",
- entity->declaration.type, symbol);
+ if (is_declaration(entity) &&
+ warning.nested_externs &&
+ entity->declaration.storage_class == STORAGE_CLASS_EXTERN &&
+ current_scope != file_scope &&
+ !entity->declaration.implicit) {
+ warningf(pos, "nested extern declaration of '%#N'", entity);
}
if (previous_entity != NULL) {
+ source_position_t const *const ppos = &previous_entity->base.source_position;
+
if (previous_entity->base.parent_scope == ¤t_function->parameters &&
previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
assert(previous_entity->kind == ENTITY_PARAMETER);
- errorf(pos,
- "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
- entity->declaration.type, symbol,
- previous_entity->declaration.type, symbol,
- &previous_entity->base.source_position);
+ errorf(pos, "declaration of '%N' redeclares the '%N' (declared %P)", entity, previous_entity, ppos);
goto finish;
}
if (previous_entity->base.parent_scope == current_scope) {
if (previous_entity->kind != entity->kind) {
- if (!is_error_entity(previous_entity) && !is_error_entity(entity)) {
+ if (is_entity_valid(previous_entity) && is_entity_valid(entity)) {
error_redefined_as_different_kind(pos, previous_entity,
entity->kind);
}
goto finish;
}
if (previous_entity->kind == ENTITY_ENUM_VALUE) {
- errorf(pos, "redeclaration of enum entry '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
+ errorf(pos, "redeclaration of '%N' (declared %P)", entity, ppos);
goto finish;
}
if (previous_entity->kind == ENTITY_TYPEDEF) {
/* TODO: C++ allows this for exactly the same type */
- errorf(pos, "redefinition of typedef '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
+ errorf(pos, "redefinition of '%N' (declared %P)", entity, ppos);
goto finish;
}
return previous_entity;
}
- type_t *const orig_type = decl->type;
- assert(orig_type != NULL);
- type_t *const type = skip_typeref(orig_type);
+ type_t *const type = skip_typeref(decl->type);
type_t *const prev_type = skip_typeref(prev_decl->type);
if (!types_compatible(type, prev_type)) {
- errorf(pos,
- "declaration '%#T' is incompatible with '%#T' (declared %P)",
- orig_type, symbol, prev_decl->type, symbol,
- &previous_entity->base.source_position);
+ errorf(pos, "declaration '%#N' is incompatible with '%#N' (declared %P)", entity, previous_entity, ppos);
} else {
unsigned old_storage_class = prev_decl->storage_class;
- if (warning.redundant_decls &&
+ if (warning.redundant_decls &&
is_definition &&
!prev_decl->used &&
!(prev_decl->modifiers & DM_USED) &&
prev_decl->storage_class == STORAGE_CLASS_STATIC) {
- warningf(&previous_entity->base.source_position,
- "unnecessary static forward declaration for '%#T'",
- prev_decl->type, symbol);
+ warningf(ppos, "unnecessary static forward declaration for '%#N'", previous_entity);
}
storage_class_t new_storage_class = decl->storage_class;
if (warning.missing_prototypes &&
prev_type->function.unspecified_parameters &&
!is_sym_main(symbol)) {
- warningf(pos, "no previous prototype for '%#T'",
- orig_type, symbol);
+ warningf(pos, "no previous prototype for '%#N'", entity);
}
} else if (new_storage_class == STORAGE_CLASS_NONE) {
new_storage_class = STORAGE_CLASS_EXTERN;
} else if (!is_definition &&
warning.redundant_decls &&
is_type_valid(prev_type) &&
- strcmp(previous_entity->base.source_position.input_name,
- "<builtin>") != 0) {
- warningf(pos,
- "redundant declaration for '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
+ strcmp(ppos->input_name, "<builtin>") != 0) {
+ warningf(pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos);
}
} else if (current_function == NULL) {
if (old_storage_class != STORAGE_CLASS_STATIC &&
new_storage_class == STORAGE_CLASS_STATIC) {
- errorf(pos,
- "static declaration of '%Y' follows non-static declaration (declared %P)",
- symbol, &previous_entity->base.source_position);
+ errorf(pos, "static declaration of '%Y' follows non-static declaration (declared %P)", symbol, ppos);
} else if (old_storage_class == STORAGE_CLASS_EXTERN) {
prev_decl->storage_class = STORAGE_CLASS_NONE;
prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
} else if (is_type_valid(prev_type)) {
if (old_storage_class == new_storage_class) {
error_redeclaration:
- errorf(pos, "redeclaration of '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
+ errorf(pos, "redeclaration of '%Y' (declared %P)", symbol, ppos);
} else {
- errorf(pos,
- "redeclaration of '%Y' with different linkage (declared %P)",
- symbol, &previous_entity->base.source_position);
+ errorf(pos, "redeclaration of '%Y' with different linkage (declared %P)", symbol, ppos);
}
}
}
return previous_entity;
}
- if (warning.shadow) {
- warningf(pos, "%s '%Y' shadows %s (declared %P)",
- get_entity_kind_name(entity->kind), symbol,
- get_entity_kind_name(previous_entity->kind),
- &previous_entity->base.source_position);
+ if (warning.shadow ||
+ (warning.shadow_local && previous_entity->base.parent_scope != file_scope)) {
+ char const *const what = get_entity_kind_name(previous_entity->kind);
+ warningf(pos, "'%N' shadows %s (declared %P)", entity, what, ppos);
}
}
if (is_definition &&
entity->declaration.storage_class != STORAGE_CLASS_STATIC) {
if (warning.missing_prototypes && !is_sym_main(symbol)) {
- warningf(pos, "no previous prototype for '%#T'",
- entity->declaration.type, symbol);
+ warningf(pos, "no previous prototype for '%#N'", entity);
} else if (warning.missing_declarations && !is_sym_main(symbol)) {
- warningf(pos, "no previous declaration for '%#T'",
- entity->declaration.type, symbol);
+ warningf(pos, "no previous declaration for '%#N'", entity);
}
}
- } else if (warning.missing_declarations &&
- entity->kind == ENTITY_VARIABLE &&
- current_scope == file_scope) {
- declaration_t *declaration = &entity->declaration;
- if (declaration->storage_class == STORAGE_CLASS_NONE) {
- warningf(pos, "no previous declaration for '%#T'",
- declaration->type, symbol);
+ } else if (entity->kind == ENTITY_VARIABLE) {
+ if (warning.missing_declarations &&
+ current_scope == file_scope &&
+ entity->declaration.storage_class == STORAGE_CLASS_NONE) {
+ warningf(pos, "no previous declaration for '%#N'", entity);
}
}
assert(current_scope != NULL);
entity->base.parent_scope = current_scope;
- entity->base.namespc = NAMESPACE_NORMAL;
environment_push(entity);
append_entity(current_scope, entity);
entity->base.symbol, &entity->base.source_position);
}
-static bool is_declaration_specifier(const token_t *token,
- bool only_specifiers_qualifiers)
+static bool is_declaration_specifier(const token_t *token)
{
switch (token->type) {
- TYPE_SPECIFIERS
- TYPE_QUALIFIERS
+ DECLARATION_START
return true;
case T_IDENTIFIER:
return is_typedef_symbol(token->symbol);
- case T___extension__:
- STORAGE_CLASSES
- return !only_specifiers_qualifiers;
-
default:
return false;
}
static void parse_init_declarator_rest(entity_t *entity)
{
- assert(is_declaration(entity));
- declaration_t *const declaration = &entity->declaration;
+ type_t *orig_type = type_error_type;
- eat('=');
+ if (entity->base.kind == ENTITY_TYPEDEF) {
+ source_position_t const *const pos = &entity->base.source_position;
+ errorf(pos, "'%N' is initialized (use __typeof__ instead)", entity);
+ } else {
+ assert(is_declaration(entity));
+ orig_type = entity->declaration.type;
+ }
- type_t *orig_type = declaration->type;
- type_t *type = skip_typeref(orig_type);
+ type_t *type = skip_typeref(orig_type);
if (entity->kind == ENTITY_VARIABLE
&& entity->variable.initializer != NULL) {
parser_error_multiple_definition(entity, HERE);
}
+ eat('=');
+ declaration_t *const declaration = &entity->declaration;
bool must_be_constant = false;
if (declaration->storage_class == STORAGE_CLASS_STATIC ||
entity->base.parent_scope == file_scope) {
}
if (is_type_function(type)) {
- errorf(&entity->base.source_position,
- "function '%#T' is initialized like a variable",
- orig_type, entity->base.symbol);
+ source_position_t const *const pos = &entity->base.source_position;
+ errorf(pos, "'%N' is initialized like a variable", entity);
orig_type = type_error_type;
}
decl->storage_class == STORAGE_CLASS_STATIC)
return;
- type_t *const orig_type = decl->type;
- type_t *const type = skip_typeref(orig_type);
+ type_t *const type = skip_typeref(decl->type);
if (!is_type_incomplete(type))
return;
return;
}
- errorf(&ent->base.source_position, "variable '%#T' has incomplete type",
- orig_type, ent->base.symbol);
+ errorf(&ent->base.source_position, "variable '%#N' has incomplete type", ent);
}
if (decl->storage_class != STORAGE_CLASS_EXTERN) {
type_t *type = decl->type;
if (is_type_reference(skip_typeref(type))) {
- errorf(&entity->base.source_position,
- "reference '%#T' must be initialized",
- type, entity->base.symbol);
+ source_position_t const *const pos = &entity->base.source_position;
+ errorf(pos, "reference '%#N' must be initialized", entity);
}
}
}
static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition)
{
symbol_t *symbol = entity->base.symbol;
- if (symbol == NULL) {
- errorf(HERE, "anonymous declaration not valid as function parameter");
+ if (symbol == NULL)
return entity;
- }
assert(entity->base.namespc == NAMESPACE_NORMAL);
entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL);
if (previous_entity == NULL
|| previous_entity->base.parent_scope != current_scope) {
- errorf(HERE, "expected declaration of a function parameter, found '%Y'",
+ errorf(&entity->base.source_position, "expected declaration of a function parameter, found '%Y'",
symbol);
return entity;
}
if (is_definition) {
- errorf(HERE, "parameter '%Y' is initialised", entity->base.symbol);
+ errorf(HERE, "'%N' is initialised", entity);
}
return record_entity(entity, false);
static void parse_declaration(parsed_declaration_func finished_declaration,
declarator_flags_t flags)
{
- declaration_specifiers_t specifiers;
- memset(&specifiers, 0, sizeof(specifiers));
-
add_anchor_token(';');
+ declaration_specifiers_t specifiers;
parse_declaration_specifiers(&specifiers);
rem_anchor_token(';');
type_t *parameter_type = parameter->declaration.type;
if (parameter_type == NULL) {
+ source_position_t const* const pos = ¶meter->base.source_position;
if (strict_mode) {
- errorf(HERE, "no type specified for function parameter '%Y'",
- parameter->base.symbol);
+ errorf(pos, "no type specified for function '%N'", parameter);
parameter_type = type_error_type;
} else {
if (warning.implicit_int) {
- warningf(HERE, "no type specified for function parameter '%Y', using 'int'",
- parameter->base.symbol);
+ warningf(pos, "no type specified for function '%N', using 'int'", parameter);
}
parameter_type = type_int;
}
parameter_type = not_promoted;
}
}
- function_parameter_t *const parameter
+ function_parameter_t *const function_parameter
= allocate_parameter(parameter_type);
- *anchor = parameter;
- anchor = ¶meter->next;
+ *anchor = function_parameter;
+ anchor = &function_parameter->next;
}
new_type->function.parameters = parameters;
new_type = identify_new_type(new_type);
if (warning.other && need_incompatible_warning) {
- type_t *proto_type_type = proto_type->declaration.type;
- warningf(HERE,
- "declaration '%#T' is incompatible with '%#T' (declared %P)",
- proto_type_type, proto_type->base.symbol,
- new_type, entity->base.symbol,
- &proto_type->base.source_position);
+ source_position_t const *const pos = &entity->base.source_position;
+ source_position_t const *const ppos = &proto_type->base.source_position;
+ symbol_t const *const sym = entity->base.symbol;
+ warningf(pos, "declaration '%#N' is incompatible with '%#T' (declared %P)", proto_type, new_type, sym, ppos);
}
-
entity->declaration.type = new_type;
rem_anchor_token('{');
{
if (first_err) {
first_err = false;
- diagnosticf("%s: In function '%Y':\n",
- current_function->base.base.source_position.input_name,
- current_function->base.base.symbol);
+ char const *const file = current_function->base.base.source_position.input_name;
+ diagnosticf("%s: In '%N':\n", file, (entity_t const*)current_function);
}
}
continue;
label_t *label = goto_statement->label;
-
- label->used = true;
if (label->base.source_position.input_name == NULL) {
print_in_function();
- errorf(&goto_statement->base.source_position,
- "label '%Y' used but not defined", label->base.symbol);
+ source_position_t const *const pos = &goto_statement->base.source_position;
+ errorf(pos, "'%N' used but not defined", (entity_t const*)label);
}
}
if (! label->used) {
print_in_function();
- warningf(&label_statement->base.source_position,
- "label '%Y' defined but not used", label->base.symbol);
+ source_position_t const *const pos = &label_statement->base.source_position;
+ warningf(pos, "'%N' defined but not used", (entity_t const*)label);
}
}
}
if (!declaration->used) {
print_in_function();
- const char *what = get_entity_kind_name(entity->kind);
- warningf(&entity->base.source_position, "%s '%Y' is unused",
- what, entity->base.symbol);
+ warningf(&entity->base.source_position, "'%N' is unused", entity);
} else if (entity->kind == ENTITY_VARIABLE && !entity->variable.read) {
print_in_function();
- const char *what = get_entity_kind_name(entity->kind);
- warningf(&entity->base.source_position, "%s '%Y' is never read",
- what, entity->base.symbol);
+ warningf(&entity->base.source_position, "'%N' is never read", entity);
}
}
}
static int determine_truth(expression_t const* const cond)
{
return
- !is_constant_expression(cond) ? 0 :
- fold_constant_to_bool(cond) ? 1 :
+ is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 :
+ fold_constant_to_bool(cond) ? 1 :
-1;
}
case STATEMENT_DECLARATION: {
declaration_statement_t const *const decl = &stmt->declaration;
entity_t const * ent = decl->declarations_begin;
- entity_t const *const last = decl->declarations_end;
+ entity_t const *const last_decl = decl->declarations_end;
if (ent != NULL) {
for (;; ent = ent->base.next) {
if (ent->kind == ENTITY_VARIABLE &&
- ent->variable.initializer != NULL &&
- !initializer_returns(ent->variable.initializer)) {
+ ent->variable.initializer != NULL &&
+ !initializer_returns(ent->variable.initializer)) {
return;
}
- if (ent == last)
+ if (ent == last_decl)
break;
}
}
if (!expression_returns(expr))
return;
- if (is_constant_expression(expr)) {
+ if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
long const val = fold_constant_to_int(expr);
case_label_statement_t * defaults = NULL;
for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
{
/* function-definitions and declarations both start with declaration
* specifiers */
- declaration_specifiers_t specifiers;
- memset(&specifiers, 0, sizeof(specifiers));
-
add_anchor_token(';');
+ declaration_specifiers_t specifiers;
parse_declaration_specifiers(&specifiers);
rem_anchor_token(';');
if (!is_type_function(type)) {
if (is_type_valid(type)) {
- errorf(HERE, "declarator '%#T' has a body but is not a function type",
- type, ndeclaration->base.symbol);
+ errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration);
}
eat_block();
return;
- } else if (is_typeref(orig_type)) {
+ }
+
+ source_position_t const *const pos = &ndeclaration->base.source_position;
+ if (is_typeref(orig_type)) {
/* §6.9.1:2 */
- errorf(&ndeclaration->base.source_position,
- "type of function definition '%#T' is a typedef",
- orig_type, ndeclaration->base.symbol);
+ errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration);
}
if (warning.aggregate_return &&
is_type_compound(skip_typeref(type->function.return_type))) {
- warningf(HERE, "function '%Y' returns an aggregate",
- ndeclaration->base.symbol);
+ warningf(pos, "'%N' returns an aggregate", ndeclaration);
}
if (warning.traditional && !type->function.unspecified_parameters) {
- warningf(HERE, "traditional C rejects ISO C style function definition of function '%Y'",
- ndeclaration->base.symbol);
+ warningf(pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration);
}
if (warning.old_style_definition && type->function.unspecified_parameters) {
- warningf(HERE, "old-style function definition '%Y'",
- ndeclaration->base.symbol);
+ warningf(pos, "old-style definition of '%N'", ndeclaration);
}
/* §6.7.5.3:14 a function definition with () means no
assert(entity->kind == ENTITY_FUNCTION);
assert(ndeclaration->kind == ENTITY_FUNCTION);
- function_t *function = &entity->function;
+ function_t *const function = &entity->function;
if (ndeclaration != entity) {
function->parameters = ndeclaration->function.parameters;
}
function_t *old_current_function = current_function;
entity_t *old_current_entity = current_entity;
current_function = function;
- current_entity = (entity_t*) function;
+ current_entity = entity;
current_parent = NULL;
goto_first = NULL;
if (warning.missing_noreturn &&
noreturn_candidate &&
!(function->base.modifiers & DM_NORETURN)) {
- warningf(&body->base.source_position,
- "function '%#T' is candidate for attribute 'noreturn'",
- type, entity->base.symbol);
+ source_position_t const *const pos = &body->base.source_position;
+ warningf(pos, "function '%#N' is candidate for attribute 'noreturn'", entity);
}
}
assert(current_parent == NULL);
assert(current_function == function);
- assert(current_entity == (entity_t*) function);
+ assert(current_entity == entity);
current_entity = old_current_entity;
current_function = old_current_function;
label_pop_to(label_stack_top);
il_size_t bit_size;
type_t *skipped_type = skip_typeref(base_type);
if (!is_type_integer(skipped_type)) {
- errorf(HERE, "bitfield base type '%T' is not an integer type",
- base_type);
+ errorf(source_position, "bitfield base type '%T' is not an integer type", base_type);
bit_size = 0;
} else {
bit_size = get_type_size(base_type) * 8;
}
- if (is_constant_expression(size)) {
+ if (is_constant_expression(size) == EXPR_CLASS_CONSTANT) {
long v = fold_constant_to_int(size);
const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol;
if ((entity->declaration.modifiers & DM_DEPRECATED) == 0)
return;
- char const *const prefix = get_entity_kind_name(entity->kind);
- const char *deprecated_string
- = get_deprecated_string(entity->declaration.attributes);
- if (deprecated_string != NULL) {
- warningf(source_position, "%s '%Y' is deprecated (declared %P): \"%s\"",
- prefix, entity->base.symbol, &entity->base.source_position,
- deprecated_string);
+ source_position_t const *const pos = &entity->base.source_position;
+ char const* const msg = get_deprecated_string(entity->declaration.attributes);
+ if (msg != NULL) {
+ warningf(source_position, "'%N' is deprecated (declared %P): \"%s\"", entity, pos, msg);
} else {
- warningf(source_position, "%s '%Y' is deprecated (declared %P)", prefix,
- entity->base.symbol, &entity->base.source_position);
+ warningf(source_position, "'%N' is deprecated (declared %P)", entity, pos);
}
}
anchor = &(*anchor)->next;
*anchor = specifiers->attributes;
- entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
- entity->base.namespc = NAMESPACE_NORMAL;
+ entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL);
entity->base.source_position = source_position;
entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
entity->declaration.storage_class = STORAGE_CLASS_NONE;
} else {
entity = parse_declarator(specifiers,
DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
+ source_position_t const *const pos = &entity->base.source_position;
if (entity->kind == ENTITY_TYPEDEF) {
- errorf(&entity->base.source_position,
- "typedef not allowed as compound member");
+ errorf(pos, "typedef not allowed as compound member");
} else {
assert(entity->kind == ENTITY_COMPOUND_MEMBER);
if (symbol != NULL) {
entity_t *prev = find_compound_entry(compound, symbol);
if (prev != NULL) {
- errorf(&entity->base.source_position,
- "multiple declarations of symbol '%Y' (declared %P)",
- symbol, &prev->base.source_position);
+ source_position_t const *const ppos = &prev->base.source_position;
+ errorf(pos, "multiple declarations of symbol '%Y' (declared %P)", symbol, ppos);
}
}
type_t *orig_type = entity->declaration.type;
type_t *type = skip_typeref(orig_type);
if (is_type_function(type)) {
- errorf(&entity->base.source_position,
- "compound member '%Y' must not have function type '%T'",
- entity->base.symbol, orig_type);
+ errorf(pos, "'%N' must not have function type '%T'", entity, orig_type);
} else if (is_type_incomplete(type)) {
/* §6.7.2.1:16 flexible array member */
if (!is_type_array(type) ||
token.type != ';' ||
look_ahead(1)->type != '}') {
- errorf(&entity->base.source_position,
- "compound member '%Y' has incomplete type '%T'",
- entity->base.symbol, orig_type);
+ errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
}
}
}
break;
}
declaration_specifiers_t specifiers;
- memset(&specifiers, 0, sizeof(specifiers));
parse_declaration_specifiers(&specifiers);
-
parse_compound_declarators(compound, &specifiers);
}
rem_anchor_token('}');
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
|| specifiers.thread_local) {
/* TODO: improve error message, user does probably not know what a
* storage class is...
*/
- errorf(HERE, "typename must not have a storage class");
+ errorf(&specifiers.source_position, "typename must not have a storage class");
}
type_t *result = parse_abstract_declarator(specifiers.type);
parse_expression_infix_function infix_parser;
};
-expression_parser_function_t expression_parsers[T_LAST_TOKEN];
+static expression_parser_function_t expression_parsers[T_LAST_TOKEN];
/**
* Prints an error message if an expression was expected but not read
literal->literal.value = token.literal;
size_t len = literal->literal.value.size;
- if (len != 1) {
+ if (len > 1) {
if (!GNU_MODE && !(c_mode & _C99)) {
errorf(HERE, "more than 1 character in character constant");
} else if (warning.multichar) {
literal->literal.value = token.literal;
size_t len = wstrlen(&literal->literal.value);
- if (len != 1) {
+ if (len > 1) {
warningf(HERE, "multi-character character constant");
}
ntype->function.linkage = LINKAGE_C;
type_t *type = identify_new_type(ntype);
- entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
+ entity_t *const entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, symbol);
entity->declaration.storage_class = STORAGE_CLASS_EXTERN;
entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
entity->declaration.type = type;
entity->declaration.implicit = true;
- entity->base.symbol = symbol;
entity->base.source_position = *source_position;
- if (current_scope != NULL) {
- bool strict_prototypes_old = warning.strict_prototypes;
- warning.strict_prototypes = false;
+ if (current_scope != NULL)
record_entity(entity, false);
- warning.strict_prototypes = strict_prototypes_old;
- }
return entity;
}
construct a hashmap here... */
entity_t *entity = scope->entities;
for ( ; entity != NULL; entity = entity->base.next) {
- if (entity->base.symbol == symbol && entity->base.namespc == namespc)
+ if (entity->base.symbol == symbol
+ && (namespace_tag_t)entity->base.namespc == namespc)
break;
}
default:
errorf(&pos, "'%Y' must be a namespace, class, struct or union (but is a %s)",
symbol, get_entity_kind_name(entity->kind));
- goto end_error;
+
+ /* skip further qualifications */
+ while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
+
+ return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
}
}
}
return entity;
-
-end_error:
- /* skip further qualifications */
- while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
-
- return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
}
static expression_t *parse_reference(void)
{
- entity_t *entity = parse_qualified_identifier();
+ source_position_t const pos = token.source_position;
+ entity_t *const entity = parse_qualified_identifier();
type_t *orig_type;
if (is_declaration(entity)) {
if (entity->kind == ENTITY_ENUM_VALUE)
kind = EXPR_REFERENCE_ENUM_VALUE;
- expression_t *expression = allocate_expression_zero(kind);
- expression->reference.entity = entity;
- expression->base.type = type;
+ expression_t *expression = allocate_expression_zero(kind);
+ expression->base.source_position = pos;
+ expression->base.type = type;
+ expression->reference.entity = entity;
/* this declaration is used */
if (is_declaration(entity)) {
current_function->need_closure = true;
}
- check_deprecated(HERE, entity);
+ check_deprecated(&pos, entity);
if (warning.init_self && entity == current_init_decl && !in_type_prop
&& entity->kind == ENTITY_VARIABLE) {
current_init_decl = NULL;
- warningf(HERE, "variable '%#T' is initialized by itself",
- entity->declaration.type, entity->base.symbol);
+ warningf(&pos, "variable '%#N' is initialized by itself", entity);
}
return expression;
*/
static expression_t *parse_cast(void)
{
- add_anchor_token(')');
-
source_position_t source_position = token.source_position;
+ eat('(');
+ add_anchor_token(')');
+
type_t *type = parse_typename();
rem_anchor_token(')');
*/
static expression_t *parse_statement_expression(void)
{
- add_anchor_token(')');
-
expression_t *expression = allocate_expression_zero(EXPR_STATEMENT);
+ eat('(');
+ add_anchor_token(')');
+
statement_t *statement = parse_compound_statement(true);
statement->compound.stmt_expr = true;
expression->statement.statement = statement;
*/
static expression_t *parse_parenthesized_expression(void)
{
- eat('(');
-
- switch (token.type) {
+ token_t const* const la1 = look_ahead(1);
+ switch (la1->type) {
case '{':
/* gcc extension: a statement expression */
return parse_statement_expression();
- TYPE_QUALIFIERS
- TYPE_SPECIFIERS
- return parse_cast();
case T_IDENTIFIER:
- if (is_typedef_symbol(token.symbol)) {
+ if (is_typedef_symbol(la1->symbol)) {
+ DECLARATION_START
return parse_cast();
}
}
+ eat('(');
add_anchor_token(')');
expression_t *result = parse_expression();
result->base.parenthesized = true;
}
/**
- * Return the declaration for a given label symbol or create a new one.
- *
- * @param symbol the symbol of the label
+ * Return the label for the current symbol or create a new one.
*/
-static label_t *get_label(symbol_t *symbol)
+static label_t *get_label(void)
{
- entity_t *label;
+ assert(token.type == T_IDENTIFIER);
assert(current_function != NULL);
- label = get_entity(symbol, NAMESPACE_LABEL);
- /* if we found a local label, we already created the declaration */
+ entity_t *label = get_entity(token.symbol, 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) {
assert(label->base.parent_scope->depth < current_scope->depth);
current_function->goto_to_outer = true;
}
- return &label->label;
+ } else if (label == NULL || label->base.parent_scope != ¤t_function->parameters) {
+ /* There is no matching label in the same function, so create a new one. */
+ label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.symbol);
+ label_push(label);
}
- label = get_entity(symbol, NAMESPACE_LABEL);
- /* if we found a label in the same function, then we already created the
- * declaration */
- if (label != NULL
- && label->base.parent_scope == ¤t_function->parameters) {
- return &label->label;
- }
-
- /* otherwise we need to create a new one */
- label = allocate_entity_zero(ENTITY_LABEL);
- label->base.namespc = NAMESPACE_LABEL;
- label->base.symbol = symbol;
-
- label_push(label);
-
+ eat(T_IDENTIFIER);
return &label->label;
}
eat(T_ANDAND);
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
- goto end_error;
+ return create_invalid_expression();
}
- symbol_t *symbol = token.symbol;
- next_token();
- label_t *label = get_label(symbol);
+ label_t *const label = get_label();
label->used = true;
label->address_taken = true;
expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS);
expression->base.source_position = source_position;
- /* label address is threaten as a void pointer */
+ /* label address is treated as a void pointer */
expression->base.type = type_void_ptr;
expression->label_address.label = label;
return expression;
-end_error:
- return create_invalid_expression();
}
/**
return parse_reference();
}
/* FALLTHROUGH */
- TYPENAME_START {
- source_position_t const pos = *HERE;
- type_t const *const type = parse_typename();
+ DECLARATION_START {
+ source_position_t const pos = *HERE;
+ declaration_specifiers_t specifiers;
+ parse_declaration_specifiers(&specifiers);
+ type_t const *const type = parse_abstract_declarator(specifiers.type);
errorf(&pos, "encountered type '%T' while parsing expression", type);
return create_invalid_expression();
}
}
errorf(HERE, "unexpected token %K, expected an expression", &token);
+ eat_until_anchor();
return create_invalid_expression();
}
-/**
- * Check if the expression has the character type and issue a warning then.
- */
-static void check_for_char_index_type(const expression_t *expression)
-{
- type_t *const type = expression->base.type;
- const type_t *const base_type = skip_typeref(type);
-
- if (is_type_atomic(base_type, ATOMIC_TYPE_CHAR) &&
- warning.char_subscripts) {
- warningf(&expression->base.source_position,
- "array subscript has type '%T'", type);
- }
-}
-
static expression_t *parse_array_expression(expression_t *left)
{
- expression_t *expression = allocate_expression_zero(EXPR_ARRAY_ACCESS);
+ expression_t *const expr = allocate_expression_zero(EXPR_ARRAY_ACCESS);
+ array_access_expression_t *const arr = &expr->array_access;
eat('[');
add_anchor_token(']');
- expression_t *inside = parse_expression();
+ expression_t *const inside = parse_expression();
type_t *const orig_type_left = left->base.type;
type_t *const orig_type_inside = inside->base.type;
type_t *const type_left = skip_typeref(orig_type_left);
type_t *const type_inside = skip_typeref(orig_type_inside);
- type_t *return_type;
- array_access_expression_t *array_access = &expression->array_access;
+ expression_t *ref;
+ expression_t *idx;
+ type_t *idx_type;
+ type_t *res_type;
if (is_type_pointer(type_left)) {
- return_type = type_left->pointer.points_to;
- array_access->array_ref = left;
- array_access->index = inside;
- check_for_char_index_type(inside);
+ ref = left;
+ idx = inside;
+ idx_type = type_inside;
+ res_type = type_left->pointer.points_to;
+ goto check_idx;
} else if (is_type_pointer(type_inside)) {
- return_type = type_inside->pointer.points_to;
- array_access->array_ref = inside;
- array_access->index = left;
- array_access->flipped = true;
- check_for_char_index_type(left);
+ arr->flipped = true;
+ ref = inside;
+ idx = left;
+ idx_type = type_left;
+ res_type = type_inside->pointer.points_to;
+check_idx:
+ res_type = automatic_type_conversion(res_type);
+ if (!is_type_integer(idx_type)) {
+ errorf(&idx->base.source_position, "array subscript must have integer type");
+ } else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR) && warning.char_subscripts) {
+ warningf(&idx->base.source_position, "array subscript has char type");
+ }
} else {
if (is_type_valid(type_left) && is_type_valid(type_inside)) {
- errorf(HERE,
- "array access on object with non-pointer types '%T', '%T'",
- orig_type_left, orig_type_inside);
+ errorf(&expr->base.source_position, "invalid types '%T[%T]' for array access", orig_type_left, orig_type_inside);
}
- return_type = type_error_type;
- array_access->array_ref = left;
- array_access->index = inside;
+ res_type = type_error_type;
+ ref = left;
+ idx = inside;
}
- expression->base.type = automatic_type_conversion(return_type);
+ arr->array_ref = ref;
+ arr->index = idx;
+ arr->base.type = res_type;
rem_anchor_token(']');
expect(']', end_error);
end_error:
- return expression;
+ return expr;
}
static expression_t *parse_typeprop(expression_kind_t const kind)
type_t *orig_type;
expression_t *expression;
- if (token.type == '(' && is_declaration_specifier(look_ahead(1), true)) {
+ if (token.type == '(' && is_declaration_specifier(look_ahead(1))) {
next_token();
add_anchor_token(')');
orig_type = parse_typename();
tp_expression->typeprop.type = orig_type;
type_t const* const type = skip_typeref(orig_type);
- char const* const wrong_type =
- GNU_MODE && is_type_atomic(type, ATOMIC_TYPE_VOID) ? NULL :
- is_type_incomplete(type) ? "incomplete" :
- type->kind == TYPE_FUNCTION ? "function designator" :
- type->kind == TYPE_BITFIELD ? "bitfield" :
- NULL;
+ char const* wrong_type = NULL;
+ if (is_type_incomplete(type)) {
+ if (!is_type_atomic(type, ATOMIC_TYPE_VOID) || !GNU_MODE)
+ wrong_type = "incomplete";
+ } else if (type->kind == TYPE_FUNCTION) {
+ if (GNU_MODE) {
+ /* function types are allowed (and return 1) */
+ if (warning.other) {
+ char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+ warningf(&tp_expression->base.source_position,
+ "%s expression with function argument returns invalid result", what);
+ }
+ } else {
+ wrong_type = "function";
+ }
+ } else {
+ if (is_type_incomplete(type))
+ wrong_type = "incomplete";
+ }
+ if (type->kind == TYPE_BITFIELD)
+ wrong_type = "bitfield";
+
if (wrong_type != NULL) {
char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
errorf(&tp_expression->base.source_position,
{
assert(token.type == '.' || token.type == T_MINUSGREATER);
bool select_left_arrow = (token.type == T_MINUSGREATER);
+ source_position_t const pos = *HERE;
next_token();
if (token.type != T_IDENTIFIER) {
bool saw_error = false;
if (is_type_pointer(type)) {
if (!select_left_arrow) {
- errorf(HERE,
+ errorf(&pos,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, orig_type);
saw_error = true;
type_left = skip_typeref(type->pointer.points_to);
} else {
if (select_left_arrow && is_type_valid(type)) {
- errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
+ errorf(&pos, "left hand side of '->' is not a pointer, but '%T'", orig_type);
saw_error = true;
}
type_left = type;
type_left->kind != TYPE_COMPOUND_UNION) {
if (is_type_valid(type_left) && !saw_error) {
- errorf(HERE,
+ errorf(&pos,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, type_left);
}
compound_t *compound = type_left->compound.compound;
if (!compound->complete) {
- errorf(HERE, "request for member '%Y' in incomplete type '%T'",
+ errorf(&pos, "request for member '%Y' in incomplete type '%T'",
symbol, type_left);
return create_invalid_expression();
}
type_qualifiers_t qualifiers = type_left->base.qualifiers;
- expression_t *result
- = find_create_select(HERE, addr, qualifiers, compound, symbol);
+ expression_t *result =
+ find_create_select(&pos, addr, qualifiers, compound, symbol);
if (result == NULL) {
- errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
+ errorf(&pos, "'%T' has no member named '%Y'", orig_type, symbol);
return create_invalid_expression();
}
/* report exact scope in error messages (like "in argument 3") */
char buf[64];
snprintf(buf, sizeof(buf), "call argument %u", pos);
- report_assign_error(error, expected_type, arg_expr, buf,
- &arg_expr->base.source_position);
+ report_assign_error(error, expected_type, arg_expr, buf,
+ &arg_expr->base.source_position);
} else if (warning.traditional || warning.conversion) {
type_t *const promoted_type = get_default_promoted_type(arg_type);
if (!types_compatible(expected_type_skip, promoted_type) &&
/* argument must be constant */
call_argument_t *argument = call->arguments;
- if (! is_constant_expression(argument->expression)) {
+ if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
"argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
break;
call_argument_t *arg = call->arguments->next;
- if (arg != NULL && ! is_constant_expression(arg->expression)) {
+ if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
"second argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
call_argument_t *locality = NULL;
if (rw != NULL) {
- if (! is_constant_expression(rw->expression)) {
+ if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
"second argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
locality = rw->next;
}
if (locality != NULL) {
- if (! is_constant_expression(locality->expression)) {
+ if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
"third argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
}
if (parameter != NULL) {
- errorf(HERE, "too few arguments to function '%E'", expression);
+ errorf(&expression->base.source_position, "too few arguments to function '%E'", expression);
} else if (argument != NULL && !function_type->variadic) {
- errorf(HERE, "too many arguments to function '%E'", expression);
+ errorf(&argument->expression->base.source_position, "too many arguments to function '%E'", expression);
}
}
/* do default promotion for other arguments */
for (; argument != NULL; argument = argument->next) {
- type_t *type = argument->expression->base.type;
- if (!is_type_object(skip_typeref(type))) {
+ type_t *argument_type = argument->expression->base.type;
+ if (!is_type_object(skip_typeref(argument_type))) {
errorf(&argument->expression->base.source_position,
"call argument '%E' must not be void", argument->expression);
}
- type = get_default_promoted_type(type);
+ argument_type = get_default_promoted_type(argument_type);
argument->expression
- = create_implicit_cast(argument->expression, type);
+ = create_implicit_cast(argument->expression, argument_type);
}
- check_format(&result->call);
+ check_format(call);
if (warning.aggregate_return &&
is_type_compound(skip_typeref(function_type->return_type))) {
- warningf(&result->base.source_position,
+ warningf(&expression->base.source_position,
"function call has aggregate value");
}
- if (call->function->kind == EXPR_REFERENCE) {
- reference_expression_t *reference = &call->function->reference;
+ if (expression->kind == EXPR_REFERENCE) {
+ reference_expression_t *reference = &expression->reference;
if (reference->entity->kind == ENTITY_FUNCTION &&
reference->entity->function.btk != bk_none)
handle_builtin_argument_restrictions(call);
expr = get_reference_address(expr);
if (expr != NULL) {
- warningf(&expr->base.source_position,
- "the address of '%Y' will always evaluate as 'true'",
- expr->reference.entity->base.symbol);
+ source_position_t const *const pos = &expr->base.source_position;
+ entity_t const *const ent = expr->reference.entity;
+ warningf(pos, "the address of '%N' will always evaluate as 'true'", ent);
}
}
}
result_type = pointer_type;
} else {
- if (is_type_valid(other_type)) {
- type_error_incompatible("while parsing conditional",
- &expression->base.source_position, true_type, false_type);
- }
- result_type = type_error_type;
+ goto types_incompatible;
}
} else {
+types_incompatible:
if (is_type_valid(true_type) && is_type_valid(false_type)) {
type_error_incompatible("while parsing conditional",
&conditional->base.source_position, true_type,
if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER
&& !may_be_register) {
- errorf(&expression->base.source_position,
- "address of register %s '%Y' requested",
- get_entity_kind_name(entity->kind), entity->base.symbol);
+ source_position_t const *const pos = &expression->base.source_position;
+ errorf(pos, "address of register '%N' requested", entity);
}
if (entity->kind == ENTITY_VARIABLE) {
expression->base.type = arithmetic_type;
}
+static void semantic_binexpr_integer(binary_expression_t *const expression)
+{
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
+ type_t *const orig_type_left = left->base.type;
+ type_t *const orig_type_right = right->base.type;
+ type_t *const type_left = skip_typeref(orig_type_left);
+ type_t *const type_right = skip_typeref(orig_type_right);
+
+ if (!is_type_integer(type_left) || !is_type_integer(type_right)) {
+ /* TODO: improve error message */
+ if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ errorf(&expression->base.source_position,
+ "operation needs integer types");
+ }
+ return;
+ }
+
+ type_t *const result_type = semantic_arithmetic(type_left, type_right);
+ expression->left = create_implicit_cast(left, result_type);
+ expression->right = create_implicit_cast(right, result_type);
+ expression->base.type = result_type;
+}
+
static void warn_div_by_zero(binary_expression_t const *const expression)
{
if (!warning.div_by_zero ||
expression_t const *const right = expression->right;
/* The type of the right operand can be different for /= */
- if (is_type_integer(right->base.type) &&
- is_constant_expression(right) &&
+ if (is_type_integer(right->base.type) &&
+ is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
!fold_constant_to_bool(right)) {
warningf(&expression->base.source_position, "division by zero");
}
type_left = promote_integer(type_left);
- if (is_constant_expression(right)) {
+ if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
long count = fold_constant_to_int(right);
if (count < 0) {
warningf(&right->base.source_position,
}
}
-static void warn_comparison_in_comparison(const expression_t *const expr)
+static bool maybe_negative(expression_t const *const expr)
{
- if (expr->base.parenthesized)
- return;
- switch (expr->base.kind) {
- case EXPR_BINARY_LESS:
- case EXPR_BINARY_GREATER:
- case EXPR_BINARY_LESSEQUAL:
- case EXPR_BINARY_GREATEREQUAL:
- case EXPR_BINARY_NOTEQUAL:
- case EXPR_BINARY_EQUAL:
- warningf(&expr->base.source_position,
- "comparisons like 'x <= y < z' do not have their mathematical meaning");
- break;
- default:
- break;
+ switch (is_constant_expression(expr)) {
+ case EXPR_CLASS_ERROR: return false;
+ case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0;
+ default: return true;
}
}
-static bool maybe_negative(expression_t const *const expr)
+static void warn_comparison(source_position_t const *const pos, expression_t const *const expr, expression_t const *const other)
{
- return
- !is_constant_expression(expr) ||
- fold_constant_to_int(expr) < 0;
+ if (warning.address) {
+ warn_string_literal_address(expr);
+
+ expression_t const* const ref = get_reference_address(expr);
+ if (ref != NULL && is_null_pointer_constant(other)) {
+ entity_t const *const ent = ref->reference.entity;
+ warningf(pos, "the address of '%N' will never be NULL", ent);
+ }
+ }
+
+ if (warning.parentheses && !expr->base.parenthesized) {
+ switch (expr->base.kind) {
+ case EXPR_BINARY_LESS:
+ case EXPR_BINARY_GREATER:
+ case EXPR_BINARY_LESSEQUAL:
+ case EXPR_BINARY_GREATEREQUAL:
+ case EXPR_BINARY_NOTEQUAL:
+ case EXPR_BINARY_EQUAL:
+ warningf(pos, "comparisons like 'x <= y < z' do not have their mathematical meaning");
+ break;
+ default:
+ break;
+ }
+ }
}
/**
*/
static void semantic_comparison(binary_expression_t *expression)
{
- expression_t *left = expression->left;
- expression_t *right = expression->right;
-
- if (warning.address) {
- warn_string_literal_address(left);
- warn_string_literal_address(right);
-
- expression_t const* const func_left = get_reference_address(left);
- if (func_left != NULL && is_null_pointer_constant(right)) {
- warningf(&expression->base.source_position,
- "the address of '%Y' will never be NULL",
- func_left->reference.entity->base.symbol);
- }
-
- expression_t const* const func_right = get_reference_address(right);
- if (func_right != NULL && is_null_pointer_constant(right)) {
- warningf(&expression->base.source_position,
- "the address of '%Y' will never be NULL",
- func_right->reference.entity->base.symbol);
- }
- }
+ source_position_t const *const pos = &expression->base.source_position;
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
- if (warning.parentheses) {
- warn_comparison_in_comparison(left);
- warn_comparison_in_comparison(right);
- }
+ warn_comparison(pos, left, right);
+ warn_comparison(pos, right, left);
type_t *orig_type_left = left->base.type;
type_t *orig_type_right = right->base.type;
/* TODO check whether constant value can be represented by other type */
if ((signed_left && maybe_negative(left)) ||
(signed_right && maybe_negative(right))) {
- warningf(&expression->base.source_position,
- "comparison between signed and unsigned");
+ warningf(pos, "comparison between signed and unsigned");
}
}
}
(expression->base.kind == EXPR_BINARY_EQUAL ||
expression->base.kind == EXPR_BINARY_NOTEQUAL) &&
is_type_float(arithmetic_type)) {
- warningf(&expression->base.source_position,
- "comparing floating point with == or != is unsafe");
+ warningf(pos, "comparing floating point with == or != is unsafe");
}
} else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
/* TODO check compatibility */
} else if (is_type_pointer(type_right)) {
expression->left = create_implicit_cast(left, type_right);
} else if (is_type_valid(type_left) && is_type_valid(type_right)) {
- type_error_incompatible("invalid operands in comparison",
- &expression->base.source_position,
- type_left, type_right);
+ type_error_incompatible("invalid operands in comparison", pos, type_left, type_right);
}
expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
type_t *const type_left = skip_typeref(orig_type_left);
if (!is_lvalue(left)) {
- errorf(HERE, "left hand side '%E' of assignment is not an lvalue",
+ errorf(&left->base.source_position, "left hand side '%E' of assignment is not an lvalue",
left);
return false;
}
if (left->kind == EXPR_REFERENCE
&& left->reference.entity->kind == ENTITY_FUNCTION) {
- errorf(HERE, "cannot assign to function '%E'", left);
+ errorf(&left->base.source_position, "cannot assign to function '%E'", left);
return false;
}
if (is_type_array(type_left)) {
- errorf(HERE, "cannot assign to array '%E'", left);
+ errorf(&left->base.source_position, "cannot assign to array '%E'", left);
return false;
}
if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
- errorf(HERE, "assignment to readonly location '%E' (type '%T')", left,
+ errorf(&left->base.source_position, "assignment to read-only location '%E' (type '%T')", left,
orig_type_left);
return false;
}
if (is_type_incomplete(type_left)) {
- errorf(HERE, "left-hand side '%E' of assignment has incomplete type '%T'",
+ errorf(&left->base.source_position, "left-hand side '%E' of assignment has incomplete type '%T'",
left, orig_type_left);
return false;
}
if (is_type_compound(type_left) && has_const_fields(&type_left->compound)) {
- errorf(HERE, "cannot assign to '%E' because compound type '%T' has readonly fields",
+ errorf(&left->base.source_position, "cannot assign to '%E' because compound type '%T' has read-only fields",
left, orig_type_left);
return false;
}
CREATE_BINEXPR_PARSER(T_GREATEREQUAL, EXPR_BINARY_GREATEREQUAL, PREC_SHIFT, semantic_comparison)
CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL, PREC_RELATIONAL, semantic_comparison)
CREATE_BINEXPR_PARSER(T_EQUALEQUAL, EXPR_BINARY_EQUAL, PREC_RELATIONAL, semantic_comparison)
-CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND, PREC_EQUALITY, semantic_binexpr_arithmetic)
-CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR, PREC_AND, semantic_binexpr_arithmetic)
-CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR, PREC_XOR, semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND, PREC_EQUALITY, semantic_binexpr_integer)
+CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR, PREC_AND, semantic_binexpr_integer)
+CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR, PREC_XOR, semantic_binexpr_integer)
CREATE_BINEXPR_PARSER(T_ANDAND, EXPR_BINARY_LOGICAL_AND, PREC_OR, semantic_logical_op)
CREATE_BINEXPR_PARSER(T_PIPEPIPE, EXPR_BINARY_LOGICAL_OR, PREC_LOGICAL_AND, semantic_logical_op)
CREATE_BINEXPR_PARSER('=', EXPR_BINARY_ASSIGN, PREC_ASSIGNMENT, semantic_binexpr_assign)
* @param precedence the precedence of the operator
*/
static void register_infix_parser(parse_expression_infix_function parser,
- int token_type, precedence_t precedence)
+ int token_type, precedence_t precedence)
{
expression_parser_function_t *entry = &expression_parsers[token_type];
return create_invalid_statement();
}
-static statement_t *parse_label_inner_statement(char const *const label, bool const eat_empty_stmt)
+static statement_t *parse_label_inner_statement(statement_t const *const label, char const *const label_kind)
{
statement_t *inner_stmt;
switch (token.type) {
case '}':
- errorf(HERE, "%s at end of compound statement", label);
+ errorf(&label->base.source_position, "%s at end of compound statement", label_kind);
inner_stmt = create_invalid_statement();
break;
case ';':
- if (eat_empty_stmt) {
+ if (label->kind == STATEMENT_LABEL) {
/* Eat an empty statement here, to avoid the warning about an empty
* statement after a label. label:; is commonly used to have a label
* before a closing brace. */
default:
inner_stmt = parse_statement();
- if (inner_stmt->kind == STATEMENT_DECLARATION) {
- errorf(&inner_stmt->base.source_position, "declaration after %s", label);
+ /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
+ if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
+ errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind);
}
break;
}
expression_t *const expression = parse_expression();
statement->case_label.expression = expression;
- if (!is_constant_expression(expression)) {
- /* This check does not prevent the error message in all cases of an
- * prior error while parsing the expression. At least it catches the
- * common case of a mistyped enum entry. */
- if (is_type_valid(skip_typeref(expression->base.type))) {
+ expression_classification_t const expr_class = is_constant_expression(expression);
+ if (expr_class != EXPR_CLASS_CONSTANT) {
+ if (expr_class != EXPR_CLASS_ERROR) {
errorf(pos, "case label does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
if (next_if(T_DOTDOTDOT)) {
expression_t *const end_range = parse_expression();
statement->case_label.end_range = end_range;
- if (!is_constant_expression(end_range)) {
- /* This check does not prevent the error message in all cases of an
- * prior error while parsing the expression. At least it catches the
- * common case of a mistyped enum entry. */
- if (is_type_valid(skip_typeref(end_range->base.type))) {
+ expression_classification_t const end_class = is_constant_expression(end_range);
+ if (end_class != EXPR_CLASS_CONSTANT) {
+ if (end_class != EXPR_CLASS_ERROR) {
errorf(pos, "case range does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
errorf(pos, "case label not within a switch statement");
}
- statement->case_label.statement = parse_label_inner_statement("case label", false);
+ statement->case_label.statement = parse_label_inner_statement(statement, "case label");
POP_PARENT;
return statement;
if (current_switch != NULL) {
const case_label_statement_t *def_label = current_switch->default_label;
if (def_label != NULL) {
- errorf(HERE, "multiple default labels in one switch (previous declared %P)",
- &def_label->base.source_position);
+ errorf(&statement->base.source_position, "multiple default labels in one switch (previous declared %P)", &def_label->base.source_position);
} else {
current_switch->default_label = &statement->case_label;
"'default' label not within a switch statement");
}
- statement->case_label.statement = parse_label_inner_statement("default label", false);
+ statement->case_label.statement = parse_label_inner_statement(statement, "default label");
POP_PARENT;
return statement;
*/
static statement_t *parse_label_statement(void)
{
- assert(token.type == T_IDENTIFIER);
- symbol_t *symbol = token.symbol;
- label_t *label = get_label(symbol);
-
statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
- statement->label.label = label;
-
- next_token();
+ label_t *const label = get_label();
+ statement->label.label = label;
PUSH_PARENT(statement);
/* if statement is already set then the label is defined twice,
* otherwise it was just mentioned in a goto/local label declaration so far
*/
+ source_position_t const* const pos = &statement->base.source_position;
if (label->statement != NULL) {
- errorf(HERE, "duplicate label '%Y' (declared %P)",
- symbol, &label->base.source_position);
+ errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.source_position);
} else {
- label->base.source_position = token.source_position;
+ label->base.source_position = *pos;
label->statement = statement;
}
eat(':');
- statement->label.statement = parse_label_inner_statement("label", true);
+ statement->label.statement = parse_label_inner_statement(statement, "label");
/* remember the labels in a list for later checking */
*label_anchor = &statement->label;
break;
}
}
- if (! found) {
- warningf(&statement->base.source_position,
- "enumeration value '%Y' not handled in switch",
- entry->base.symbol);
+ if (!found) {
+ warningf(&statement->base.source_position, "'%N' not handled in switch", entry);
}
last_value = value;
}
}
if (next_if(';')) {
- } else if (is_declaration_specifier(&token, false)) {
+ } else if (is_declaration_specifier(&token)) {
parse_declaration(record_entity, DECL_FLAGS_NONE);
} else {
add_anchor_token(';');
statement->gotos.expression = expression;
} else if (token.type == T_IDENTIFIER) {
- symbol_t *symbol = token.symbol;
- next_token();
- statement->gotos.label = get_label(symbol);
+ label_t *const label = get_label();
+ label->used = true;
+ statement->gotos.label = label;
} else {
if (GNU_MODE)
parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
}
} else {
assign_error_t error = semantic_assign(return_type, return_value);
- report_assign_error(error, return_type, return_value, "'return'",
- pos);
+ report_assign_error(error, return_type, return_value, "'return'",
+ pos);
}
return_value = create_implicit_cast(return_value, return_type);
/* check for returning address of a local var */
if (warning.other && return_value != NULL
- && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
+ && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
const expression_t *expression = return_value->unary.value;
if (expression_is_local_variable(expression)) {
warningf(pos, "function returns address of local variable");
/* ISO/IEC 14882:1998(E) §6.6.3:3 */
if (c_mode & _CXX || strict_mode) {
errorf(pos,
- "'return' without value, in function returning non-void");
+ "'return' without value, in function returning non-void");
} else {
warningf(pos,
- "'return' without value, in function returning non-void");
+ "'return' without value, in function returning non-void");
}
}
statement->returns.value = return_value;
symbol_t *symbol = token.symbol;
entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
if (entity != NULL && entity->base.parent_scope == current_scope) {
- errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition %P)",
- symbol, &entity->base.source_position);
+ source_position_t const *const ppos = &entity->base.source_position;
+ errorf(HERE, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
} else {
- entity = allocate_entity_zero(ENTITY_LOCAL_LABEL);
-
+ entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol);
entity->base.parent_scope = current_scope;
- entity->base.namespc = NAMESPACE_LABEL;
entity->base.source_position = token.source_position;
- entity->base.symbol = symbol;
*anchor = entity;
anchor = &entity->base.next;
if (entity != NULL
&& entity->kind != ENTITY_NAMESPACE
&& entity->base.parent_scope == current_scope) {
- if (!is_error_entity(entity)) {
+ if (is_entity_valid(entity)) {
error_redefined_as_different_kind(&token.source_position,
entity, ENTITY_NAMESPACE);
}
}
if (entity == NULL) {
- entity = allocate_entity_zero(ENTITY_NAMESPACE);
- entity->base.symbol = symbol;
+ entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol);
entity->base.source_position = token.source_position;
- entity->base.namespc = NAMESPACE_NORMAL;
entity->base.parent_scope = current_scope;
}
declaration->storage_class != STORAGE_CLASS_STATIC)
continue;
- type_t *const type = declaration->type;
const char *s;
if (entity->kind == ENTITY_FUNCTION) {
/* inhibit warning for static inline functions */
s = "defined";
}
- warningf(&declaration->base.source_position, "'%#T' %s but not used",
- type, declaration->base.symbol, s);
+ warningf(&declaration->base.source_position, "'%#N' %s but not used", entity);
}
}
static void parse_linkage_specification(void)
{
eat(T_extern);
- assert(token.type == T_STRING_LITERAL);
- const char *linkage = parse_string_literals().begin;
+ source_position_t const pos = *HERE;
+ char const *const linkage = parse_string_literals().begin;
linkage_kind_t old_linkage = current_linkage;
linkage_kind_t new_linkage;
} else if (strcmp(linkage, "C++") == 0) {
new_linkage = LINKAGE_CXX;
} else {
- errorf(HERE, "linkage string \"%s\" not recognized", linkage);
+ errorf(&pos, "linkage string \"%s\" not recognized", linkage);
new_linkage = LINKAGE_INVALID;
}
current_linkage = new_linkage;
add_anchor_token(T_EOF);
#ifndef NDEBUG
+ /* make a copy of the anchor set, so we can check if it is restored after parsing */
unsigned char token_anchor_copy[T_LAST_TOKEN];
memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
#endif
while (token.type != T_EOF && token.type != '}') {
#ifndef NDEBUG
- bool anchor_leak = false;
- for (int i = 0; i != T_LAST_TOKEN; ++i) {
+ for (int i = 0; i < T_LAST_TOKEN; ++i) {
unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
if (count != 0) {
- errorf(HERE, "Leaked anchor token %k %d times", i, count);
- anchor_leak = true;
+ /* the anchor set and its copy differs */
+ internal_errorf(HERE, "Leaked anchor token %k %d times", i, count);
}
}
if (in_gcc_extension) {
- errorf(HERE, "Leaked __extension__");
- anchor_leak = true;
+ /* an gcc extension scope was not closed */
+ internal_errorf(HERE, "Leaked __extension__");
}
-
- if (anchor_leak)
- abort();
#endif
parse_external();
}
}
+void set_default_visibility(elf_visibility_tag_t visibility)
+{
+ default_visibility = visibility;
+}
+
/**
* Parse the input.
*
{
size_t n = ARR_LEN(incomplete_arrays);
for (size_t i = 0; i != n; ++i) {
- declaration_t *const decl = incomplete_arrays[i];
- type_t *const orig_type = decl->type;
- type_t *const type = skip_typeref(orig_type);
+ declaration_t *const decl = incomplete_arrays[i];
+ type_t *const type = skip_typeref(decl->type);
if (!is_type_incomplete(type))
continue;
if (warning.other) {
- warningf(&decl->base.source_position,
- "array '%#T' assumed to have one element",
- orig_type, decl->base.symbol);
+ source_position_t const *const pos = &decl->base.source_position;
+ warningf(pos, "array '%#N' assumed to have one element", (entity_t const*)decl);
}
type_t *const new_type = duplicate_type(type);
init_expression_parsers();
obstack_init(&temp_obst);
-
- symbol_t *const va_list_sym = symbol_table_insert("__builtin_va_list");
- type_valist = create_builtin_type(va_list_sym, type_void_ptr);
}
/**