re PR c++/48948 ([C++0x] constexpr friend function cannot be defined in-class)
authorJason Merrill <jason@redhat.com>
Wed, 18 May 2011 17:19:15 +0000 (13:19 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 18 May 2011 17:19:15 +0000 (13:19 -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.

From-SVN: r173869

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C

index 6260a3b085d33ef98e3c14fde134b089b75212e4..cc4319eeff0cd6f7e873d1b651c9b04de366a836 100644 (file)
@@ -1,3 +1,25 @@
+2011-05-18  Jason Merrill  <jason@redhat.com>
+
+       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.
+
 2011-05-16  Jason Merrill  <jason@redhat.com>
 
        PR c++/48969
index dc2c509a8cf29feaef4cc905d8f7ab3e158f08ec..4e52b1854881b117cd38a52e3a0918d543306a07 100644 (file)
@@ -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));
 
index c0b52908883b6924514c0990c17a8a22544bc3c6..dfb2b66c0ba2128e1148f595a2fa511239c9d673 100644 (file)
@@ -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);
index 793914002fe2cbbaca942fbd46c9bd7208a9ddbb..e950c43e9cf19a6830bbe134722b1daa86806021 100644 (file)
@@ -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 (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;
     }
@@ -12524,6 +12518,10 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
        maybe_apply_pragma_weak (decl1);
     }
 
+  /* constexpr functions must have literal argument types and
+     literal return type.  */
+  validate_constexpr_fundecl (decl1);
+
   /* Reset this in case the call to pushdecl changed it.  */
   current_function_decl = decl1;
 
index cc14f0275bce1e9aadd0b5e8988f8455703e51c8..75d0674bb40e4c647e1aff18c794daa40c9f2f09 100644 (file)
@@ -8595,8 +8595,6 @@ instantiate_class_template_1 (tree type)
   pop_deferring_access_checks ();
   pop_tinst_level ();
 
-  check_deferred_constexpr_decls ();
-
   /* The vtable for a template class can be emitted in any translation
      unit in which the class is instantiated.  When there is no key
      method, however, finish_struct_1 will already have added TYPE to
@@ -9743,7 +9741,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
        if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)
            && !processing_template_decl)
          defaulted_late_check (r);
-       validate_constexpr_fundecl (r);
 
        apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
                                        args, complain, in_decl);
index 56d2411854026b8cb8b37f85b7edb85545e85f2c..8d0cce1c478c0b5203e1afc3a6e50c0336e3d16f 100644 (file)
@@ -5337,9 +5337,9 @@ literal_type_p (tree t)
     return true;
   if (CLASS_TYPE_P (t))
     {
-      /* We can't answer this question until the class is complete.  */
-      gcc_assert (!TYPE_BEING_DEFINED (t) || errorcount);
-      return CLASSTYPE_LITERAL_P (complete_type (t));
+      t = complete_type (t);
+      gcc_assert (COMPLETE_TYPE_P (t) || errorcount);
+      return CLASSTYPE_LITERAL_P (t);
     }
   if (TREE_CODE (t) == ARRAY_TYPE)
     return literal_type_p (strip_array_types (t));
@@ -5356,7 +5356,7 @@ ensure_literal_type_for_constexpr_object (tree decl)
   if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl)
       && !processing_template_decl)
     {
-      if (CLASS_TYPE_P (type) && TYPE_BEING_DEFINED (type))
+      if (CLASS_TYPE_P (type) && !COMPLETE_TYPE_P (complete_type (type)))
        /* Don't complain here, we'll complain about incompleteness
           when we try to initialize the variable.  */;
       else if (!literal_type_p (type))
@@ -5417,22 +5417,15 @@ retrieve_constexpr_fundef (tree fun)
 }
 
 /* Check whether the parameter and return types of FUN are valid for a
-   constexpr function, and complain if COMPLAIN.  If DEFER_OK is true,
-   return -1 if we can't tell yet because some of the types are still being
-   defined.  */
+   constexpr function, and complain if COMPLAIN.  */
 
-static int
-is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok)
+static bool
+is_valid_constexpr_fn (tree fun, bool complain)
 {
-#define IF_NON_LITERAL(TYPE)                                           \
-  if (defer_ok && CLASS_TYPE_P (TYPE) && TYPE_BEING_DEFINED (TYPE))    \
-    return -1;                                                         \
-  else if (!literal_type_p (TYPE))
-
   tree parm = FUNCTION_FIRST_USER_PARM (fun);
   bool ret = true;
   for (; parm != NULL; parm = TREE_CHAIN (parm))
-    IF_NON_LITERAL (TREE_TYPE (parm))
+    if (!literal_type_p (TREE_TYPE (parm)))
       {
        ret = false;
        if (complain)
@@ -5443,7 +5436,7 @@ is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok)
   if (!DECL_CONSTRUCTOR_P (fun))
     {
       tree rettype = TREE_TYPE (TREE_TYPE (fun));
-      IF_NON_LITERAL (rettype)
+      if (!literal_type_p (rettype))
        {
          ret = false;
          if (complain)
@@ -5451,54 +5444,19 @@ is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok)
                   rettype, fun);
        }
 
