Bug 90951

Summary: [8/9 Regression] error initializing a constexpr array of a struct with const member
Product: gcc Reporter: Martin Sebor <msebor>
Component: c++Assignee: Jason Merrill <jason>
Status: RESOLVED FIXED    
Severity: normal CC: jason, webrown.cpp
Priority: P2 Keywords: rejects-valid
Version: 9.0   
Target Milestone: 8.4   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90938
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90947
Host: Target:
Build: Known to work: 4.8.5
Known to fail: 10.0, 4.9.1, 5.5.0, 6.4.0, 7.4.0, 8.3.0, 9.1.0 Last reconfirmed: 2020-01-28 00:00:00

Description Martin Sebor 2019-06-20 20:12:13 UTC
Here's another bug caused by my r270155.  The valid code is accepted by Clang and GCC 8 but rejected by GCC 9.1.0 and 10.0.

$ cat t.C && gcc -S -Wall t.C
struct S { const char a[2]; };

constexpr struct S a[1] = { { "" } };

static_assert ('\0' == *a[0].a, "!");
t.C:5:30: error: use of deleted function ‘S::S()’
    5 | static_assert ('\0' == *a[0].a, "!");
      |                              ^
t.C:1:8: note: ‘S::S()’ is implicitly deleted because the default definition would be ill-formed:
    1 | struct S { const char a[2]; };
      |        ^
t.C:1:8: error: uninitialized const member in ‘struct S’
t.C:1:23: note: ‘const char S::a [2]’ should be initialized
    1 | struct S { const char a[2]; };
      |                       ^
t.C:5:37: error: use of deleted function ‘S::S()’
    5 | static_assert ('\0' == *a[0].a, "!");
      |                                     ^
t.C:5:21: error: non-constant condition for static assertion
    5 | static_assert ('\0' == *a[0].a, "!");
      |                ~~~~~^~~~~~~~~~
t.C:5:21: error: use of deleted function ‘S::S()’
Comment 1 Martin Sebor 2019-06-20 20:46:15 UTC
Actually, I don't think this is related to r270155.  When the test case is modified as shown below it fails to compile even prior to the change and all the way to GCC 4.9.  It is accepted by GCC 4.8.  It needs -std=c++11:


#define assert(expr) static_assert (expr, #expr)

struct S { const char a[2]; };

constexpr struct S a[1][1][1] = { };

assert ('\0' == *a[0][0][0].a);

t.C:7:29: error: use of deleted function ‘S::S()’
    7 | assert ('\0' == *a[0][0][0].a);
      |                             ^
t.C:1:37: note: in definition of macro ‘assert’
    1 | #define assert(expr) static_assert (expr, #expr)
      |                                     ^~~~
t.C:3:10: note: ‘S::S()’ is implicitly deleted because the default definition would be ill-formed:
    3 |   struct S { const char a[2]; };
      |          ^
t.C:3:10: error: uninitialized const member in ‘struct S’
t.C:3:25: note: ‘const char S::a [2]’ should be initialized
    3 |   struct S { const char a[2]; };
      |                         ^
t.C:7:31: error: use of deleted function ‘S::S()’
    7 | assert ('\0' == *a[0][0][0].a);
      |                               ^
t.C:7:14: error: non-constant condition for static assertion
    7 | assert ('\0' == *a[0][0][0].a);
      |         ~~~~~^~~~~~~~~~~~~~~~
t.C:1:37: note: in definition of macro ‘assert’
    1 | #define assert(expr) static_assert (expr, #expr)
      |                                     ^~~~
t.C:7:14: error: use of deleted function ‘S::S()’
    7 | assert ('\0' == *a[0][0][0].a);
      |         ~~~~~^~~~~~~~~~~~~~~~
t.C:1:37: note: in definition of macro ‘assert’
    1 | #define assert(expr) static_assert (expr, #expr)
      |                                     ^~~~
