aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2016-05-20 22:23:10 +0000
committerMartin Sebor <msebor@redhat.com>2016-05-20 22:23:10 +0000
commit0e87193b73a77a32ac49efecd517a5f516fbfc99 (patch)
treeac73cfdeb4c5483ac27c5fdb146e58e30f7020d0
parent0a64c66e1eeafa31eed8d533fe4c1dcfaa09ac77 (diff)
PR c/71115 - [4.9/5/6/7 Regression] Missing warning: excess elements
in struct initializer gcc/c/ChangeLog: 2016-05-20 Martin Sebor <msebor@redhat.com> PR c/71115 * c-typeck.c (error_init): Use expansion_point_location_if_in_system_header. (warning_init): Same. gcc/testsuite/ChangeLog: 2016-05-20 Martin Sebor <msebor@redhat.com> PR c/71115 * gcc.dg/init-excess-2.c: New test. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@236549 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/c/ChangeLog7
-rw-r--r--gcc/c/c-typeck.c20
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-sfinae.C287
-rw-r--r--gcc/testsuite/gcc.dg/Woverride-init-1.c10
-rw-r--r--gcc/testsuite/gcc.dg/Woverride-init-2.c10
-rw-r--r--gcc/testsuite/gcc.dg/init-excess-2.c47
7 files changed, 371 insertions, 15 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 5731048b087..c65f2e9e5e0 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,10 @@
+2016-05-20 Martin Sebor <msebor@redhat.com>
+
+ PR c/71115
+ * c-typeck.c (error_init): Use
+ expansion_point_location_if_in_system_header.
+ (warning_init): Same.
+
2016-05-19 David Malcolm <dmalcolm@redhat.com>
PR c/71171
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 30102404284..7c9b078ed1b 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -5879,16 +5879,21 @@ error_init (location_t loc, const char *gmsgid)
component name is taken from the spelling stack. */
static void
-pedwarn_init (location_t location, int opt, const char *gmsgid)
+pedwarn_init (location_t loc, int opt, const char *gmsgid)
{
char *ofwhat;
bool warned;
+ /* Use the location where a macro was expanded rather than where
+ it was defined to make sure macros defined in system headers
+ but used incorrectly elsewhere are diagnosed. */
+ source_location exploc = expansion_point_location_if_in_system_header (loc);
+
/* The gmsgid may be a format string with %< and %>. */
- warned = pedwarn (location, opt, gmsgid);
+ warned = pedwarn (exploc, opt, gmsgid);
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat && warned)
- inform (location, "(near initialization for %qs)", ofwhat);
+ inform (exploc, "(near initialization for %qs)", ofwhat);
}
/* Issue a warning for a bad initializer component.
@@ -5903,11 +5908,16 @@ warning_init (location_t loc, int opt, const char *gmsgid)
char *ofwhat;
bool warned;
+ /* Use the location where a macro was expanded rather than where
+ it was defined to make sure macros defined in system headers
+ but used incorrectly elsewhere are diagnosed. */
+ source_location exploc = expansion_point_location_if_in_system_header (loc);
+
/* The gmsgid may be a format string with %< and %>. */
- warned = warning_at (loc, opt, gmsgid);
+ warned = warning_at (exploc, opt, gmsgid);
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
if (*ofwhat && warned)
- inform (loc, "(near initialization for %qs)", ofwhat);
+ inform (exploc, "(near initialization for %qs)", ofwhat);
}
/* If TYPE is an array type and EXPR is a parenthesized string
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1a6a460f621..70354d4e4be 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2016-05-20 Martin Sebor <msebor@redhat.com>
+
+ PR c/71115
+ * gcc.dg/init-excess-2.c: New test.
+
2016-05-20 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/opt53.adb: New test.
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-sfinae.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-sfinae.C
new file mode 100644
index 00000000000..a83d7f4e1de
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-sfinae.C
@@ -0,0 +1,287 @@
+// Test exercising SFINAE depending on the well-definedness of constexpr
+// functions.
+// { dg-do compile { target c++14 } }
+
+#define Assert(e) static_assert ((e), #e)
+
+// Exercise SFINAE based on the absence of integer division by zero.
+namespace DivByZero {
+
+// Define a pair of functions that have undefined and well-defined
+// behavior, respectively, due to division by zero, depending on
+// their arguments.
+
+// The following function is undefined when I is zero, well defined
+// otherwise.
+constexpr bool div_zero_0 (int i, int j) { return 1 + j / (i == 0); }
+
+// The following function is undefined when I is non-zero, and well
+// defined otherwise.
+constexpr bool div_zero_1 (int i, int j) { return 1 + j / (i != 0); }
+
+// Define a pair of overfloads each of which is viable when the constexpr
+// function it invokes has well-defined semantics and not otherwise.
+template <int I>
+constexpr int f (int (*)[div_zero_0 (I, 0)] = 0) { return 0; }
+
+template <int I>
+constexpr int f (int (*)[div_zero_1 (I, 0)] = 0) { return 1; }
+
+// Verify that the correct overload is selected based on the template
+// argument and without triggering a compilation error for the undefined
+// behavior in the non-viable constexpr function above.
+Assert (f<0>() == 0);
+Assert (f<1>() == 1);
+
+}
+
+// Exercise SFINAE based on the absence of signed integer overflow
+// in addition.
+namespace IntAddOverflow {
+
+constexpr int a [] = { 1234, __INT_MAX__ / 2 };
+
+constexpr int vflow_0 (int i) { return a [!i] * 7; }
+constexpr int vflow_1 (int i) { return a [i] * 11; }
+
+template <int I>
+constexpr int f (int (*)[vflow_0 (I)] = 0) { return 1; }
+
+template <int I>
+constexpr int f (int (*)[vflow_1 (I)] = 0) { return 0; }
+
+constexpr int n0 = f<0>();
+constexpr int n1 = f<1>();
+
+Assert (n0 == 0);
+Assert (n1 == 1);
+
+}
+
+// Exercise SFINAE based on the absence of signed integer overflow
+// in multiplication.
+namespace IntMulOverflow {
+
+constexpr long a [] = { 1234, __LONG_MAX__ / 2 };
+
+constexpr long vflow_0 (int i) { return a [!i] * 3; }
+constexpr long vflow_1 (int i) { return a [i] * 7; }
+
+template <int I>
+constexpr int f (int (*)[vflow_0 (I)] = 0) { return 1; }
+
+template <int I>
+constexpr int f (int (*)[vflow_1 (I)] = 0) { return 0; }
+
+constexpr int n0 = f<0>();
+constexpr int n1 = f<1>();
+
+Assert (n0 == 0);
+Assert (n1 == 1);
+
+}
+
+// Exercise SFINAE based on the absence of undefined pointer arithmetic
+// involving null pointers. Subtracting one null pointer from another
+// is well-defined, but subtracting a null pointer from a non-null one
+// is not.
+namespace NullPointerArithmetic {
+
+constexpr int i = 0;
+constexpr const int* a[] = { 0, &i };
+
+// Well-defined core constant expressoons involving null pointers.
+constexpr __PTRDIFF_TYPE__ d00 = a [0] - a [0];
+constexpr __PTRDIFF_TYPE__ d11 = a [1] - a [1];
+
+// Undefined core constant expressoons involving null pointers.
+// constexpr __PTRDIFF_TYPE__ d01 = a [0] - a [1];
+// constexpr __PTRDIFF_TYPE__ d10 = a [1] - a [0];
+
+constexpr bool nullptr_sub_0 (int i, int j) { return 1 + a [i != 0] - a [j]; }
+
+constexpr bool nullptr_sub_1 (int i, int j) { return 1 + a [i == 0] - a [j]; }
+
+template <int I>
+constexpr int f (int (*)[nullptr_sub_0 (I, 0)] = 0) { return 0; }
+
+template <int I>
+constexpr int f (int (*)[nullptr_sub_1 (I, 0)] = 0) { return 1; }
+
+constexpr int n0 = f<0>();
+constexpr int n1 = f<1>();
+
+Assert (n0 == 0);
+Assert (n1 == 1);
+
+}
+
+// Exercise SFINAE based on the absence of undefined pointer arithmetic
+// involving null poiinters. Subtracting one null pointer from another
+// is well-defined, but subtracting a null pointer from a non-null one
+// is not.
+namespace NullPointerDereference {
+
+struct S { int a, b; };
+
+constexpr S s = { };
+constexpr const S* a[] = { 0, &s };
+
+constexpr bool nullptr_ref_0 (int i) { return &a [i != 0]->b == &s.b; }
+constexpr bool nullptr_ref_1 (int i) { return &a [i == 0]->b == &s.b; }
+
+template <int I>
+constexpr int f (int (*)[nullptr_ref_0 (I)] = 0) { return 1; }
+
+template <int I>
+constexpr int f (int (*)[nullptr_ref_1 (I)] = 0) { return 0; }
+
+constexpr int n0 = f<0>();
+constexpr int n1 = f<1>();
+
+Assert (n0 == 0);
+Assert (n1 == 1);
+
+}
+
+// Exercise SFINAE based on whether or not two constexpr function
+// calls have a circular depency on one another such that a call
+// to one would not terminate.
+namespace CircularDependency {
+
+constexpr bool call_me (int i, bool (*f)(int)) { return f (i); }
+
+constexpr bool undefined_if_0 (int i) {
+ return i ? 1 : call_me (i, undefined_if_0);
+}
+
+constexpr bool undefined_if_1 (int i) {
+ return i ? call_me (i, undefined_if_1) : 1;
+}
+
+template <int I>
+constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }
+
+constexpr int n0 = f<0>();
+constexpr int n1 = f<1>();
+
+Assert (n0 == 1);
+Assert (n1 == 0);
+
+}
+
+// Exercise SFINAE based on whether constexpr functions flow off
+// the end without returning a value.
+namespace FlowOffTheEnd {
+
+constexpr bool undefined_if_0 (int i) { switch (i) case 1: return 1; }
+constexpr bool undefined_if_1 (int i) { switch (i) case 0: return 1; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 1; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 0; }
+
+constexpr int n0 = f<0>();
+constexpr int n1 = f<1>();
+
+Assert (n0 == 0);
+Assert (n1 == 1);
+
+}
+
+// Exercise SFINAE based on the presence and absence of a left shift
+// expression with a negative second operand.
+namespace NegativeLeftShift {
+
+constexpr int a [] = { -1, 1 };
+
+constexpr int undefined_if_0 (int i) { return 1 << a [i]; }
+constexpr int undefined_if_1 (int i) { return 1 << a [!i]; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }
+
+constexpr int n0 = f<0>();
+constexpr int n1 = f<1>();
+
+Assert (n0 == 1);
+Assert (n1 == 0);
+
+}
+
+// Exercise SFINAE based on the presence and absence of a right shift
+// expression with a negative second operand.
+namespace NegativeRightShift {
+
+constexpr int a [] = { -1, 1 };
+
+constexpr int undefined_if_0 (int i) { return 2 >> a [i]; }
+constexpr int undefined_if_1 (int i) { return 2 >> a [!i]; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }
+
+constexpr int n0 = f<0>();
+constexpr int n1 = f<1>();
+
+Assert (n0 == 1);
+Assert (n1 == 0);
+
+}
+
+// Exercise SFINAE based on the absence of signed integer overflow
+// in a signed left shift expression.
+namespace LeftShiftOverflow {
+
+constexpr int a[] = { 1234, 1 };
+
+constexpr int undefined_if_0 (int i) { return 1 << a [i]; }
+constexpr int undefined_if_1 (int i) { return 1 << a [!i]; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }
+
+constexpr int n0 = f<0>();
+constexpr int n1 = f<1>();
+
+Assert (n0 == 1);
+Assert (n1 == 0);
+
+}
+
+// Exercise SFINAE based on the absence of using a negative array
+// index.
+namespace NegativeArrayIndex {
+
+constexpr int a [] = { -1, 1 };
+
+constexpr int undefined_if_0 (int i) { return 2 + a [a [i]]; }
+constexpr int undefined_if_1 (int i) { return 2 + a [a [!i]]; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }
+
+template <int I>
+constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }
+
+constexpr int n0 = f<0>();
+constexpr int n1 = f<1>();
+
+Assert (n0 == 1);
+Assert (n1 == 0);
+
+}
diff --git a/gcc/testsuite/gcc.dg/Woverride-init-1.c b/gcc/testsuite/gcc.dg/Woverride-init-1.c
index 29eca3095cd..b01d8a29dcc 100644
--- a/gcc/testsuite/gcc.dg/Woverride-init-1.c
+++ b/gcc/testsuite/gcc.dg/Woverride-init-1.c
@@ -10,19 +10,19 @@ union u { char a; long long b; };
struct s s0 = {
.a = 1,
.b = 2,
- .a = 3, /* { dg-warning "initialized field overwritten|near init" } */
- 4, /* { dg-warning "initialized field overwritten|near init" } */
+ .a = 3, /* { dg-warning "initialized field overwritten" } */
+ 4, /* { dg-warning "initialized field overwritten" } */
5
};
union u u0 = {
.a = 1,
- .b = 2, /* { dg-warning "initialized field overwritten|near init" } */
- .a = 3 }; /* { dg-warning "initialized field overwritten|near init" } */
+ .b = 2, /* { dg-warning "initialized field overwritten" } */
+ .a = 3 }; /* { dg-warning "initialized field overwritten" } */
int a[5] = {
[0] = 1,
[1] = 2,
- [0] = 3, /* { dg-warning "initialized field overwritten|near init" } */
+ [0] = 3, /* { dg-warning "initialized field overwritten" } */
[2] = 4
};
diff --git a/gcc/testsuite/gcc.dg/Woverride-init-2.c b/gcc/testsuite/gcc.dg/Woverride-init-2.c
index c5490b5ad35..d0ece89eb6d 100644
--- a/gcc/testsuite/gcc.dg/Woverride-init-2.c
+++ b/gcc/testsuite/gcc.dg/Woverride-init-2.c
@@ -10,19 +10,19 @@ union u { char a; long long b; };
struct s s0 = {
.a = 1,
.b = 2,
- .a = 3, /* { dg-warning "initialized field overwritten|near init" } */
- 4, /* { dg-warning "initialized field overwritten|near init" } */
+ .a = 3, /* { dg-warning "initialized field overwritten" } */
+ 4, /* { dg-warning "initialized field overwritten" } */
5
};
union u u0 = {
.a = 1,
- .b = 2, /* { dg-warning "initialized field overwritten|near init" } */
- .a = 3 }; /* { dg-warning "initialized field overwritten|near init" } */
+ .b = 2, /* { dg-warning "initialized field overwritten" } */
+ .a = 3 }; /* { dg-warning "initialized field overwritten" } */
int a[5] = {
[0] = 1,
[1] = 2,
- [0] = 3, /* { dg-warning "initialized field overwritten|near init" } */
+ [0] = 3, /* { dg-warning "initialized field overwritten" } */
[2] = 4
};
diff --git a/gcc/testsuite/gcc.dg/init-excess-2.c b/gcc/testsuite/gcc.dg/init-excess-2.c
new file mode 100644
index 00000000000..1bf0a96a880
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/init-excess-2.c
@@ -0,0 +1,47 @@
+/* Test for diagnostics about excess initializers when using a macro
+ defined in a system header:
+ c/71115 - Missing warning: excess elements in struct initializer. */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#include <stddef.h>
+
+int* a[1] = {
+ 0,
+ NULL /* { dg-warning "excess elements|near init" } */
+};
+
+const char str[1] = {
+ 0,
+ NULL /* { dg-warning "excess elements|near init" } */
+};
+
+struct S {
+ int *a;
+} s = {
+ 0,
+ NULL /* { dg-warning "excess elements|near init" } */
+};
+
+struct __attribute__ ((designated_init)) S2 {
+ int *a;
+} s2 = {
+ NULL /* { dg-warning "positional initialization|near init" } */
+};
+
+union U {
+ int *a;
+} u = {
+ 0,
+ NULL /* { dg-warning "excess elements|near init" } */
+};
+
+int __attribute__ ((vector_size (16))) ivec = {
+ 0, 0, 0, 0,
+ NULL /* { dg-warning "excess elements|near init" } */
+};
+
+int* scal = {
+ 0,
+ NULL /* { dg-warning "excess elements|near init" } */
+};