-      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun))
+      /* Check this again here for cxx_eval_call_expression.  */
+      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
+         && !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun)))
        {
-         IF_NON_LITERAL (DECL_CONTEXT (fun))
-           {
-             ret = false;
-             if (complain)
-               error ("enclosing class of %q+#D is not a literal type", fun);
-           }
+         ret = false;
+         if (complain)
+           error ("enclosing class of %q+#D is not a literal type", fun);
        }
     }
 
   return ret;
 }
 
-/* We can't check the parameter and return types of a constexpr function
-   for literality until any open classes are complete, so we defer checking
-   of any constexpr functions declared in a class.  */
-
-static GTY(()) VEC(tree,gc) *deferred_constexpr_decls;
-
-void
-check_deferred_constexpr_decls (void)
-{
-  unsigned i;
-  tree fn;
-
-  /* Some of the deferred decls might still need to be deferred,
-     so move the vector out of the way.  */
-  VEC(tree,gc) *vec = deferred_constexpr_decls;
-  deferred_constexpr_decls = NULL;
-
-  FOR_EACH_VEC_ELT (tree, vec, i, fn)
-    {
-      DECL_DEFERRED_CONSTEXPR_CHECK (fn) = false;
-      validate_constexpr_fundecl (fn);
-    }
-
-  if (deferred_constexpr_decls == NULL)
-    {
-      /* If we didn't need to re-defer any, keep the same vector.  */
-      VEC_truncate (tree, vec, 0);
-      deferred_constexpr_decls = vec;
-    }
-  else
-    /* Otherwise, discard the old vector.  */
-    release_tree_vector (vec);
-}
-
 /* Return non-null if FUN certainly designates a valid constexpr function
    declaration.  Otherwise return NULL.  Issue appropriate diagnostics
    if necessary.  Note that we only check the declaration, not the body
@@ -5507,23 +5465,13 @@ check_deferred_constexpr_decls (void)
 tree
 validate_constexpr_fundecl (tree fun)
 {
-  int valid;
-
   if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
     return NULL;
   else if (DECL_CLONED_FUNCTION_P (fun))
     /* We already checked the original function.  */
     return fun;
 
-  valid = is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun),
-                                /*defer_ok=*/true);
-  if (valid < 0)
-    {
-      DECL_DEFERRED_CONSTEXPR_CHECK (fun) = true;
-      VEC_safe_push (tree, gc, deferred_constexpr_decls, fun);
-      return NULL;
-    }
-  else if (valid == 0)
+  if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun)))
     {
       DECL_DECLARED_CONSTEXPR_P (fun) = false;
       return NULL;
@@ -5768,9 +5716,6 @@ 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);
@@ -6143,7 +6088,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
          if (DECL_TEMPLATE_INFO (fun)
              && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
                                            (DECL_TI_TEMPLATE (fun))))
-           is_valid_constexpr_fn (fun, true, /*defer_ok=*/false);
+           is_valid_constexpr_fn (fun, true);
        }
       *non_constant_p = true;
       return t;
index 45b3c5f2708fe0ca13dae2931da37ecd262ccee0..111a32251c09d6557114349a2d69d56cc117b069 100644 (file)
@@ -1,3 +1,9 @@
+2011-05-18  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/constexpr-incomplete3.C: New.
+       * g++.dg/cpp0x/constexpr-incomplete2.C: Adjust.
+       * g++.dg/cpp0x/constexpr-memfn1.C: Adjust.
+
 2011-05-18  Stuart Henderson  <shenders@gcc.gnu.org>
 
        * gcc.target/bfin/mcpu-bf592.c: New test.
index 7a9a24dc40a3b9d51502457bbdebbccf8e4c3394..dc0b7429dc65c7c52f92e2a9bfae3196b6df8966 100644 (file)
@@ -1,4 +1,4 @@
-// A constructor that might or might not be constexpr doesn't make
+// A constructor that might or might not be constexpr still makes
 // its class literal.
 // { dg-options -std=c++0x }
 
@@ -28,4 +28,4 @@ struct D
   C<D> c;
 };
 
-constexpr D d {};              // { dg-error "not literal" }
+constexpr D d {};              // { dg-error "not a constexpr function" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete3.C
new file mode 100644 (file)
index 0000000..81822b0
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/49015
+// { dg-options -std=c++0x }
+
+class A;
+
+class B {
+  friend constexpr B f(A); // Line 5
+};
+
+class A {};
+
+constexpr B f(A) { return B(); } // Line 10
index 4646f82b90439967d471d02b973356577f884f5e..ef7ac6b4842aa448961e11da0b6ce8b760f1663f 100644 (file)
@@ -13,6 +13,6 @@ constexpr X X::g(X x) { return x; }
 struct Y
 {
   Y() { }
-  constexpr Y f(Y y);          // { dg-error "constexpr" }
-  static constexpr Y g(Y y);   // { dg-error "constexpr" }
+  constexpr Y f(Y y);          // { dg-error "not a literal type" }
+  static constexpr Y g(Y y) {} // { dg-error "constexpr" }
 };