Comment 2 Martin Sebor 2019-06-20 20:49:33 UTC
The compilation error was introduced in r209934 (gcc 5.0.0) via:

	PR c++/60980
	* init.c (build_value_init): Don't try to call an array constructor.

Prior to that GCC fails with an ICE on this test case.  The ICE was in turn introduced in r203985 (gcc 4.9.0):

	In C++11 a trivial [cd]tor might not be callable.
	* class.c (user_provided_p): A function deleted on its declation
	in the class is not user-provided.
	(type_build_ctor_call): Also force a ctor call if we
	might have a deleted or private trivial ctor.
	(type_build_dtor_call): New.
	(deduce_noexcept_on_destructors): Remove obsolete code.
	* cp-tree.h: Declare type_build_dtor_call.
	* decl.c (expand_static_init): Make sure trivial dtors are callable.
	(cxx_maybe_build_cleanup): Likewise.
	* except.c (build_throw): Likewise.
	* init.c (build_value_init): Handle trivial but not callable ctors.
	(perform_target_ctor): Make sure trivial dtor is callable.
	(perform_member_init): Likewise.
	(expand_cleanup_for_base): Likewise.
	(build_vec_delete_1): Likewise.
	(build_delete): Likewise.
	(push_base_cleanups): Likewise.
	(build_new_1): Avoid redundant error.
	* method.c (synthesized_method_walk): Can't ever exit early in C++11.
	Always process the subobject destructor.
	* semantics.c (finish_compound_literal): Make sure trivial dtor is
	callable.
	* typeck2.c (split_nonconstant_init): Likewise.

Before this change the test case was accepted.
Comment 3 GCC Commits 2020-02-04 22:27:39 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:0712ea6313bc44f9ae8feb235c1b02c92cdd0527

commit r10-6437-g0712ea6313bc44f9ae8feb235c1b02c92cdd0527
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Feb 4 15:54:17 2020 -0500

    c++: Fix constexpr vs. omitted aggregate init.
    
    Value-initialization is importantly different from {}-initialization for
    this testcase, where the former calls the deleted S constructor and the
    latter initializes S happily.
    
    	PR c++/90951
    	* constexpr.c (cxx_eval_array_reference): {}-initialize missing
    	elements instead of value-initializing them.
Comment 4 Jason Merrill 2020-02-05 21:00:32 UTC
Fixed for GCC 10 so far.
Comment 5 GCC Commits 2020-02-24 21:25:30 UTC
The releases/gcc-8 branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:300d219af336436fbb58043db193f54d2a1b4b49

commit r8-10054-g300d219af336436fbb58043db193f54d2a1b4b49
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Feb 24 16:22:45 2020 -0500

    c++: Fix constexpr vs. omitted aggregate init.
    
    Value-initialization is importantly different from {}-initialization for
    this testcase, where the former calls the deleted S constructor and the
    latter initializes S happily.
    
    gcc/cp/ChangeLog
    2020-02-24  Jason Merrill  <jason@redhat.com>
    
    	PR c++/90951
    	* constexpr.c (cxx_eval_array_reference): {}-initialize missing
    	elements instead of value-initializing them.
Comment 6 GCC Commits 2020-02-26 19:25:59 UTC
The releases/gcc-9 branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:c51ac41714469104ee6120db3eedfb0964290502

commit r9-8292-gc51ac41714469104ee6120db3eedfb0964290502
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Feb 26 13:03:23 2020 -0500

    c++: Fix constexpr vs. omitted aggregate init.
    
    Value-initialization is importantly different from {}-initialization for
    this testcase, where the former calls the deleted S constructor and the
    latter initializes S happily.
    
    gcc/cp/ChangeLog
    2020-02-26  Jason Merrill  <jason@redhat.com>
    
    	PR c++/90951
    	* constexpr.c (cxx_eval_array_reference): {}-initialize missing
    	elements instead of value-initializing them.
Comment 7 Jason Merrill 2020-02-26 21:22:31 UTC
And 8.4 and 9.3.