Patchwork C++0x constexpr PATCH #1: improve setting of CLASSTYPE_LITERAL_P

login
register
mail settings
Submitter Jason Merrill
Date Oct. 27, 2010, 7:04 p.m.
Message ID <4CC877A8.8030109@redhat.com>
Download mbox | patch
Permalink /patch/69390/
State New
Headers show

Comments

Jason Merrill - Oct. 27, 2010, 7:04 p.m.
This patch improves the rules that determine whether or not a class is a 
literal type.  It also introduces a flag TYPE_HAS_CONSTEXPR_CTOR which 
indicates that a class has a constexpr constructor that is not a 
copy/move constructor, which property is disjoint from that of 
literality; a literal class can have a trivial default constructor which 
is not constexpr, and a non-literal class can have constexpr 
constructors for the purpose of static initialization.

Tested x86_64-pc-linux-gnu, applied to trunk.

Patch

commit dbebe24af5ef8db253d4ce7656f53e9ae6816667
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Oct 27 14:24:31 2010 -0400

    	* class.c (check_bases): Propagate non-literality.
    	(check_field_decls): Likewise.
    	(finalize_literal_type_property): New.
    	(check_bases_and_members): Call it.
    	* cp-tree.h (TYPE_HAS_CONSTEXPR_CTOR): New.
    	(lang_type_class): Add has_constexpr_ctor field.
    	(DECL_DECLARED_CONSTEXPR_P): Strip template.
    	* decl.c (grok_special_member_properties): Set
    	TYPE_HAS_CONSTEXPR_CTOR.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index f76c2be..00af0ae 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1269,6 +1269,10 @@  check_bases (tree t,
 
       gcc_assert (COMPLETE_TYPE_P (basetype));
 
+      /* If any base class is non-literal, so is the derived class.  */
+      if (!CLASSTYPE_LITERAL_P (basetype))
+        CLASSTYPE_LITERAL_P (t) = false;
+
       /* Effective C++ rule 14.  We only need to check TYPE_POLYMORPHIC_P
 	 here because the case of virtual functions but non-virtual
 	 dtor is handled in finish_struct_1.  */
@@ -3051,6 +3055,11 @@  check_field_decls (tree t, tree *access_decls,
       if (TREE_PRIVATE (x) || TREE_PROTECTED (x))
 	CLASSTYPE_NON_AGGREGATE (t) = 1;
 
+      /* If at least one non-static data member is non-literal, the whole
+         class becomes non-literal.  */
+      if (!literal_type_p (type))
+        CLASSTYPE_LITERAL_P (t) = false;
+
       /* A standard-layout class is a class that:
 	 ...
 	 has the same access control (Clause 11) for all non-static data members,
@@ -4455,6 +4464,41 @@  type_requires_array_cookie (tree type)
   return has_two_argument_delete_p;
 }
 
+/* Finish computing the `literal type' property of class type T.
+
+   At this point, we have already processed base classes and
+   non-static data members.  We need to check whether the copy
+   constructor is trivial, the destructor is trivial, and there
+   is a trivial default constructor or at least one constexpr
+   constructor other than the copy constructor.  */
+
+static void
+finalize_literal_type_property (tree t)
+{
+  if (cxx_dialect < cxx0x
+      || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+      /* FIXME These constraints seem unnecessary; remove from standard.
+	 || !TYPE_HAS_TRIVIAL_COPY_CTOR (t)
+	 || TYPE_HAS_COMPLEX_MOVE_CTOR (t)*/ )
+    CLASSTYPE_LITERAL_P (t) = false;
+  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) && !CLASSTYPE_TEMPLATE_INSTANTIATION (t))
+    {
+      tree fn;
+      for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
+	if (DECL_DECLARED_CONSTEXPR_P (fn)
+	    && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
+	    && !DECL_CONSTRUCTOR_P (fn))
+	  {
+	    error ("enclosing class of %q+D is not a literal type", fn);
+	    DECL_DECLARED_CONSTEXPR_P (fn) = false;
+	  }
+    }
+}
+
 /* Check the validity of the bases and members declared in T.  Add any
    implicitly-generated functions (like copy-constructors and
    assignment operators).  Compute various flag bits (like
@@ -4611,6 +4655,10 @@  check_bases_and_members (tree t)
       CLASSTYPE_NON_AGGREGATE (t) = 1;
     }
 
+  /* Compute the 'literal type' property before we
+     do anything with non-static member functions.  */
+  finalize_literal_type_property (t);
+
   /* Create the in-charge and not-in-charge variants of constructors
      and destructors.  */
   clone_constructors_and_destructors (t);
