when redeclaring stuff with different attributes merge the attributes and don't displ...
authorMatthias Braun <matze@braunis.de>
Mon, 17 Aug 2009 12:45:38 +0000 (12:45 +0000)
committerMatthias Braun <matze@braunis.de>
Mon, 17 Aug 2009 12:45:38 +0000 (12:45 +0000)
[r26373]

attribute.c
attribute_t.h
parser.c

index 3e42ff2..9385333 100644 (file)
@@ -24,6 +24,7 @@
 #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] = {
@@ -422,3 +423,52 @@ const char *get_deprecated_string(const attribute_t *attribute)
        }
        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);
+       }
+}
index 1a62aeb..652b17d 100644 (file)
@@ -143,4 +143,6 @@ struct attribute_t {
 
 const char *get_attribute_name(attribute_kind_t kind);
 
+bool attributes_equal(const attribute_t *attr1, const attribute_t *attr2);
+
 #endif
index 1686f34..dc94f49 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -4275,6 +4275,47 @@ static bool is_error_entity(entity_t *const ent)
        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
@@ -4429,8 +4470,14 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
 
                                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,