return true;
return false;
}
-\f
+
+/* If NTYPE is a type of a non-variadic function with a prototype
+ and OTYPE is a type of a function without a prototype and ATTRS
+ contains attribute format, diagnosess and removes it from ATTRS.
+ Returns the result of build_type_attribute_variant of NTYPE and
+ the (possibly) modified ATTRS. */
+
+static tree
+build_functype_attribute_variant (tree ntype, tree otype, tree attrs)
+{
+ if (!prototype_p (otype)
+ && prototype_p (ntype)
+ && lookup_attribute ("format", attrs))
+ {
+ warning_at (input_location, OPT_Wattributes,
+ "%qs attribute cannot be applied to a function that "
+ "does not take variable arguments", "format");
+ attrs = remove_attribute ("format", attrs);
+ }
+ return build_type_attribute_variant (ntype, attrs);
+
+}
/* Return the composite type of two compatible types.
We assume that comptypes has already been done and returned
/* Save space: see if the result is identical to one of the args. */
if (valtype == TREE_TYPE (t1) && !TYPE_ARG_TYPES (t2))
- return build_type_attribute_variant (t1, attributes);
+ return build_functype_attribute_variant (t1, t2, attributes);
if (valtype == TREE_TYPE (t2) && !TYPE_ARG_TYPES (t1))
- return build_type_attribute_variant (t2, attributes);
+ return build_functype_attribute_variant (t2, t1, attributes);
/* Simple way if one arg fails to specify argument types. */
if (TYPE_ARG_TYPES (t1) == NULL_TREE)
--- /dev/null
+/* PR c/93812 - ICE on redeclaration of an attribute format function without
+ protoype
+ It's not clear that attribute format should be accepted on functions
+ without a prototype. If it's decided that it shouldn't be the tests
+ here will need to be adjusted.
+ { dg-do compile }
+ { dg-options "-Wall" } */
+
+#define FMT(n1, n2) __attribute__((__format__(__printf__, n1, n2)))
+
+// Exercise function declarations.
+FMT (1, 2) void print1 ();
+
+FMT (2, 3) void print2 ();
+ void print2 ();
+
+FMT (3, 4) void print3 ();
+FMT (3, 4) void print3 ();
+
+FMT (1, 2) void print4 ();
+ void print4 (void); // { dg-warning "'format' attribute cannot be applied to a function that does not take variable arguments" }
+
+ void print5 ();
+FMT (1, 2) void print5 (void); // { dg-warning "\\\[-Wattributes" }
+
+FMT (1, 2) void print6 ();
+ void print6 (const char*, ...); // { dg-error "conflicting types" }
+
+ void print7 (const char*, ...);
+FMT (1, 2) void print7 (); // { dg-error "conflicting types" }
+
+
+// Exercise function calls.
+void test_print (void)
+{
+ print1 ("%i %s", 123, "");
+ print1 ("%s %i", 123, 123); // { dg-warning "\\\[-Wformat" }
+
+ print2 (0, "%s %i", "", 123);
+ print2 (1, "%i %s", "", 123); // { dg-warning "\\\[-Wformat" }
+
+ print3 (0, 1, "%s %i", "", 123);
+ print3 (1, 2, "%i %s", "", 123); // { dg-warning "\\\[-Wformat" }
+
+ // Just verify there's no ICE.
+ print4 ();
+ print5 ();
+ print6 ("%i %s", 123, "");
+}
+
+
+// Exercise declarations of pointers to functions.
+FMT (1, 2) void (*pfprint1)();
+
+FMT (2, 3) void (*pfprint2)();
+ void (*pfprint2)();
+
+FMT (3, 4) void (*pfprint3)();
+FMT (3, 4) void (*pfprint3)();
+
+FMT (1, 2) void (*pfprint4)();
+ void (*pfprint4)(void); // { dg-warning "'format' attribute cannot be applied to a function that does not take variable arguments" }
+
+ void (*pfprint5)();
+FMT (1, 2) void (*pfprint5)(void); // { dg-warning "\\\[-Wattributes" }
+
+FMT (1, 2) void (*pfprint6)();
+ void (*pfprint6)(const char*, ...); // { dg-error "conflicting types" }
+
+ void (*pfprint7)(const char*, ...);
+FMT (1, 2) void (*pfprint7)(); // { dg-error "conflicting types" }
+
+// Exercise calls via function pointers.
+void test_pfprint (void)
+{
+ pfprint1 ("%i %s", 123, "");
+ pfprint1 ("%s %i", 123, 123); // { dg-warning "\\\[-Wformat" }
+
+ pfprint2 (0, "%s %i", "", 123);
+ pfprint2 (1, "%i %s", "", 123); // { dg-warning "\\\[-Wformat" }
+
+ pfprint3 (0, 1, "%s %i", "", 123);
+ pfprint3 (1, 2, "%i %s", "", 123); // { dg-warning "\\\[-Wformat" }
+
+ // Just verify there's no ICE.
+ pfprint4 ();
+ pfprint5 ();
+ pfprint6 ("%i %s", 123, "");
+}