#include "warning.h"
#include "attribute_t.h"
#include "symbol_t.h"
+#include "adt/error.h"
#include "type_t.h"
static const char *const attribute_names[ATTRIBUTE_LAST+1] = {
}
return NULL;
}
+
+static bool property_attribute_equal(const attribute_property_argument_t *prop1,
+ const attribute_property_argument_t *prop2)
+{
+ return prop1->put_symbol == prop2->put_symbol
+ && prop1->get_symbol == prop2->get_symbol;
+}
+
+static bool attribute_argument_equal(const attribute_argument_t *arg1,
+ const attribute_argument_t *arg2)
+{
+ if (arg1->kind != arg2->kind)
+ return false;
+
+ switch (arg1->kind) {
+ case ATTRIBUTE_ARGUMENT_SYMBOL:
+ return arg1->v.symbol == arg2->v.symbol;
+ case ATTRIBUTE_ARGUMENT_EXPRESSION:
+ /* TODO */
+ return false;
+ }
+ panic("Unknown argument type found");
+}
+
+static bool attribute_arguments_equal(const attribute_argument_t *args1,
+ const attribute_argument_t *args2)
+{
+ for ( ; args1 != NULL && args2 != NULL;
+ args1 = args1->next, args2 = args2->next) {
+ if (!attribute_argument_equal(args1, args2))
+ return false;
+ }
+ /* both should be NULL now */
+ return args1 == args2;
+}
+
+bool attributes_equal(const attribute_t *attr1, const attribute_t *attr2)
+{
+ if (attr1->kind != attr2->kind)
+ return false;
+
+ switch (attr1->kind) {
+ case ATTRIBUTE_MS_PROPERTY:
+ return property_attribute_equal(attr1->a.property, attr2->a.property);
+ default:
+ return attribute_arguments_equal(attr1->a.arguments,
+ attr2->a.arguments);
+ }
+}
return false;
}
+static bool contains_attribute(const attribute_t *list, const attribute_t *attr)
+{
+ for (const attribute_t *tattr = list; tattr != NULL; tattr = tattr->next) {
+ if (attributes_equal(tattr, attr))
+ return true;
+ }
+ return false;
+}
+
+/**
+ * test wether new_list contains any attributes not included in old_list
+ */
+static bool has_new_attributes(const attribute_t *old_list,
+ const attribute_t *new_list)
+{
+ for (const attribute_t *attr = new_list; attr != NULL; attr = attr->next) {
+ if (!contains_attribute(old_list, attr))
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Merge in attributes from an attribute list (probably from a previous
+ * declaration with the same name). Warning: destroys the old structure
+ * of the attribute list - don't reuse attributes after this call.
+ */
+static void merge_in_attributes(declaration_t *decl, attribute_t *attributes)
+{
+ attribute_t *next;
+ for (attribute_t *attr = attributes; attr != NULL; attr = next) {
+ next = attr->next;
+ if (contains_attribute(decl->attributes, attr))
+ continue;
+
+ /* move attribute to new declarations attributes list */
+ attr->next = decl->attributes;
+ decl->attributes = attr;
+ }
+}
+
/**
* record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
* for various problems that occur for multiple definitions
if (old_storage_class == STORAGE_CLASS_EXTERN &&
new_storage_class == STORAGE_CLASS_EXTERN) {
-warn_redundant_declaration:
- if (!is_definition &&
+
+warn_redundant_declaration: ;
+ bool has_new_attrs
+ = has_new_attributes(prev_decl->attributes,
+ decl->attributes);
+ if (has_new_attrs) {
+ merge_in_attributes(decl, prev_decl->attributes);
+ } else if (!is_definition &&
warning.redundant_decls &&
is_type_valid(prev_type) &&
strcmp(previous_entity->base.source_position.input_name,