Re: C++ PATCH for c++/48948 (rejecting constexpr friend that takes the current class)

2011-05-18 Thread Jason Merrill

On 05/11/2011 05:27 PM, Jason Merrill wrote:

We want to allow a constexpr friend function that takes the current
class, so we need to defer checking the literality of parameter types
until any classes involved are complete.


It was pointed out to me that the restriction already only applies to 
function definitions, not declarations, which dramatically simplifies 
the code.  This patch reverts most of the previous one, and only checks 
return/parameter types at the point of definition.


Tested x86_64-pc-linux-gnu, applying to trunk.
commit f2a2c7b6af06123b5f81bd474b60bddfe9b58550
Author: Jason Merrill ja...@redhat.com
Date:   Mon May 16 17:21:17 2011 -0400

	PR c++/48948
	PR c++/49015
	* class.c (finalize_literal_type_property): Do check
	for constexpr member functions of non-literal class.
	(finish_struct): Don't call check_deferred_constexpr_decls.
	* cp-tree.h: Don't declare it.
	(DECL_DEFERRED_CONSTEXPR_CHECK): Remove.
	* decl.c (grok_special_member_properties): Don't check it
	(grokfnedcl): Don't call validate_constexpr_fundecl.
	(start_preparsed_function): Do call it.
	* pt.c (tsubst_decl): Don't call it.
	(instantiate_class_template_1): Don't call
	check_deferred_constexpr_decls.
	* semantics.c (literal_type_p): Check for any incompleteness.
	(ensure_literal_type_for_constexpr_object): Likewise.
	(is_valid_constexpr_fn): Revert deferral changes.
	(validate_constexpr_fundecl): Likewise.
	(register_constexpr_fundef): Likewise.
	(check_deferred_constexpr_decls): Remove.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index dc2c509..4e52b18 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4582,6 +4582,8 @@ type_requires_array_cookie (tree type)
 static void
 finalize_literal_type_property (tree t)
 {
+  tree fn;
+
   if (cxx_dialect  cxx0x
   || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
   /* FIXME These constraints seem unnecessary; remove from standard.
@@ -4591,6 +4593,18 @@ finalize_literal_type_property (tree t)
   else if (CLASSTYPE_LITERAL_P (t)  !TYPE_HAS_TRIVIAL_DFLT (t)
 	!TYPE_HAS_CONSTEXPR_CTOR (t))
 CLASSTYPE_LITERAL_P (t) = false;
+
+  if (!CLASSTYPE_LITERAL_P (t))
+for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
+  if (DECL_DECLARED_CONSTEXPR_P (fn)
+	   TREE_CODE (fn) != TEMPLATE_DECL
+	   DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
+	   !DECL_CONSTRUCTOR_P (fn))
+	{
+	  DECL_DECLARED_CONSTEXPR_P (fn) = false;
+	  if (!DECL_TEMPLATE_INFO (fn))
+	error (enclosing class of %q+#D is not a literal type, fn);
+	}
 }
 
 /* Check the validity of the bases and members declared in T.  Add any
@@ -5831,8 +5845,6 @@ finish_struct (tree t, tree attributes)
   else
 error (trying to finish struct, but kicked out due to previous parse errors);
 
-  check_deferred_constexpr_decls ();
-
   if (processing_template_decl  at_function_scope_p ())
 add_stmt (build_min (TAG_DEFN, t));
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c0b5290..dfb2b66 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -93,7 +93,6 @@ c-common.h, not after.
   TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE)
   LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR)
   TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
-  DECL_DEFERRED_CONSTEXPR_CHECK (in FUNCTION_DECL)
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
   ICS_BAD_FLAG (in _CONV)
   FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -2345,11 +2344,6 @@ struct GTY((variable_size)) lang_decl {
 #define DECL_DECLARED_CONSTEXPR_P(DECL) \
   DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
 
-/* True if we can't tell yet whether the argument/return types of DECL
-   are literal because one is still being defined.  */
-#define DECL_DEFERRED_CONSTEXPR_CHECK(DECL) \
-  TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
-
 /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
template function.  */
 #define DECL_PRETTY_FUNCTION_P(NODE) \
@@ -5337,7 +5331,6 @@ extern void finish_handler_parms		(tree, tree);
 extern void finish_handler			(tree);
 extern void finish_cleanup			(tree, tree);
 extern bool literal_type_p (tree);
-extern void check_deferred_constexpr_decls (void);
 extern tree validate_constexpr_fundecl (tree);
 extern tree register_constexpr_fundef (tree, tree);
 extern bool check_constexpr_ctor_body (tree, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7939140..e950c43 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -7200,10 +7200,7 @@ grokfndecl (tree ctype,
   if (inlinep)
 DECL_DECLARED_INLINE_P (decl) = 1;
   if (inlinep  2)
-{
-  DECL_DECLARED_CONSTEXPR_P (decl) = true;
-  validate_constexpr_fundecl (decl);
-}
+DECL_DECLARED_CONSTEXPR_P (decl) = true;
 
   DECL_EXTERNAL (decl) = 1;
   if (quals  TREE_CODE (type) == FUNCTION_TYPE)
@@ -10681,9 +10678,6 @@ grok_special_member_properties (tree decl)
 	TYPE_HAS_LIST_CTOR (class_type) = 1;
 
   if 

Re: C++ PATCH for c++/48948 (rejecting constexpr friend that takes the current class)

2011-05-12 Thread Jason Merrill
While thinking about this issue some more it occurred to me that this 
deferral can be problematic for constructors, since we use whether or 
not a constructor is really constexpr to decide whether or not a class 
is literal.  The rule that seems to me to make the most sense is to say 
that if we don't know yet whether a constructor is really constexpr, it 
doesn't satisfy the literal class requirement for a constexpr constructor.


Tested x86_64-pc-linux-gnu, applied to trunk.
commit 7919b46302ba6182d2dfa31d33eacbc2335de31e
Author: Jason Merrill ja...@redhat.com
Date:   Thu May 12 12:33:08 2011 -0400

* cp-tree.h (DECL_DEFERRED_CONSTEXPR_CHECK): New.
* semantics.c (validate_constexpr_fundecl): Set it.
(check_deferred_constexpr_decls): Clear it.
(register_constexpr_fundef): Make sure it isn't set.
* decl.c (grok_special_member_properties): Check it.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ec59346..bcf78f8 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -93,6 +93,7 @@ c-common.h, not after.
   TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE)
   LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR)
   TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
+  DECL_DEFERRED_CONSTEXPR_CHECK (in FUNCTION_DECL)
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
   ICS_BAD_FLAG (in _CONV)
   FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -2338,6 +2339,11 @@ struct GTY((variable_size)) lang_decl {
 #define DECL_DECLARED_CONSTEXPR_P(DECL) \
   DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
 
+/* True if we can't tell yet whether the argument/return types of DECL
+   are literal because one is still being defined.  */
+#define DECL_DEFERRED_CONSTEXPR_CHECK(DECL) \
+  TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
+
 /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
template function.  */
 #define DECL_PRETTY_FUNCTION_P(NODE) \
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 87be112..7939140 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10681,6 +10681,9 @@ grok_special_member_properties (tree decl)
TYPE_HAS_LIST_CTOR (class_type) = 1;
 
   if (DECL_DECLARED_CONSTEXPR_P (decl)
+ /* It doesn't count if we can't tell yet whether or not
+the constructor is actually constexpr.  */
+  !DECL_DEFERRED_CONSTEXPR_CHECK (decl)
   !copy_fn_p (decl)  !move_fn_p (decl))
TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1;
 }
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index ffabad1..f1f3121 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5483,7 +5483,10 @@ check_deferred_constexpr_decls (void)
   deferred_constexpr_decls = NULL;
 
   FOR_EACH_VEC_ELT (tree, vec, i, fn)
-validate_constexpr_fundecl (fn);
+{
+  DECL_DEFERRED_CONSTEXPR_CHECK (fn) = false;
+  validate_constexpr_fundecl (fn);
+}
 
   if (deferred_constexpr_decls == NULL)
 {
@@ -5516,6 +5519,7 @@ validate_constexpr_fundecl (tree fun)
 /*defer_ok=*/true);
   if (valid  0)
 {
+  DECL_DEFERRED_CONSTEXPR_CHECK (fun) = true;
   VEC_safe_push (tree, gc, deferred_constexpr_decls, fun);
   return NULL;
 }
@@ -5764,6 +5768,9 @@ register_constexpr_fundef (tree fun, tree body)
   constexpr_fundef entry;
   constexpr_fundef **slot;
 
+  gcc_assert (DECL_DECLARED_CONSTEXPR_P (fun)
+  !DECL_DEFERRED_CONSTEXPR_CHECK (fun));
+
   if (DECL_CONSTRUCTOR_P (fun))
 body = build_constexpr_constructor_member_initializers
   (DECL_CONTEXT (fun), body);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
new file mode 100644
index 000..7a9a24d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
@@ -0,0 +1,31 @@
+// A constructor that might or might not be constexpr doesn't make
+// its class literal.
+// { dg-options -std=c++0x }
+
+template class T
+struct B
+{
+  constexpr B(T) { }
+  constexpr B() {}
+};
+
+struct A
+{
+  BA b;
+};
+
+constexpr A a {};
+
+template class T
+struct C
+{
+  constexpr C(T) { }
+  C() {}
+};
+
+struct D
+{
+  CD c;
+};
+
+constexpr D d {};  // { dg-error not literal }