source_position_t source_position;
storage_class_t storage_class;
unsigned char alignment; /**< Alignment, 0 if not set. */
- bool is_inline : 1;
- bool deprecated : 1;
+ bool is_inline : 1;
+ bool thread_local : 1; /**< GCC __thread */
+ bool deprecated : 1;
decl_modifiers_t modifiers; /**< declaration modifiers */
gnu_attribute_t *gnu_attributes; /**< list of GNU attributes */
const char *deprecated_string; /**< can be set if declaration was marked deprecated. */
bool must_be_constant;
} parse_initializer_env_t;
+/**
+ * Capture a MS __base extension.
+ */
+typedef struct based_spec_t {
+ source_position_t source_position;
+ variable_t *base_variable;
+} based_spec_t;
+
typedef entity_t* (*parsed_declaration_func) (entity_t *declaration, bool is_definition);
/** The current token. */
-static token_t token;
+static token_t token;
/** The lookahead ring-buffer. */
-static token_t lookahead_buffer[MAX_LOOKAHEAD];
+static token_t lookahead_buffer[MAX_LOOKAHEAD];
/** Position of the next token in the lookahead buffer. */
-static int lookahead_bufpos;
-static stack_entry_t *environment_stack = NULL;
-static stack_entry_t *label_stack = NULL;
-static scope_t *file_scope = NULL;
-static scope_t *current_scope = NULL;
+static int lookahead_bufpos;
+static stack_entry_t *environment_stack = NULL;
+static stack_entry_t *label_stack = NULL;
+static scope_t *file_scope = NULL;
+static scope_t *current_scope = NULL;
/** Point to the current function declaration if inside a function. */
-static function_t *current_function = NULL;
-static entity_t *current_init_decl = NULL;
-static switch_statement_t *current_switch = NULL;
-static statement_t *current_loop = NULL;
-static statement_t *current_parent = NULL;
-static ms_try_statement_t *current_try = NULL;
-static linkage_kind_t current_linkage = LINKAGE_INVALID;
-static goto_statement_t *goto_first = NULL;
-static goto_statement_t *goto_last = NULL;
-static label_statement_t *label_first = NULL;
-static label_statement_t *label_last = NULL;
+static function_t *current_function = NULL;
+static entity_t *current_init_decl = NULL;
+static switch_statement_t *current_switch = NULL;
+static statement_t *current_loop = NULL;
+static statement_t *current_parent = NULL;
+static ms_try_statement_t *current_try = NULL;
+static linkage_kind_t current_linkage = LINKAGE_INVALID;
+static goto_statement_t *goto_first = NULL;
+static goto_statement_t **goto_anchor = NULL;
+static label_statement_t *label_first = NULL;
+static label_statement_t **label_anchor = NULL;
/** current translation unit. */
-static translation_unit_t *unit = NULL;
+static translation_unit_t *unit = NULL;
/** true if we are in a type property context (evaluation only for type. */
-static bool in_type_prop = false;
+static bool in_type_prop = false;
/** true in we are in a __extension__ context. */
-static bool in_gcc_extension = false;
-static struct obstack temp_obst;
+static bool in_gcc_extension = false;
+static struct obstack temp_obst;
+static entity_t *anonymous_entity;
#define PUSH_PARENT(stmt) \
static void parse_external(void);
static void parse_compound_type_entries(compound_t *compound_declaration);
+
+typedef enum declarator_flags_t {
+ DECL_FLAGS_NONE = 0,
+ DECL_MAY_BE_ABSTRACT = 1U << 0,
+ DECL_CREATE_COMPOUND_MEMBER = 1U << 1,
+ DECL_IS_PARAMETER = 1U << 2
+} declarator_flags_t;
+
static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
- bool may_be_abstract,
- bool create_compound_member);
+ declarator_flags_t flags);
+
static entity_t *record_entity(entity_t *entity, bool is_definition);
static void semantic_comparison(binary_expression_t *expression);
-#define STORAGE_CLASSES \
- case T_typedef: \
- case T_extern: \
- case T_static: \
- case T_auto: \
- case T_register: \
- case T___thread:
+#define STORAGE_CLASSES \
+ STORAGE_CLASSES_NO_EXTERN \
+ case T_extern:
#define STORAGE_CLASSES_NO_EXTERN \
case T_typedef: \
va_end(ap);
}
-/**
- * Report a type error.
- */
-static void type_error(const char *msg, const source_position_t *source_position,
- type_t *type)
-{
- errorf(source_position, "%s, but found type '%T'", msg, type);
-}
-
/**
* Report an incompatible type.
*/
namespace_tag_t namespc)
{
entity_t *entity = symbol->entity;
- for( ; entity != NULL; entity = entity->base.symbol_next) {
+ for (; entity != NULL; entity = entity->base.symbol_next) {
if (entity->base.namespc == namespc)
return entity;
}
if (new_top == top)
return;
- for(i = top; i > new_top; --i) {
+ for (i = top; i > new_top; --i) {
stack_entry_t *entry = &stack[i - 1];
entity_t *old_entity = entry->old_entity;
string_t string = { NULL, 0 };
parse_gnu_attribute_string_arg(attribute, &string);
if (string.begin != NULL) {
- for(size_t i = 0; i < 4; ++i) {
+ for (size_t i = 0; i < 4; ++i) {
if (strcmp(tls_models[i], string.begin) == 0) {
attribute->u.value = i;
return;
string_t string = { NULL, 0 };
parse_gnu_attribute_string_arg(attribute, &string);
if (string.begin != NULL) {
- for(size_t i = 0; i < 4; ++i) {
+ for (size_t i = 0; i < 4; ++i) {
if (strcmp(visibilities[i], string.begin) == 0) {
attribute->u.value = i;
return;
string_t string = { NULL, 0 };
parse_gnu_attribute_string_arg(attribute, &string);
if (string.begin != NULL) {
- for(int i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; ++i) {
if (strcmp(visibilities[i], string.begin) == 0) {
attribute->u.value = i;
return;
string_t string = { NULL, 0 };
parse_gnu_attribute_string_arg(attribute, &string);
if (string.begin != NULL) {
- for(size_t i = 0; i < 5; ++i) {
+ for (size_t i = 0; i < 5; ++i) {
if (strcmp(interrupts[i], string.begin) == 0) {
attribute->u.value = i;
return;
goto end_error;
}
const char *name = token.v.symbol->string;
- for(i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; ++i) {
if (strcmp_underscore(format_names[i], name) == 0)
break;
}
next_token();
int i;
- for(i = 0; i < GNU_AK_LAST; ++i) {
+ for (i = 0; i < GNU_AK_LAST; ++i) {
if (strcmp_underscore(gnu_attribute_names[i], name) == 0)
break;
}
{
size_t len = ARR_LEN(path->path);
- for(size_t i = 0; i < len; ++i) {
+ for (size_t i = 0; i < len; ++i) {
const type_path_entry_t *entry = & path->path[i];
type_t *type = skip_typeref(entry->type);
fprintf(stderr, ".%s",
entry->v.compound_entry->base.symbol->string);
} else if (is_type_array(type)) {
- fprintf(stderr, "[%zu]", entry->v.index);
+ fprintf(stderr, "[%u]", (unsigned) entry->v.index);
} else {
fprintf(stderr, "-INVALID-");
}
static bool walk_designator(type_path_t *path, const designator_t *designator,
bool used_in_offsetof)
{
- for( ; designator != NULL; designator = designator->next) {
+ for (; designator != NULL; designator = designator->next) {
type_path_entry_t *top = get_type_path_top(path);
type_t *orig_type = top->type;
} else {
compound_t *compound = type->compound.compound;
entity_t *iter = compound->members.entities;
- for( ; iter != NULL; iter = iter->base.next) {
+ for (; iter != NULL; iter = iter->base.next) {
if (iter->base.symbol == symbol) {
break;
}
eat(T_union);
}
- symbol_t *symbol = NULL;
+ symbol_t *symbol = NULL;
compound_t *compound = NULL;
if (token.type == T___attribute__) {
}
if (token.type == '{') {
- compound->complete = true;
-
parse_compound_type_entries(compound);
modifiers |= parse_attributes(&attributes);
+
+ if (symbol == NULL) {
+ assert(anonymous_entity == NULL);
+ anonymous_entity = (entity_t*)compound;
+ }
}
compound->modifiers |= modifiers;
eat('{');
if (token.type == '}') {
- next_token();
errorf(HERE, "empty enum not allowed");
+ next_token();
return;
}
parse_enum_entries(type);
parse_attributes(&attributes);
- } else if(!entity->enume.complete && !(c_mode & _GNUC)) {
+
+ if (symbol == NULL) {
+ assert(anonymous_entity == NULL);
+ anonymous_entity = entity;
+ }
+ } else if (!entity->enume.complete && !(c_mode & _GNUC)) {
errorf(HERE, "enum %Y used before definition (incomplete enumes are a GNU extension)",
symbol);
}
return entity;
}
+static void parse_microsoft_based(based_spec_t *based_spec)
+{
+ if (token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing __based", T_IDENTIFIER, NULL);
+ return;
+ }
+ symbol_t *symbol = token.v.symbol;
+ entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
+
+ if (entity == NULL || entity->base.kind != ENTITY_VARIABLE) {
+ errorf(HERE, "'%Y' is not a variable name.", symbol);
+ entity = create_error_entity(symbol, ENTITY_VARIABLE);
+ } else {
+ variable_t *variable = &entity->variable;
+
+ if (based_spec->base_variable != NULL) {
+ errorf(HERE, "__based type qualifier specified more than once");
+ }
+ based_spec->source_position = token.source_position;
+ based_spec->base_variable = variable;
+
+ type_t *const type = variable->base.type;
+
+ if (is_type_valid(type)) {
+ if (! is_type_pointer(skip_typeref(type))) {
+ errorf(HERE, "variable in __based modifier must have pointer type instead of %T", type);
+ }
+ if (variable->base.base.parent_scope != file_scope) {
+ errorf(HERE, "a nonstatic local variable may not be used in a __based specification");
+ }
+ }
+ }
+ next_token();
+}
+
/**
* Finish the construction of a struct type by calculating
* its size, offsets, alignment.
modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
switch (token.type) {
-
/* storage class */
#define MATCH_STORAGE_CLASS(token, class) \
case token: \
errorf(HERE, "multiple storage classes in declaration specifiers"); \
} \
specifiers->storage_class = class; \
+ if (specifiers->thread_local) \
+ goto check_thread_storage_class; \
next_token(); \
break;
break;
case T___thread:
- switch (specifiers->storage_class) {
- case STORAGE_CLASS_NONE:
- specifiers->storage_class = STORAGE_CLASS_THREAD;
- break;
-
- case STORAGE_CLASS_EXTERN:
- specifiers->storage_class = STORAGE_CLASS_THREAD_EXTERN;
- break;
-
- case STORAGE_CLASS_STATIC:
- specifiers->storage_class = STORAGE_CLASS_THREAD_STATIC;
- break;
+ if (specifiers->thread_local) {
+ errorf(HERE, "duplicate '__thread'");
+ } else {
+ specifiers->thread_local = true;
+check_thread_storage_class:
+ switch (specifiers->storage_class) {
+ case STORAGE_CLASS_EXTERN:
+ case STORAGE_CLASS_NONE:
+ case STORAGE_CLASS_STATIC:
+ break;
- default:
- errorf(HERE, "multiple storage classes in declaration specifiers");
- break;
+ char const* wrong;
+ case STORAGE_CLASS_AUTO: wrong = "auto"; goto wrong_thread_stoarge_class;
+ case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_stoarge_class;
+ case STORAGE_CLASS_TYPEDEF: wrong = "typedef"; goto wrong_thread_stoarge_class;
+wrong_thread_stoarge_class:
+ errorf(HERE, "'__thread' used with '%s'", wrong);
+ break;
+ }
}
next_token();
break;
case T_inline:
case T__forceinline: /* ^ DECLARATION_START except for __attribute__ */
case T_IDENTIFIER:
+ case '&':
case '*':
errorf(HERE, "discarding stray %K in declaration specifier", &token);
next_token();
switch (la1_type) {
DECLARATION_START
case T_IDENTIFIER:
+ case '&':
case '*': {
errorf(HERE, "%K does not name a type", &token);
next_token();
saw_error = true;
- if (la1_type == '*')
+ if (la1_type == '&' || la1_type == '*')
goto finish_specifiers;
continue;
}
} while (token.type == T_IDENTIFIER);
}
-static type_t *automatic_type_conversion(type_t *orig_type);
-
static void semantic_parameter(declaration_t *declaration)
{
/* TODO: improve error messages */
source_position_t const* const pos = &declaration->base.source_position;
- /* §6.9.1:6 */
+ /* §6.9.1:6 The declarations in the declaration list shall contain no
+ * storage-class specifier other than register and no
+ * initializations. */
switch (declaration->declared_storage_class) {
/* Allowed storage classes */
case STORAGE_CLASS_NONE:
break;
}
- type_t *const orig_type = declaration->type;
- /* §6.7.5.3(7): Array as last part of a parameter type is just syntactic
- * sugar. Turn it into a pointer.
- * §6.7.5.3(8): A declaration of a parameter as ``function returning type''
- * shall be adjusted to ``pointer to function returning type'', as in 6.3.2.1.
- */
- type_t *const type = automatic_type_conversion(orig_type);
- declaration->type = type;
-
+ /* §6.7.5.3:4 After adjustment, the parameters in a parameter type list in
+ * a function declarator that is part of a definition of that
+ * function shall not have incomplete type. */
+ type_t *type = declaration->type;
if (is_type_incomplete(skip_typeref(type))) {
- errorf(pos, "parameter '%#T' is of incomplete type",
- orig_type, declaration->base.symbol);
+ errorf(pos, "parameter '%#T' has incomplete type",
+ type, declaration->base.symbol);
}
}
parse_declaration_specifiers(&specifiers);
- entity_t *entity = parse_declarator(&specifiers, true, false);
+ entity_t *entity = parse_declarator(&specifiers,
+ DECL_MAY_BE_ABSTRACT | DECL_IS_PARAMETER);
+ anonymous_entity = NULL;
return entity;
}
typedef enum construct_type_kind_t {
CONSTRUCT_INVALID,
CONSTRUCT_POINTER,
+ CONSTRUCT_REFERENCE,
CONSTRUCT_FUNCTION,
CONSTRUCT_ARRAY
} construct_type_kind_t;
struct parsed_pointer_t {
construct_type_t construct_type;
type_qualifiers_t type_qualifiers;
+ variable_t *base_variable; /**< MS __based extension. */
+};
+
+typedef struct parsed_reference_t parsed_reference_t;
+struct parsed_reference_t {
+ construct_type_t construct_type;
};
typedef struct construct_function_type_t construct_function_type_t;
type_t *type;
};
-static construct_type_t *parse_pointer_declarator(void)
+static construct_type_t *parse_pointer_declarator(variable_t *base_variable)
{
eat('*');
memset(pointer, 0, sizeof(pointer[0]));
pointer->construct_type.kind = CONSTRUCT_POINTER;
pointer->type_qualifiers = parse_type_qualifiers();
+ pointer->base_variable = base_variable;
+
+ return &pointer->construct_type;
+}
- return (construct_type_t*) pointer;
+static construct_type_t *parse_reference_declarator(void)
+{
+ eat('&');
+
+ parsed_reference_t *reference = obstack_alloc(&temp_obst, sizeof(reference[0]));
+ memset(reference, 0, sizeof(reference[0]));
+ reference->construct_type.kind = CONSTRUCT_REFERENCE;
+
+ return (construct_type_t*)reference;
}
static construct_type_t *parse_array_declarator(void)
expect(']');
end_error:
- return (construct_type_t*) array;
+ return &array->construct_type;
}
-static construct_type_t *parse_function_declarator(scope_t *scope)
+static construct_type_t *parse_function_declarator(scope_t *scope,
+ decl_modifiers_t modifiers)
{
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ function_type_t *ftype = &type->function;
- type->function.linkage = current_linkage;
+ ftype->linkage = current_linkage;
- /* TODO: revive this... once we know exactly how to do it */
-#if 0
- decl_modifiers_t modifiers = entity->declaration.modifiers;
+ switch (modifiers & (DM_CDECL | DM_STDCALL | DM_FASTCALL | DM_THISCALL)) {
+ case DM_NONE: break;
+ case DM_CDECL: ftype->calling_convention = CC_CDECL; break;
+ case DM_STDCALL: ftype->calling_convention = CC_STDCALL; break;
+ case DM_FASTCALL: ftype->calling_convention = CC_FASTCALL; break;
+ case DM_THISCALL: ftype->calling_convention = CC_THISCALL; break;
- unsigned mask = modifiers & (DM_CDECL|DM_STDCALL|DM_FASTCALL|DM_THISCALL);
-
- if (mask & (mask-1)) {
- const char *first = NULL, *second = NULL;
-
- /* more than one calling convention set */
- if (modifiers & DM_CDECL) {
- if (first == NULL) first = "cdecl";
- else if (second == NULL) second = "cdecl";
- }
- if (modifiers & DM_STDCALL) {
- if (first == NULL) first = "stdcall";
- else if (second == NULL) second = "stdcall";
- }
- if (modifiers & DM_FASTCALL) {
- if (first == NULL) first = "fastcall";
- else if (second == NULL) second = "fastcall";
- }
- if (modifiers & DM_THISCALL) {
- if (first == NULL) first = "thiscall";
- else if (second == NULL) second = "thiscall";
- }
- errorf(&entity->base.source_position,
- "%s and %s attributes are not compatible", first, second);
+ default:
+ errorf(HERE, "multiple calling conventions in declaration");
+ break;
}
- if (modifiers & DM_CDECL)
- type->function.calling_convention = CC_CDECL;
- else if (modifiers & DM_STDCALL)
- type->function.calling_convention = CC_STDCALL;
- else if (modifiers & DM_FASTCALL)
- type->function.calling_convention = CC_FASTCALL;
- else if (modifiers & DM_THISCALL)
- type->function.calling_convention = CC_THISCALL;
-#endif
-
- parse_parameters(&type->function, scope);
+ parse_parameters(ftype, scope);
construct_function_type_t *construct_function_type =
obstack_alloc(&temp_obst, sizeof(construct_function_type[0]));
decl_modifiers_t modifiers = parse_attributes(&attributes);
- /* pointers */
- while (token.type == '*') {
- construct_type_t *type = parse_pointer_declarator();
+ /* MS __based extension */
+ based_spec_t base_spec;
+ base_spec.base_variable = NULL;
+
+ for (;;) {
+ construct_type_t *type;
+ switch (token.type) {
+ case '&':
+ if (!(c_mode & _CXX))
+ errorf(HERE, "references are only available for C++");
+ if (base_spec.base_variable != NULL && warning.other) {
+ warningf(&base_spec.source_position,
+ "__based does not precede a pointer operator, ignored");
+ }
+ type = parse_reference_declarator();
+ /* consumed */
+ base_spec.base_variable = NULL;
+ break;
+
+ case '*':
+ type = parse_pointer_declarator(base_spec.base_variable);
+ /* consumed */
+ base_spec.base_variable = NULL;
+ break;
+
+ case T__based:
+ next_token();
+ expect('(');
+ add_anchor_token(')');
+ parse_microsoft_based(&base_spec);
+ rem_anchor_token(')');
+ expect(')');
+ continue;
+
+ default:
+ goto ptr_operator_end;
+ }
if (last == NULL) {
first = type;
/* TODO: find out if this is correct */
modifiers |= parse_attributes(&attributes);
}
+ptr_operator_end:
+ if (base_spec.base_variable != NULL && warning.other) {
+ warningf(&base_spec.source_position,
+ "__based does not precede a pointer operator, ignored");
+ }
- if (env != NULL)
- env->modifiers |= modifiers;
+ if (env != NULL) {
+ modifiers |= env->modifiers;
+ env->modifiers = modifiers;
+ }
construct_type_t *inner_types = NULL;
construct_type_t *p = last;
- while(true) {
+ while (true) {
construct_type_t *type;
switch (token.type) {
case '(': {
if (env != NULL)
scope = &env->parameters;
- type = parse_function_declarator(scope);
+ type = parse_function_declarator(scope, modifiers);
break;
}
case '[':
}
}
-static type_t *construct_declarator_type(construct_type_t *construct_list,
- type_t *type)
+static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type)
{
construct_type_t *iter = construct_list;
- for( ; iter != NULL; iter = iter->next) {
+ for (; iter != NULL; iter = iter->next) {
switch (iter->kind) {
case CONSTRUCT_INVALID:
internal_errorf(HERE, "invalid type construction found");
}
case CONSTRUCT_POINTER: {
+ if (is_type_reference(skip_typeref(type)))
+ errorf(HERE, "cannot declare a pointer to reference");
+
parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter;
- type = make_pointer_type(type, parsed_pointer->type_qualifiers);
+ type = make_based_pointer_type(type, parsed_pointer->type_qualifiers, parsed_pointer->base_variable);
continue;
}
+ case CONSTRUCT_REFERENCE:
+ if (is_type_reference(skip_typeref(type)))
+ errorf(HERE, "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");
+
parsed_array_t *parsed_array = (parsed_array_t*) iter;
type_t *array_type = allocate_type_zero(TYPE_ARRAY);
return type;
}
+static type_t *automatic_type_conversion(type_t *orig_type);
+
static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
- bool may_be_abstract,
- bool create_compound_member)
+ declarator_flags_t flags)
{
parse_declarator_env_t env;
memset(&env, 0, sizeof(env));
+ env.modifiers = specifiers->modifiers;
- construct_type_t *construct_type
- = parse_inner_declarator(&env, may_be_abstract);
- type_t *type = construct_declarator_type(construct_type, specifiers->type);
+ construct_type_t *construct_type =
+ parse_inner_declarator(&env, (flags & DECL_MAY_BE_ABSTRACT) != 0);
+ type_t *orig_type =
+ construct_declarator_type(construct_type, specifiers->type);
+ type_t *type = skip_typeref(orig_type);
if (construct_type != NULL) {
obstack_free(&temp_obst, construct_type);
entity = allocate_entity_zero(ENTITY_TYPEDEF);
entity->base.symbol = env.symbol;
entity->base.source_position = env.source_position;
- entity->typedefe.type = type;
+ entity->typedefe.type = orig_type;
+
+ if (anonymous_entity != NULL) {
+ if (is_type_compound(type)) {
+ assert(anonymous_entity->compound.alias == NULL);
+ assert(anonymous_entity->kind == ENTITY_STRUCT ||
+ anonymous_entity->kind == ENTITY_UNION);
+ anonymous_entity->compound.alias = entity;
+ anonymous_entity = NULL;
+ } else if (is_type_enum(type)) {
+ assert(anonymous_entity->enume.alias == NULL);
+ assert(anonymous_entity->kind == ENTITY_ENUM);
+ anonymous_entity->enume.alias = entity;
+ anonymous_entity = NULL;
+ }
+ }
} else {
- if (create_compound_member) {
- entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
- } else if (is_type_function(skip_typeref(type))) {
+ if (flags & DECL_CREATE_COMPOUND_MEMBER) {
+ entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
+
+ if (specifiers->is_inline && is_type_valid(type)) {
+ errorf(&env.source_position,
+ "compound member '%Y' declared 'inline'", env.symbol);
+ }
+
+ if (specifiers->thread_local ||
+ specifiers->storage_class != STORAGE_CLASS_NONE) {
+ errorf(&env.source_position,
+ "compound member '%Y' must have no storage class",
+ env.symbol);
+ }
+ } else if (flags & DECL_IS_PARAMETER) {
+ /* §6.7.5.3:7 A declaration of a parameter as ``array of type''
+ * shall be adjusted to ``qualified pointer to type'',
+ * [...]
+ * §6.7.5.3:8 A declaration of a parameter as ``function returning
+ * type'' shall be adjusted to ``pointer to function
+ * returning type'', as in 6.3.2.1. */
+ orig_type = automatic_type_conversion(type);
+ goto create_variable;
+ } else if (is_type_function(type)) {
entity = allocate_entity_zero(ENTITY_FUNCTION);
entity->function.is_inline = specifiers->is_inline;
entity->function.parameters = env.parameters;
+
+ if (specifiers->thread_local || (
+ specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+ specifiers->storage_class != STORAGE_CLASS_NONE &&
+ specifiers->storage_class != STORAGE_CLASS_STATIC)
+ ) {
+ errorf(&env.source_position,
+ "invalid storage class for function '%Y'", env.symbol);
+ }
} else {
+create_variable:
entity = allocate_entity_zero(ENTITY_VARIABLE);
entity->variable.get_property_sym = specifiers->get_property_sym;
entity->variable.alignment = specifiers->alignment;
}
- if (warning.other && specifiers->is_inline && is_type_valid(type)) {
- warningf(&env.source_position,
- "variable '%Y' declared 'inline'\n", env.symbol);
+ if (specifiers->is_inline && is_type_valid(type)) {
+ errorf(&env.source_position,
+ "variable '%Y' declared 'inline'", env.symbol);
+ }
+
+ entity->variable.thread_local = specifiers->thread_local;
+
+ bool invalid_storage_class = false;
+ if (current_scope == file_scope) {
+ if (specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+ specifiers->storage_class != STORAGE_CLASS_NONE &&
+ specifiers->storage_class != STORAGE_CLASS_STATIC) {
+ invalid_storage_class = true;
+ }
+ } else {
+ if (specifiers->thread_local &&
+ specifiers->storage_class == STORAGE_CLASS_NONE) {
+ invalid_storage_class = true;
+ }
+ }
+ if (invalid_storage_class) {
+ errorf(&env.source_position,
+ "invalid storage class for variable '%Y'", env.symbol);
}
}
- entity->base.source_position = env.source_position;
- entity->base.symbol = env.symbol;
- entity->base.namespc = NAMESPACE_NORMAL;
- entity->declaration.type = type;
- entity->declaration.modifiers = env.modifiers | specifiers->modifiers;
+ entity->base.source_position = env.source_position;
+ entity->base.symbol = env.symbol;
+ entity->base.namespc = NAMESPACE_NORMAL;
+ entity->declaration.type = orig_type;
+ entity->declaration.modifiers = env.modifiers;
entity->declaration.deprecated_string = specifiers->deprecated_string;
storage_class_t storage_class = specifiers->storage_class;
&& entity->kind == ENTITY_VARIABLE
&& current_scope == file_scope) {
declaration_t *declaration = &entity->declaration;
- if (declaration->storage_class == STORAGE_CLASS_NONE ||
- declaration->storage_class == STORAGE_CLASS_THREAD) {
+ if (declaration->storage_class == STORAGE_CLASS_NONE) {
warningf(pos, "no previous declaration for '%#T'",
declaration->type, symbol);
}
}
bool must_be_constant = false;
- if (declaration->storage_class == STORAGE_CLASS_STATIC ||
- declaration->storage_class == STORAGE_CLASS_THREAD_STATIC ||
+ if (declaration->storage_class == STORAGE_CLASS_STATIC ||
entity->base.parent_scope == file_scope) {
must_be_constant = true;
}
const declaration_specifiers_t *specifiers)
{
eat(';');
+ anonymous_entity = NULL;
if (warning.other) {
- if (specifiers->storage_class != STORAGE_CLASS_NONE) {
+ if (specifiers->storage_class != STORAGE_CLASS_NONE ||
+ specifiers->thread_local) {
warningf(&specifiers->source_position,
"useless storage class in empty declaration");
}
}
}
+static void check_variable_type_complete(entity_t *ent)
+{
+ if (ent->kind != ENTITY_VARIABLE)
+ return;
+
+ /* §6.7:7 If an identifier for an object is declared with no linkage, the
+ * type for the object shall be complete [...] */
+ declaration_t *decl = &ent->declaration;
+ if (decl->storage_class != STORAGE_CLASS_NONE)
+ return;
+
+ type_t *type = decl->type;
+ if (!is_type_incomplete(skip_typeref(type)))
+ return;
+
+ errorf(&ent->base.source_position, "variable '%#T' has incomplete type",
+ type, ent->base.symbol);
+}
+
+
static void parse_declaration_rest(entity_t *ndeclaration,
const declaration_specifiers_t *specifiers,
parsed_declaration_func finished_declaration)
{
add_anchor_token(';');
add_anchor_token(',');
- while(true) {
+ while (true) {
entity_t *entity = finished_declaration(ndeclaration, token.type == '=');
if (token.type == '=') {
parse_init_declarator_rest(entity);
+ } else if (entity->kind == ENTITY_VARIABLE) {
+ /* ISO/IEC 14882:1998(E) §8.5.3:3 The initializer can be omitted
+ * [...] where the extern specifier is explicitly used. */
+ declaration_t *decl = &entity->declaration;
+ 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);
+ }
+ }
}
+ check_variable_type_complete(entity);
+
if (token.type != ',')
break;
eat(',');
add_anchor_token('=');
- ndeclaration = parse_declarator(specifiers, /*may_be_abstract=*/false, false);
+ ndeclaration = parse_declarator(specifiers, DECL_FLAGS_NONE);
rem_anchor_token('=');
}
expect(';');
end_error:
+ anonymous_entity = NULL;
rem_anchor_token(';');
rem_anchor_token(',');
}
if (token.type == ';') {
parse_anonymous_declaration_rest(&specifiers);
} else {
- entity_t *entity = parse_declarator(&specifiers, /*may_be_abstract=*/false, false);
+ entity_t *entity = parse_declarator(&specifiers, DECL_FLAGS_NONE);
parse_declaration_rest(entity, &specifiers, finished_declaration);
}
}
function_parameter_t *last_parameter = NULL;
entity_t *parameter_declaration = entity->function.parameters.entities;
- for( ; parameter_declaration != NULL;
+ for (; parameter_declaration != NULL;
parameter_declaration = parameter_declaration->base.next) {
type_t *parameter_type = parameter_declaration->declaration.type;
if (parameter_type == NULL) {
"label '%Y' used but not defined", label->base.symbol);
}
}
- goto_first = NULL;
- goto_last = NULL;
if (warning.unused_label) {
for (const label_statement_t *label_statement = label_first;
}
}
}
- label_first = label_last = NULL;
}
static void warn_unused_decl(entity_t *entity, entity_t *end,
add_anchor_token('{');
/* declarator is common to both function-definitions and declarations */
- entity_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false, false);
+ entity_t *ndeclaration = parse_declarator(&specifiers, DECL_FLAGS_NONE);
rem_anchor_token('{');
rem_anchor_token(';');
scope_push(&function->parameters);
entity_t *parameter = function->parameters.entities;
- for( ; parameter != NULL; parameter = parameter->base.next) {
+ for (; parameter != NULL; parameter = parameter->base.next) {
if (parameter->base.parent_scope == &ndeclaration->function.parameters) {
parameter->base.parent_scope = current_scope;
}
current_function = function;
current_parent = NULL;
- statement_t *const body = parse_compound_statement(false);
+ goto_first = NULL;
+ goto_anchor = &goto_first;
+ label_first = NULL;
+ label_anchor = &label_first;
+
+ statement_t *const body = parse_compound_statement(false);
function->statement = body;
first_err = true;
check_labels();
long v = fold_constant(size);
if (v < 0) {
- errorf(source_position, "negative width in bit-field '%Y'",
- symbol);
+ errorf(source_position, "negative width in bit-field '%Y'", symbol);
} else if (v == 0) {
- errorf(source_position, "zero width for bit-field '%Y'",
- symbol);
+ errorf(source_position, "zero width for bit-field '%Y'", symbol);
} else if (bit_size > 0 && (il_size_t)v > bit_size) {
- errorf(source_position, "width of '%Y' exceeds its type",
- symbol);
+ errorf(source_position, "width of '%Y' exceeds its type", symbol);
} else {
type->bitfield.bit_size = v;
}
static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
{
entity_t *iter = compound->members.entities;
- for( ; iter != NULL; iter = iter->base.next) {
+ for (; iter != NULL; iter = iter->base.next) {
if (iter->kind != ENTITY_COMPOUND_MEMBER)
continue;
- if (iter->base.symbol == NULL) {
+ if (iter->base.symbol == symbol) {
+ return iter;
+ } else if (iter->base.symbol == NULL) {
type_t *type = skip_typeref(iter->declaration.type);
if (is_type_compound(type)) {
entity_t *result
}
continue;
}
-
- if (iter->base.symbol == symbol) {
- return iter;
- }
}
return NULL;
entity->declaration.modifiers = specifiers->modifiers;
entity->declaration.type = type;
} else {
- entity = parse_declarator(specifiers,/*may_be_abstract=*/true, true);
+ entity = parse_declarator(specifiers,
+ DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
assert(entity->kind == ENTITY_COMPOUND_MEMBER);
if (token.type == ':') {
entity_t *prev = find_compound_entry(compound, symbol);
if (prev != NULL) {
- assert(prev->base.symbol == symbol);
errorf(&entity->base.source_position,
"multiple declarations of symbol '%Y' (declared %P)",
symbol, &prev->base.source_position);
append_entity(&compound->members, entity);
- if (token.type != ',')
- break;
- next_token();
- }
- expect(';');
-
-end_error:
- ;
-}
-
-static void semantic_compound(compound_t *compound)
-{
- entity_t *entity = compound->members.entities;
- for ( ; entity != NULL; entity = entity->base.next) {
- assert(entity->kind == ENTITY_COMPOUND_MEMBER);
-
type_t *orig_type = entity->declaration.type;
type_t *type = skip_typeref(orig_type);
-
if (is_type_function(type)) {
- errorf(HERE,
- "compound member '%Y' must not have function type '%T'",
- entity->base.symbol, orig_type);
+ errorf(&entity->base.source_position,
+ "compound member '%Y' must not have function type '%T'",
+ entity->base.symbol, orig_type);
} else if (is_type_incomplete(type)) {
- /* §6.7.2.1 (16) flexible array member */
- if (is_type_array(type) && entity->base.next == NULL) {
+ /* §6.7.2.1:16 flexible array member */
+ if (is_type_array(type) &&
+ token.type == ';' &&
+ look_ahead(1)->type == '}') {
compound->has_flexible_member = true;
} else {
- errorf(HERE,
- "compound member '%Y' has incomplete type '%T'",
- entity->base.symbol, orig_type);
+ errorf(&entity->base.source_position,
+ "compound member '%Y' has incomplete type '%T'",
+ entity->base.symbol, orig_type);
}
}
+
+ if (token.type != ',')
+ break;
+ next_token();
}
+ expect(';');
+
+end_error:
+ anonymous_entity = NULL;
}
static void parse_compound_type_entries(compound_t *compound)
parse_compound_declarators(compound, &specifiers);
}
- semantic_compound(compound);
rem_anchor_token('}');
next_token();
+
+ /* §6.7.2.1:7 */
+ compound->complete = true;
}
static type_t *parse_typename(void)
declaration_specifiers_t specifiers;
memset(&specifiers, 0, sizeof(specifiers));
parse_declaration_specifiers(&specifiers);
- if (specifiers.storage_class != STORAGE_CLASS_NONE) {
+ if (specifiers.storage_class != STORAGE_CLASS_NONE ||
+ specifiers.thread_local) {
/* TODO: improve error message, user does probably not know what a
* storage class is...
*/
cnst->conste.v.character = token.v.string;
if (cnst->conste.v.character.size != 1) {
- if (warning.multichar && GNU_MODE) {
+ if (!GNU_MODE) {
+ errorf(HERE, "more than 1 character in character constant");
+ } else if (warning.multichar) {
warningf(HERE, "multi-character character constant");
- } else {
- errorf(HERE, "more than 1 characters in character constant");
}
}
next_token();
cnst->conste.v.wide_character = token.v.wide_string;
if (cnst->conste.v.wide_character.size != 1) {
- if (warning.multichar && GNU_MODE) {
+ if (!GNU_MODE) {
+ errorf(HERE, "more than 1 character in character constant");
+ } else if (warning.multichar) {
warningf(HERE, "multi-character character constant");
- } else {
- errorf(HERE, "more than 1 characters in character constant");
}
}
next_token();
next_token();
designator_t *last_designator = result;
- while(true) {
+ while (true) {
if (token.type == '.') {
next_token();
if (token.type != T_IDENTIFIER) {
add_anchor_token(',');
if (token.type != ')') {
- while(true) {
+ while (true) {
(void)parse_assignment_expression();
if (token.type != ',')
break;
eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__);
- char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
-
/* we only refer to a type property, mark this case */
bool old = in_type_prop;
in_type_prop = true;
type->kind == TYPE_BITFIELD ? "bitfield" :
NULL;
if (wrong_type != NULL) {
+ char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
errorf(&tp_expression->base.source_position,
"operand of %s expression must not be of %s type '%T'",
what, wrong_type, orig_type);
}
/* do default promotion */
- for( ; argument != NULL; argument = argument->next) {
+ for (; argument != NULL; argument = argument->next) {
type_t *type = argument->expression->base.type;
type = get_default_promoted_type(type);
}
}
+static void semantic_condition(expression_t const *const expr,
+ char const *const context)
+{
+ type_t *const type = skip_typeref(expr->base.type);
+ if (is_type_scalar(type)) {
+ warn_reference_address_as_bool(expr);
+ } else if (is_type_valid(type)) {
+ errorf(&expr->base.source_position,
+ "%s must have scalar type", context);
+ }
+}
+
/**
* Parse a conditional expression, ie. 'expression ? ... : ...'.
*
conditional_expression_t *conditional = &result->conditional;
conditional->condition = expression;
- warn_reference_address_as_bool(expression);
-
eat('?');
add_anchor_token(':');
- /* 6.5.15.2 */
- type_t *const condition_type_orig = expression->base.type;
- type_t *const condition_type = skip_typeref(condition_type_orig);
- if (!is_type_scalar(condition_type) && is_type_valid(condition_type)) {
- type_error("expected a scalar type in conditional condition",
- &expression->base.source_position, condition_type_orig);
- }
+ /* §6.5.15:2 The first operand shall have scalar type. */
+ semantic_condition(expression, "condition of conditional operator");
expression_t *true_expression = expression;
bool gnu_cond = false;
case EXPR_UNARY_DEREFERENCE:
return true;
- default:
+ default: {
+ type_t *type = skip_typeref(expression->base.type);
+ return
+ /* ISO/IEC 14882:1998(E) §3.10:3 */
+ is_type_reference(type) ||
/* Claim it is an lvalue, if the type is invalid. There was a parse
* error before, which maybe prevented properly recognizing it as
* lvalue. */
- return !is_type_valid(skip_typeref(expression->base.type));
+ !is_type_valid(type);
+ }
}
}
static void semantic_not(unary_expression_t *expression)
{
- type_t *const orig_type = expression->value->base.type;
- type_t *const type = skip_typeref(orig_type);
- if (!is_type_scalar(type) && is_type_valid(type)) {
- errorf(&expression->base.source_position,
- "operand of ! must be of scalar type");
- }
-
- warn_reference_address_as_bool(expression->value);
-
+ /* §6.5.3.3:1 The operand [...] of the ! operator, scalar type. */
+ semantic_condition(expression->value, "operand of !");
expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
*/
static void semantic_logical_op(binary_expression_t *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);
-
- warn_reference_address_as_bool(left);
- warn_reference_address_as_bool(right);
-
- if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) {
- /* TODO: improve error message */
- if (is_type_valid(type_left) && is_type_valid(type_right)) {
- errorf(&expression->base.source_position,
- "operation needs scalar types");
- }
- return;
- }
-
+ /* §6.5.13:2 Each of the operands shall have scalar type.
+ * §6.5.14:2 Each of the operands shall have scalar type. */
+ semantic_condition(expression->left, "left operand of logical operator");
+ semantic_condition(expression->right, "right operand of logical operator");
expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
assert(left != NULL);
left->base.source_position = source_position;
- while(true) {
+ while (true) {
if (token.type < 0) {
return expected_expression_error();
}
*/
static asm_argument_t *parse_asm_arguments(bool is_out)
{
- asm_argument_t *result = NULL;
- asm_argument_t *last = NULL;
+ asm_argument_t *result = NULL;
+ asm_argument_t **anchor = &result;
while (token.type == T_STRING_LITERAL || token.type == '[') {
asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
set_address_taken(expression, true);
- if (last != NULL) {
- last->next = argument;
- } else {
- result = argument;
- }
- last = argument;
+ *anchor = argument;
+ anchor = &argument->next;
if (token.type != ',')
break;
asm_clobber_t *result = NULL;
asm_clobber_t *last = NULL;
- while(token.type == T_STRING_LITERAL) {
+ while (token.type == T_STRING_LITERAL) {
asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
clobber->clobber = parse_string_literals();
}
/* remember the labels in a list for later checking */
- if (label_last == NULL) {
- label_first = &statement->label;
- } else {
- label_last->next = &statement->label;
- }
- label_last = &statement->label;
+ *label_anchor = &statement->label;
+ label_anchor = &statement->label.next;
POP_PARENT;
return statement;
add_anchor_token(')');
expression_t *const expr = parse_expression();
statement->ifs.condition = expr;
- warn_reference_address_as_bool(expr);
+ /* §6.8.4.1:1 The controlling expression of an if statement shall have
+ * scalar type. */
+ semantic_condition(expr, "condition of 'if'-statment");
mark_vars_read(expr, NULL);
rem_anchor_token(')');
expect(')');
add_anchor_token(')');
expression_t *const cond = parse_expression();
statement->whiles.condition = cond;
- warn_reference_address_as_bool(cond);
+ /* §6.8.5:2 The controlling expression of an iteration statement shall
+ * have scalar type. */
+ semantic_condition(cond, "condition of 'while'-statement");
mark_vars_read(cond, NULL);
rem_anchor_token(')');
expect(')');
add_anchor_token(')');
expression_t *const cond = parse_expression();
statement->do_while.condition = cond;
- warn_reference_address_as_bool(cond);
+ /* §6.8.5:2 The controlling expression of an iteration statement shall
+ * have scalar type. */
+ semantic_condition(cond, "condition of 'do-while'-statement");
mark_vars_read(cond, NULL);
rem_anchor_token(')');
expect(')');
expect('(');
add_anchor_token(')');
- if (token.type != ';') {
- if (is_declaration_specifier(&token, false)) {
- parse_declaration(record_entity);
- } else {
- add_anchor_token(';');
- expression_t *const init = parse_expression();
- statement->fors.initialisation = init;
- mark_vars_read(init, VAR_ANY);
- if (warning.unused_value && !expression_has_effect(init)) {
- warningf(&init->base.source_position,
- "initialisation of 'for'-statement has no effect");
- }
- rem_anchor_token(';');
- expect(';');
- }
+ if (token.type == ';') {
+ next_token();
+ } else if (is_declaration_specifier(&token, false)) {
+ parse_declaration(record_entity);
} else {
+ add_anchor_token(';');
+ expression_t *const init = parse_expression();
+ statement->fors.initialisation = init;
+ mark_vars_read(init, VAR_ANY);
+ if (warning.unused_value && !expression_has_effect(init)) {
+ warningf(&init->base.source_position,
+ "initialisation of 'for'-statement has no effect");
+ }
+ rem_anchor_token(';');
expect(';');
}
add_anchor_token(';');
expression_t *const cond = parse_expression();
statement->fors.condition = cond;
- warn_reference_address_as_bool(cond);
+ /* §6.8.5:2 The controlling expression of an iteration statement shall
+ * have scalar type. */
+ semantic_condition(cond, "condition of 'for'-statement");
mark_vars_read(cond, NULL);
rem_anchor_token(';');
}
expression_t *expression = parse_expression();
mark_vars_read(expression, NULL);
- /* Argh: although documentation say the expression must be of type void *,
- * gcc excepts anything that can be casted into void * without error */
+ /* Argh: although documentation says the expression must be of type void*,
+ * gcc accepts anything that can be casted into void* without error */
type_t *type = expression->base.type;
if (type != type_error_type) {
}
/* remember the goto's in a list for later checking */
- if (goto_last == NULL) {
- goto_first = &statement->gotos;
- } else {
- goto_last->next = &statement->gotos;
- }
- goto_last = &statement->gotos;
+ *goto_anchor = &statement->gotos;
+ goto_anchor = &statement->gotos.next;
expect(';');
* declaration types, so we guess a bit here to improve robustness
* for incorrect programs */
switch (la1_type) {
+ case '&':
case '*':
if (get_entity(token.v.symbol, NAMESPACE_NORMAL) != NULL)
goto expression_statment;
} while (token.type == T___extension__);
bool old_gcc_extension = in_gcc_extension;
in_gcc_extension = true;
- statement = parse_statement();
+ statement = intern_parse_statement();
in_gcc_extension = old_gcc_extension;
break;
/* look over all statements again to produce no effect warnings */
if (warning.unused_value) {
statement_t *sub_statement = statement->compound.statements;
- for( ; sub_statement != NULL; sub_statement = sub_statement->base.next) {
+ for (; sub_statement != NULL; sub_statement = sub_statement->base.next) {
if (sub_statement->kind != STATEMENT_EXPRESSION)
continue;
/* don't emit a warning for the last expression in an expression