Hi,
On 23/01/2018 18:38, Jason Merrill wrote:
On 01/22/2018 05:13 PM, Paolo Carlini wrote:
Hi again,
On 22/01/2018 22:50, Paolo Carlini wrote:
Ok. The below passes the C++ testsuite and I'm finishing testing it.
Therefore, as you already hinted to, we can now say that what was
*really* missing from potential_constant_expression_1 was the use of
default_init_uninitialized_part, which does all the non-trivial work
besides the later !DECL_NONTRIVIALLY_INITIALIZED_P check.
check_for_uninitialized_const_var also provides the informs, which
were completely missing.
Grrr. Testing the library revealed immediately the failure of
18_support/byte/ops.cc, because in constexpr_context_p == true, thus
from potential_constant_expression_1, the case CP_TYPE_CONST_P
triggers. I guess we really want to keep the existing
constexpr_context_p == false cases separate. I'm therefore restarting
testing with the below.
+ && ((!constexpr_context_p
+ && (CP_TYPE_CONST_P (type) || var_in_constexpr_fn (decl)))
+ || (constexpr_context_p && !DECL_NONTRIVIALLY_INITIALIZED_P
(decl)))
&& !DECL_INITIAL (decl))
I think I'd replace the DECL_INITIAL check with
DECL_NONTRIVIALLY_INITIALIZED_P, which seems more precise. So we
ought to be ok with the simpler
&& (constexpr_context_p
|| CP_TYPE_CONST_P (type) || var_in_constexpr_fn (decl))
&& !DECL_NONTRIVIALLY_INITIALIZED_P (decl))
Oh nice, thanks Jason.
I'm therefore finishing regtesting the below, it's currently half way
through the library testsuite. Ok if it passes?
Thanks again,
Paolo.
////////////////////////
Index: cp/constexpr.c
===================================================================
--- cp/constexpr.c (revision 256991)
+++ cp/constexpr.c (working copy)
@@ -5707,13 +5707,9 @@ potential_constant_expression_1 (tree t, bool want
"%<thread_local%> in %<constexpr%> context", tmp);
return false;
}
- else if (!DECL_NONTRIVIALLY_INITIALIZED_P (tmp))
- {
- if (flags & tf_error)
- error_at (DECL_SOURCE_LOCATION (tmp), "uninitialized "
- "variable %qD in %<constexpr%> context", tmp);
- return false;
- }
+ else if (!check_for_uninitialized_const_var
+ (tmp, /*constexpr_context_p=*/true, flags))
+ return false;
}
return RECUR (tmp, want_rval);
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h (revision 256991)
+++ cp/cp-tree.h (working copy)
@@ -6221,6 +6221,7 @@ extern tree finish_case_label
(location_t, tree,
extern tree cxx_maybe_build_cleanup (tree, tsubst_flags_t);
extern bool check_array_designated_initializer (constructor_elt *,
unsigned HOST_WIDE_INT);
+extern bool check_for_uninitialized_const_var (tree, bool, tsubst_flags_t);
/* in decl2.c */
extern void record_mangling (tree, bool);
Index: cp/decl.c
===================================================================
--- cp/decl.c (revision 256991)
+++ cp/decl.c (working copy)
@@ -72,7 +72,6 @@ static int check_static_variable_definition (tree,
static void record_unknown_type (tree, const char *);
static tree builtin_function_1 (tree, tree, bool);
static int member_function_or_else (tree, tree, enum overload_flags);
-static void check_for_uninitialized_const_var (tree);
static tree local_variable_p_walkfn (tree *, int *, void *);
static const char *tag_name (enum tag_types);
static tree lookup_and_check_tag (enum tag_types, tree, tag_scope, bool);
@@ -5545,10 +5544,14 @@ maybe_commonize_var (tree decl)
}
}
-/* Issue an error message if DECL is an uninitialized const variable. */
+/* Issue an error message if DECL is an uninitialized const variable.
+ CONSTEXPR_CONTEXT_P is true when the function is called in a constexpr
+ context from potential_constant_expression. Returns true if all is well,
+ false otherwise. */
-static void
-check_for_uninitialized_const_var (tree decl)
+bool
+check_for_uninitialized_const_var (tree decl, bool constexpr_context_p,
+ tsubst_flags_t complain)
{
tree type = strip_array_types (TREE_TYPE (decl));
@@ -5557,26 +5560,38 @@ maybe_commonize_var (tree decl)
7.1.6 */
if (VAR_P (decl)
&& TREE_CODE (type) != REFERENCE_TYPE
- && (CP_TYPE_CONST_P (type) || var_in_constexpr_fn (decl))
- && !DECL_INITIAL (decl))
+ && (constexpr_context_p
+ || CP_TYPE_CONST_P (type) || var_in_constexpr_fn (decl))
+ && !DECL_NONTRIVIALLY_INITIALIZED_P (decl))
{
tree field = default_init_uninitialized_part (type);
if (!field)
- return;
+ return true;
- if (CP_TYPE_CONST_P (type))
- permerror (DECL_SOURCE_LOCATION (decl),
- "uninitialized const %qD", decl);
- else
+ if (!constexpr_context_p)
{
- if (!is_instantiation_of_constexpr (current_function_decl))
- error_at (DECL_SOURCE_LOCATION (decl),
- "uninitialized variable %qD in %<constexpr%> function",
- decl);
- cp_function_chain->invalid_constexpr = true;
+ if (CP_TYPE_CONST_P (type))
+ {
+ if (complain & tf_error)
+ permerror (DECL_SOURCE_LOCATION (decl),
+ "uninitialized const %qD", decl);
+ }
+ else
+ {
+ if (!is_instantiation_of_constexpr (current_function_decl)
+ && (complain & tf_error))
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "uninitialized variable %qD in %<constexpr%> "
+ "function", decl);
+ cp_function_chain->invalid_constexpr = true;
+ }
}
+ else if (complain & tf_error)
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "uninitialized variable %qD in %<constexpr%> context",
+ decl);
- if (CLASS_TYPE_P (type))
+ if (CLASS_TYPE_P (type) && (complain & tf_error))
{
tree defaulted_ctor;
@@ -5591,7 +5606,11 @@ maybe_commonize_var (tree decl)
"and the implicitly-defined constructor does not "
"initialize %q#D", field);
}
+
+ return false;
}
+
+ return true;
}
/* Structure holding the current initializer being processed by reshape_init.
@@ -6252,7 +6271,8 @@ check_initializer (tree decl, tree init, int flags
flags |= LOOKUP_ALREADY_DIGESTED;
}
else if (!init)
- check_for_uninitialized_const_var (decl);
+ check_for_uninitialized_const_var (decl, /*constexpr_context_p =*/false,
+ tf_warning_or_error);
/* Do not reshape constructors of vectors (they don't need to be
reshaped. */
else if (BRACE_ENCLOSED_INITIALIZER_P (init))
@@ -6379,7 +6399,8 @@ check_initializer (tree decl, tree init, int flags
diagnose_uninitialized_cst_or_ref_member (core_type,
/*using_new=*/false,
/*complain=*/true);
- check_for_uninitialized_const_var (decl);
+ check_for_uninitialized_const_var (decl, /*constexpr_context_p=*/false,
+ tf_warning_or_error);
}
if (init && init != error_mark_node)
Index: testsuite/g++.dg/cpp1y/constexpr-83921-1.C
===================================================================
--- testsuite/g++.dg/cpp1y/constexpr-83921-1.C (nonexistent)
+++ testsuite/g++.dg/cpp1y/constexpr-83921-1.C (working copy)
@@ -0,0 +1,5 @@
+// PR c++/83921
+// { dg-do compile { target c++14 } }
+
+struct Foo { };
+constexpr void test() { Foo f; }
Index: testsuite/g++.dg/cpp1y/constexpr-83921-2.C
===================================================================
--- testsuite/g++.dg/cpp1y/constexpr-83921-2.C (nonexistent)
+++ testsuite/g++.dg/cpp1y/constexpr-83921-2.C (working copy)
@@ -0,0 +1,5 @@
+// PR c++/83921
+// { dg-do compile { target c++14 } }
+
+struct Foo { Foo() = default; };
+constexpr void test() { Foo f; }
Index: testsuite/g++.dg/cpp1y/constexpr-83921-3.C
===================================================================
--- testsuite/g++.dg/cpp1y/constexpr-83921-3.C (nonexistent)
+++ testsuite/g++.dg/cpp1y/constexpr-83921-3.C (working copy)
@@ -0,0 +1,5 @@
+// PR c++/83921
+// { dg-do compile { target c++14 } }
+
+struct Foo { int m; };
+constexpr void test() { Foo f; } // { dg-error "uninitialized" }
Index: testsuite/g++.dg/ext/stmtexpr20.C
===================================================================
--- testsuite/g++.dg/ext/stmtexpr20.C (nonexistent)
+++ testsuite/g++.dg/ext/stmtexpr20.C (working copy)
@@ -0,0 +1,13 @@
+// PR c++/83921
+// { dg-options "" }
+// { dg-do compile { target c++11 } }
+
+struct test { const int *addr; };
+
+const test* setup()
+{
+ static constexpr test atest =
+ { ({ int inner = 1; (const int*)(0); }) };
+
+ return &atest;
+}
Index: testsuite/g++.dg/ext/stmtexpr21.C
===================================================================
--- testsuite/g++.dg/ext/stmtexpr21.C (nonexistent)
+++ testsuite/g++.dg/ext/stmtexpr21.C (working copy)
@@ -0,0 +1,13 @@
+// PR c++/83921
+// { dg-options "" }
+// { dg-do compile { target c++11 } }
+
+struct test { const int *addr; };
+
+const test* setup()
+{
+ static constexpr test atest =
+ { ({ int inner; (const int*)(0); }) }; // { dg-error "uninitialized" }
+
+ return &atest;
+}