@@ -5445,6 +5493,7 @@  finish_struct_1 (tree t)
   CLASSTYPE_EMPTY_P (t) = 1;
   CLASSTYPE_NEARLY_EMPTY_P (t) = 1;
   CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) = 0;
+  CLASSTYPE_LITERAL_P (t) = true;
 
   /* Do end-of-class semantic processing: checking the validity of the
      bases and members and add implicitly generated methods.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ec026a4..8c0c9b1 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1324,6 +1324,7 @@  struct GTY(()) lang_type_class {
   unsigned lazy_move_assign : 1;
   unsigned has_complex_move_ctor : 1;
   unsigned has_complex_move_assign : 1;
+  unsigned has_constexpr_ctor : 1;
 
   /* When adding a flag here, consider whether or not it ought to
      apply to a template instance if it applies to the template.  If
@@ -1332,7 +1333,7 @@  struct GTY(()) lang_type_class {
   /* There are some bits left to fill out a 32-bit word.  Keep track
      of this by updating the size of this bitfield whenever you add or
      remove a flag.  */
-  unsigned dummy : 4;
+  unsigned dummy : 3;
 
   tree primary_base;
   VEC(tree_pair_s,gc) *vcall_indices;
@@ -1457,6 +1458,12 @@  struct GTY((variable_size)) lang_type {
 #define TYPE_HAS_LIST_CTOR(NODE) \
   (LANG_TYPE_CLASS_CHECK (NODE)->has_list_ctor)
 
+/* Nonzero if this class has a constexpr constructor other than a copy/move
+   constructor.  Note that a class can have constexpr constructors for
+   static initialization even if it isn't a literal class.  */
+#define TYPE_HAS_CONSTEXPR_CTOR(NODE) \
+  (LANG_TYPE_CLASS_CHECK (NODE)->has_constexpr_ctor)
+
 /* Nonzero if this class defines an overloaded operator new.  (An
    operator new [] doesn't count.)  */
 #define TYPE_HAS_NEW_OPERATOR(NODE) \
@@ -2334,7 +2341,7 @@  struct GTY((variable_size)) lang_decl {
 
 /* True if DECL is declared 'constexpr'.  */
 #define DECL_DECLARED_CONSTEXPR_P(DECL) \
-  DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (DECL))
+  DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
 
 /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
    template function.  */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e513bc0..e27a64d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10292,6 +10292,10 @@  grok_special_member_properties (tree decl)
 	TYPE_HAS_COMPLEX_MOVE_CTOR (class_type) = 1;
       else if (is_list_ctor (decl))
 	TYPE_HAS_LIST_CTOR (class_type) = 1;
+
+      if (DECL_DECLARED_CONSTEXPR_P (decl)
+	  && !copy_fn_p (decl) && !move_fn_p (decl))
+	TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1;
     }
   else if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
     {
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0012bdd..4e73068 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5245,6 +5245,7 @@  float_const_decimal64_p (void)
   return 0;
 }
 
+
 /* Return true if T is a literal type.   */
 
 bool
@@ -5259,7 +5260,6 @@  literal_type_p (tree t)
   return false;
 }
 
-
 /* If DECL is a variable declared `constexpr', require its type
    be literal.  Return the DECL if OK, otherwise NULL.  */