unsigned char alignment; /**< Alignment, 0 if not set. */
unsigned int is_inline : 1;
unsigned int deprecated : 1;
- decl_modifiers_t decl_modifiers; /**< MS __declspec extended modifier mask */
+ 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. */
symbol_t *get_property_sym; /**< the name of the get property if set. */
attribute->u.value = true;
}
+static void check_no_argument(gnu_attribute_t *attribute, const char *name)
+{
+ if(!attribute->have_arguments)
+ return;
+
+ /* should have no arguments */
+ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+ eat_until_matching_token('(');
+ /* we have already consumed '(', so we stop before ')', eat it */
+ eat(')');
+ attribute->invalid = true;
+}
+
/**
* Parse one GNU attribute.
*
* interrupt( string literal )
* sentinel( constant expression )
*/
-static void parse_gnu_attribute(gnu_attribute_t **attributes)
+static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes)
{
- gnu_attribute_t *head = *attributes;
- gnu_attribute_t *last = *attributes;
+ gnu_attribute_t *head = *attributes;
+ gnu_attribute_t *last = *attributes;
+ decl_modifiers_t modifiers = 0;
gnu_attribute_t *attribute;
eat(T___attribute__);
case GNU_AK_STDCALL:
case GNU_AK_FASTCALL:
case GNU_AK_DEPRECATED:
- case GNU_AK_NOINLINE:
- case GNU_AK_NORETURN:
case GNU_AK_NAKED:
- case GNU_AK_PURE:
- case GNU_AK_ALWAYS_INLINE:
case GNU_AK_MALLOC:
case GNU_AK_WEAK:
- case GNU_AK_CONSTRUCTOR:
- case GNU_AK_DESTRUCTOR:
- case GNU_AK_NOTHROW:
- case GNU_AK_TRANSPARENT_UNION:
case GNU_AK_COMMON:
case GNU_AK_NOCOMMON:
- case GNU_AK_PACKED:
case GNU_AK_SHARED:
case GNU_AK_NOTSHARED:
case GNU_AK_USED:
case GNU_AK_MAY_ALIAS:
case GNU_AK_MS_STRUCT:
case GNU_AK_GCC_STRUCT:
+ check_no_argument(attribute, name);
+ break;
+
+ case GNU_AK_PURE:
+ check_no_argument(attribute, name);
+ modifiers |= DM_PURE;
+ break;
+
+ case GNU_AK_ALWAYS_INLINE:
+ check_no_argument(attribute, name);
+ modifiers |= DM_FORCEINLINE;
+ break;
+
case GNU_AK_DLLIMPORT:
+ check_no_argument(attribute, name);
+ modifiers |= DM_DLLIMPORT;
+ break;
+
case GNU_AK_DLLEXPORT:
- if(attribute->have_arguments) {
- /* should have no arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- eat_until_matching_token('(');
- /* we have already consumed '(', so we stop before ')', eat it */
- eat(')');
- attribute->invalid = true;
- }
+ check_no_argument(attribute, name);
+ modifiers |= DM_DLLEXPORT;
+ break;
+
+ case GNU_AK_PACKED:
+ check_no_argument(attribute, name);
+ modifiers |= DM_PACKED;
+ break;
+
+ case GNU_AK_NOINLINE:
+ check_no_argument(attribute, name);
+ modifiers |= DM_NOINLINE;
+ break;
+
+ case GNU_AK_NORETURN:
+ check_no_argument(attribute, name);
+ modifiers |= DM_NORETURN;
+ break;
+
+ case GNU_AK_NOTHROW:
+ check_no_argument(attribute, name);
+ modifiers |= DM_NOTHROW;
+ break;
+
+ case GNU_AK_TRANSPARENT_UNION:
+ check_no_argument(attribute, name);
+ modifiers |= DM_TRANSPARENT_UNION;
+ break;
+
+ case GNU_AK_CONSTRUCTOR:
+ check_no_argument(attribute, name);
+ modifiers |= DM_CONSTRUCTOR;
+ break;
+
+ case GNU_AK_DESTRUCTOR:
+ check_no_argument(attribute, name);
+ modifiers |= DM_DESTRUCTOR;
break;
case GNU_AK_ALIGNED:
expect(')');
end_error:
*attributes = head;
+
+ return modifiers;
}
/**
* Parse GNU attributes.
*/
-static void parse_attributes(gnu_attribute_t **attributes)
+static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes)
{
+ decl_modifiers_t modifiers = 0;
+
while(true) {
switch(token.type) {
case T___attribute__: {
- parse_gnu_attribute(attributes);
+ modifiers |= parse_gnu_attribute(attributes);
break;
}
case T_asm:
attributes_finished:
end_error:
- return;
+ return modifiers;
}
static designator_t *parse_designation(void)
size = result->wide_string.string.size;
break;
+ case INITIALIZER_DESIGNATOR:
+ case INITIALIZER_VALUE:
+ /* can happen for parse errors */
+ size = 0;
+ break;
+
default:
internal_errorf(HERE, "invalid initializer type");
}
static declaration_t *parse_compound_type_specifier(bool is_struct)
{
- gnu_attribute_t *attributes = NULL;
+ gnu_attribute_t *attributes = NULL;
+ decl_modifiers_t modifiers = 0;
if(is_struct) {
eat(T_struct);
} else {
declaration_t *declaration = NULL;
if (token.type == T___attribute__) {
- parse_attributes(&attributes);
+ modifiers |= parse_attributes(&attributes);
}
if(token.type == T_IDENTIFIER) {
if(token.type == '{') {
if (declaration->init.complete) {
assert(symbol != NULL);
- errorf(HERE, "multiple definitions of '%s %Y'",
- is_struct ? "struct" : "union", symbol);
+ errorf(HERE, "multiple definitions of '%s %Y' (previous definition at %P)",
+ is_struct ? "struct" : "union", symbol,
+ &declaration->source_position);
declaration->scope.declarations = NULL;
}
declaration->init.complete = true;
parse_compound_type_entries(declaration);
- parse_attributes(&attributes);
+ modifiers |= parse_attributes(&attributes);
}
+ declaration->modifiers |= modifiers;
return declaration;
}
static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *specifiers)
{
- decl_modifiers_t *modifiers = &specifiers->decl_modifiers;
+ decl_modifiers_t *modifiers = &specifiers->modifiers;
while(true) {
if(token.type == T_restrict) {
case T__forceinline:
/* only in microsoft mode */
- specifiers->decl_modifiers |= DM_FORCEINLINE;
+ specifiers->modifiers |= DM_FORCEINLINE;
case T_inline:
next_token();
break;
case T___attribute__:
- parse_attributes(&specifiers->gnu_attributes);
+ specifiers->modifiers
+ |= parse_attributes(&specifiers->gnu_attributes);
break;
case T_IDENTIFIER: {
}
/* TODO: find out if this is correct */
- parse_attributes(&attributes);
+ decl_modifiers_t modifiers = parse_attributes(&attributes);
+ if (declaration != NULL)
+ declaration->modifiers |= modifiers;
construct_type_t *inner_types = NULL;
}
declarator_finished:
- parse_attributes(&attributes);
+ modifiers = parse_attributes(&attributes);
+ if (declaration != NULL)
+ declaration->modifiers |= modifiers;
/* append inner_types at the end of the list, we don't to set last anymore
* as it's not needed anymore */
{
declaration_t *const declaration = allocate_declaration_zero();
declaration->declared_storage_class = specifiers->declared_storage_class;
- declaration->decl_modifiers = specifiers->decl_modifiers;
+ declaration->modifiers = specifiers->modifiers;
declaration->deprecated = specifiers->deprecated;
declaration->deprecated_string = specifiers->deprecated_string;
declaration->get_property_sym = specifiers->get_property_sym;
declaration->type = specifiers->type;
declaration->declared_storage_class = specifiers->declared_storage_class;
declaration->source_position = specifiers->source_position;
- declaration->decl_modifiers = specifiers->decl_modifiers;
+ declaration->modifiers = specifiers->modifiers;
if (declaration->declared_storage_class != STORAGE_CLASS_NONE) {
warningf(&declaration->source_position,
assert(parameter->parent_scope == NULL
|| parameter->parent_scope == scope);
parameter->parent_scope = scope;
+ if (parameter->symbol == NULL) {
+ errorf(&ndeclaration->source_position, "parameter name omitted");
+ continue;
+ }
environment_push(parameter);
}
declaration->declared_storage_class = STORAGE_CLASS_NONE;
declaration->storage_class = STORAGE_CLASS_NONE;
declaration->source_position = source_position;
- declaration->decl_modifiers = specifiers->decl_modifiers;
+ declaration->modifiers = specifiers->modifiers;
declaration->type = type;
} else {
declaration = parse_declarator(specifiers,/*may_be_abstract=*/true);
other_expression = true_expression;
}
- if(is_type_pointer(other_type)) {
- if(!pointers_compatible(true_type, false_type)) {
+ /* TODO Treat (void*)0 as null pointer constant */
+ if (is_type_pointer(other_type)) {
+ type_t *to1 = pointer_type->pointer.points_to;
+ type_t *to2 = other_type->pointer.points_to;
+
+ type_t *to;
+ if (is_type_atomic(to1, ATOMIC_TYPE_VOID) ||
+ is_type_atomic(to2, ATOMIC_TYPE_VOID)) {
+ to = type_void;
+ } else if (types_compatible(get_unqualified_type(to1),
+ get_unqualified_type(to2))) {
+ to = to1;
+ } else {
warningf(&expression->base.source_position,
- "pointer types '%T' and '%T' in conditional expression are incompatible", true_type, false_type);
+ "pointer types '%T' and '%T' in conditional expression are incompatible",
+ true_type, false_type);
+ to = type_void;
}
- result_type = true_type;
+
+ type_t *const copy = duplicate_type(to);
+ copy->base.qualifiers = to1->base.qualifiers | to2->base.qualifiers;
+
+ type_t *const type = typehash_insert(copy);
+ if (type != copy)
+ free_type(copy);
+
+ result_type = make_pointer_type(type, TYPE_QUALIFIER_NONE);
} else if(is_null_pointer_constant(other_expression)) {
result_type = pointer_type;
} else if(is_type_integer(other_type)) {
type_t *orig_pointer_type)
{
type_t *points_to = pointer_type->pointer.points_to;
+ points_to = skip_typeref(points_to);
+
if (is_type_incomplete(points_to) &&
(! (c_mode & _GNUC)
|| !is_type_atomic(points_to, ATOMIC_TYPE_VOID))) {
type_left, orig_type_left);
expression->base.type = type_left;
} else if(is_type_pointer(type_left) && is_type_pointer(type_right)) {
- if(!pointers_compatible(type_left, type_right)) {
- errorf(HERE,
- "pointers to incompatible objects to binary '-' ('%T', '%T')",
+ type_t *const unqual_left = get_unqualified_type(skip_typeref(type_left->pointer.points_to));
+ type_t *const unqual_right = get_unqualified_type(skip_typeref(type_right->pointer.points_to));
+ if (!types_compatible(unqual_left, unqual_right)) {
+ errorf(&expression->base.source_position,
+ "subtracting pointers to incompatible types '%T' and '%T'",
orig_type_left, orig_type_right);
- } else {
- expression->base.type = type_ptrdiff_t;
+ } else if (!is_type_object(unqual_left)) {
+ if (is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) {
+ warningf(&expression->base.source_position,
+ "subtracting pointers to void");
+ } else {
+ errorf(&expression->base.source_position,
+ "subtracting pointers to non-object types '%T'",
+ orig_type_left);
+ }
}
+ expression->base.type = type_ptrdiff_t;
} else if (is_type_valid(type_left) && is_type_valid(type_right)) {
- errorf(HERE, "invalid operands to binary '-' ('%T', '%T')",
+ errorf(HERE, "invalid operands of types '%T' and '%T' to binary '-'",
orig_type_left, orig_type_right);
}
}