This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCHes for c++/45923 (constexpr diagnostics)


In C++0x when an expression fails to satisfy the requirements of a constant expression it can be hard to figure out why; previously the compiler would just say that a particular class or function was not literal or constexpr without explaining why. This patch improves diagnostics by having the compiler recursively explain why classes are not literal or functions not constexpr.

The second patch updates the rules for what classes can be literal, adding aggregates. I've left in trivial default constructors for now even though it was dropped from the FDIS.

The third patch is necessary to avoid some testsuite failures from complaints about non-literal temporaries if we do eventually drop trivial default constructors.

The last patch tweaks the similar function maybe_explain_implicit_delete to use a pointer set instead of a hash table, since we were only using it as a set anyway.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit fe193797db267abf26a2632fed0a36828505d0c9
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 27 17:02:23 2011 -0400

    	PR c++/45923
    	* class.c (explain_non_literal_class): New.
    	(finalize_literal_type_property): Call it.
    	* cp-tree.h: Declare it.
    	* semantics.c (ensure_literal_type_for_constexpr_object): Call it.
    	(is_valid_constexpr_fn): Likewise.
    	(massage_constexpr_body): Split out from...
    	(register_constexpr_fundef): ...here.
    	(is_instantiation_of_constexpr): New.
    	(expand_or_defer_fn_1): Leave DECL_SAVED_TREE alone in that case.
    	(explain_invalid_constexpr_fn): New.
    	(cxx_eval_call_expression): Call it.
    	(potential_constant_expression_1): Likewise.  Avoid redundant errors.
    	* method.c (process_subob_fn): Diagnose non-constexpr.
    	(walk_field_subobs): Likewise.
    	(synthesized_method_walk): Don't shortcut if we want diagnostics.
    	(explain_implicit_non_constexpr): New.
    	(defaulted_late_check): Use it.
    	* call.c (build_cxx_call): Remember location.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index e2d455a..56f3408 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -6721,7 +6721,10 @@ build_cxx_call (tree fn, int nargs, tree *argarray)
 {
   tree fndecl;
 
+  /* Remember roughly where this call is.  */
+  location_t loc = EXPR_LOC_OR_HERE (fn);
   fn = build_call_a (fn, nargs, argarray);
+  SET_EXPR_LOCATION (fn, loc);
 
   /* If this call might throw an exception, note that fact.  */
   fndecl = get_callee_fndecl (fn);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 9054b5c..6aefd68 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "tree-dump.h"
 #include "splay-tree.h"
+#include "pointer-set.h"
 
 /* The number of nested classes being processed.  If we are not in the
    scope of any class, this is zero.  */
@@ -4582,10 +4583,73 @@ finalize_literal_type_property (tree t)
 	{
 	  DECL_DECLARED_CONSTEXPR_P (fn) = false;
 	  if (!DECL_TEMPLATE_INFO (fn))
-	    error ("enclosing class of %q+#D is not a literal type", fn);
+	    {
+	      error ("enclosing class of constexpr non-static member "
+		     "function %q+#D is not a literal type", fn);
+	      explain_non_literal_class (t);
+	    }
 	}
 }
 
+/* T is a non-literal type used in a context which requires a constant
+   expression.  Explain why it isn't literal.  */
+
+void
+explain_non_literal_class (tree t)
+{
+  static struct pointer_set_t *diagnosed;
+
+  if (!CLASS_TYPE_P (t))
+    return;
+  t = TYPE_MAIN_VARIANT (t);
+
+  if (diagnosed == NULL)
+    diagnosed = pointer_set_create ();
+  if (pointer_set_insert (diagnosed, t) != 0)
+    /* Already explained.  */
+    return;
+
+  inform (0, "%q+T is not literal because:", t);
+  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+    inform (0, "  %q+T has a non-trivial destructor", t);
+  else if (CLASSTYPE_NON_AGGREGATE (t)
+	   && !TYPE_HAS_TRIVIAL_DFLT (t)
+	   && !TYPE_HAS_CONSTEXPR_CTOR (t))
+    inform (0, "  %q+T is not an aggregate, does not have a trivial "
+	    "default constructor, and has no constexpr constructor that "
+	    "is not a copy or move constructor", t);
+  else
+    {
+      tree binfo, base_binfo, field; int i;
+      for (binfo = TYPE_BINFO (t), i = 0;
+	   BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+	{
+	  tree basetype = TREE_TYPE (base_binfo);
+	  if (!CLASSTYPE_LITERAL_P (basetype))
+	    {
+	      inform (0, "  base class %qT of %q+T is non-literal",
+		      basetype, t);
+	      explain_non_literal_class (basetype);
+	      return;
+	    }
+	}
+      for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+	{
+	  tree ftype;
+	  if (TREE_CODE (field) != FIELD_DECL)
+	    continue;
+	  ftype = TREE_TYPE (field);
+	  if (!literal_type_p (ftype))
+	    {
+	      inform (0, "  non-static data member %q+D has "
+		      "non-literal type", field);
+	      if (CLASS_TYPE_P (ftype))
+		explain_non_literal_class (ftype);
+	    }
+	}
+    }
+}
+
 /* 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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9afb33c..7244cc8 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4816,6 +4816,7 @@ extern bool type_has_virtual_destructor		(tree);
 extern bool type_has_move_constructor		(tree);
 extern bool type_has_move_assign		(tree);
 extern bool type_build_ctor_call		(tree);
+extern void explain_non_literal_class		(tree);
 extern void defaulted_late_check		(tree);
 extern bool defaultable_fn_check		(tree);
 extern void fixup_type_variants			(tree);
@@ -5094,6 +5095,7 @@ extern void finish_thunk			(tree);
 extern void use_thunk				(tree, bool);
 extern bool trivial_fn_p			(tree);
 extern bool maybe_explain_implicit_delete	(tree);
+extern void explain_implicit_non_constexpr	(tree);
 extern void synthesize_method			(tree);
 extern tree lazily_declare_fn			(special_function_kind,
 						 tree);
@@ -5364,6 +5366,7 @@ extern tree maybe_constant_value (tree);
 extern tree maybe_constant_init (tree);
 extern bool is_sub_constant_expr (tree);
 extern bool reduced_constant_expression_p (tree);
+extern void explain_invalid_constexpr_fn (tree);
 extern VEC(tree,heap)* cx_error_context (void);
 
 enum {
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index ec1c502..f10e846 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -958,7 +958,15 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
 	  && !DECL_TEMPLATE_INSTANTIATED (fn))
 	instantiate_decl (fn, /*defer_ok*/false, /*expl_class*/false);
       if (!DECL_DECLARED_CONSTEXPR_P (fn))
-	*constexpr_p = false;
+	{
+	  *constexpr_p = false;
+	  if (msg)
+	    {
+	      inform (0, "defaulted constructor calls non-constexpr "
+		      "%q+D", fn);
+	      explain_invalid_constexpr_fn (fn);
+	    }
+	}
     }
 
   return;
@@ -1037,7 +1045,12 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
 	  /* FIXME will need adjustment for non-static data member
 	     initializers.  */
 	  if (constexpr_p && !CLASS_TYPE_P (mem_type))
-	    *constexpr_p = false;
+	    {
+	      *constexpr_p = false;
+	      if (msg)
+		inform (0, "defaulted default constructor does not "
+			"initialize %q+#D", field);
+	    }
 	}
 
       if (!CLASS_TYPE_P (mem_type))
@@ -1071,8 +1084,9 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
 /* The caller wants to generate an implicit declaration of SFK for CTYPE
    which is const if relevant and CONST_P is set.  If spec_p, trivial_p and
    deleted_p are non-null, set their referent appropriately.  If diag is
-   true, we're being called from maybe_explain_implicit_delete to give
-   errors.  */
+   true, we're either being called from maybe_explain_implicit_delete to
+   give errors, or if constexpr_p is non-null, from
+   explain_invalid_constexpr_fn.  */
 
 static void
 synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
@@ -1175,6 +1189,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
      resolution, so a constructor can be trivial even if it would otherwise
      call a non-trivial constructor.  */
   if (expected_trivial
+      && !diag
       && (!copy_arg_p || cxx_dialect < cxx0x))
     {
       if (constexpr_p && sfk == sfk_constructor)
@@ -1366,6 +1381,20 @@ maybe_explain_implicit_delete (tree decl)
   return false;
 }
 
+/* DECL is a defaulted function which was declared constexpr.  Explain why
+   it can't be constexpr.  */
+
+void
+explain_implicit_non_constexpr (tree decl)
+{
+  tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl));
+  bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
+  bool dummy;
+  synthesized_method_walk (DECL_CLASS_CONTEXT (decl),
+			   special_function_p (decl), const_p,
+			   NULL, NULL, NULL, &dummy, true);
+}
+
 /* Implicitly declare the special function indicated by KIND, as a
    member of TYPE.  For copy constructors and assignment operators,
    CONST_P indicates whether these functions should take a const
@@ -1581,7 +1610,12 @@ defaulted_late_check (tree fn)
       && DECL_DECLARED_CONSTEXPR_P (fn))
     {
       if (!CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
-	error ("%qD cannot be declared as constexpr", fn);
+	{
+	  error ("explicitly defaulted function %q+D cannot be declared "
+		 "as constexpr because the implicit declaration is not "
+		 "constexpr:", fn);
+	  explain_implicit_non_constexpr (fn);
+	}
       DECL_DECLARED_CONSTEXPR_P (fn) = false;
     }
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 8121a00..4581729 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3538,6 +3538,17 @@ emit_associated_thunks (tree fn)
     }
 }
 
+/* Returns true iff FUN is an instantiation of a constexpr function
+   template.  */
+
+static inline bool
+is_instantiation_of_constexpr (tree fun)
+{
+  return (DECL_TEMPLATE_INFO (fun)
+	  && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
+					(DECL_TI_TEMPLATE (fun))));
+}
+
 /* Generate RTL for FN.  */
 
 bool
@@ -3567,7 +3578,10 @@ expand_or_defer_fn_1 (tree fn)
       /* We don't want to process FN again, so pretend we've written
 	 it out, even though we haven't.  */
       TREE_ASM_WRITTEN (fn) = 1;
-      DECL_SAVED_TREE (fn) = NULL_TREE;
+      /* If this is an instantiation of a constexpr function, keep
+	 DECL_SAVED_TREE for explain_invalid_constexpr_fn.  */
+      if (!is_instantiation_of_constexpr (fn))
+	DECL_SAVED_TREE (fn) = NULL_TREE;
       return false;
     }
 
@@ -5299,6 +5313,7 @@ ensure_literal_type_for_constexpr_object (tree decl)
 	{
 	  error ("the type %qT of constexpr variable %qD is not literal",
 		 type, decl);
+	  explain_non_literal_class (type);
 	  return NULL;
 	}
     }
@@ -5365,8 +5380,11 @@ is_valid_constexpr_fn (tree fun, bool complain)
       {
 	ret = false;
 	if (complain)
-	  error ("invalid type for parameter %d of constexpr "
-		 "function %q+#D", DECL_PARM_INDEX (parm), fun);
+	  {
+	    error ("invalid type for parameter %d of constexpr "
+		   "function %q+#D", DECL_PARM_INDEX (parm), fun);
+	    explain_non_literal_class (TREE_TYPE (parm));
+	  }
       }
 
   if (!DECL_CONSTRUCTOR_P (fun))
@@ -5376,8 +5394,11 @@ is_valid_constexpr_fn (tree fun, bool complain)
 	{
 	  ret = false;
 	  if (complain)
-	    error ("invalid return type %qT of constexpr function %q+D",
-		   rettype, fun);
+	    {
+	      error ("invalid return type %qT of constexpr function %q+D",
+		     rettype, fun);
+	      explain_non_literal_class (rettype);
+	    }
 	}
 
       /* Check this again here for cxx_eval_call_expression.  */
@@ -5386,7 +5407,11 @@ is_valid_constexpr_fn (tree fun, bool complain)
 	{
 	  ret = false;
 	  if (complain)
-	    error ("enclosing class of %q+#D is not a literal type", fun);
+	    {
+	      error ("enclosing class of constexpr non-static member "
+		     "function %q+#D is not a literal type", fun);
+	      explain_non_literal_class (DECL_CONTEXT (fun));
+	    }
 	}
     }
 
@@ -5640,18 +5665,13 @@ constexpr_fn_retval (tree body)
     }
 }
 
-/* We are processing the definition of the constexpr function FUN.
-   Check that its BODY fulfills the propriate requirements and
-   enter it in the constexpr function definition table.
-   For constructor BODY is actually the TREE_LIST of the
-   member-initializer list.  */
+/* Subroutine of register_constexpr_fundef.  BODY is the DECL_SAVED_TREE of
+   FUN; do the necessary transformations to turn it into a single expression
+   that we can store in the hash table.  */
 
-tree
-register_constexpr_fundef (tree fun, tree body)
+static tree
+massage_constexpr_body (tree fun, tree body)
 {
-  constexpr_fundef entry;
-  constexpr_fundef **slot;
-
   if (DECL_CONSTRUCTOR_P (fun))
     body = build_constexpr_constructor_member_initializers
       (DECL_CONTEXT (fun), body);
@@ -5666,12 +5686,28 @@ register_constexpr_fundef (tree fun, tree body)
       if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
         body = TREE_OPERAND (body, 0);
       body = constexpr_fn_retval (body);
-      if (body == NULL_TREE || body == error_mark_node)
-        {
-          error ("body of constexpr function %qD not a return-statement", fun);
-          DECL_DECLARED_CONSTEXPR_P (fun) = false;
-          return NULL;
-        }
+    }
+  return body;
+}
+
+/* We are processing the definition of the constexpr function FUN.
+   Check that its BODY fulfills the propriate requirements and
+   enter it in the constexpr function definition table.
+   For constructor BODY is actually the TREE_LIST of the
+   member-initializer list.  */
+
+tree
+register_constexpr_fundef (tree fun, tree body)
+{
+  constexpr_fundef entry;
+  constexpr_fundef **slot;
+
+  body = massage_constexpr_body (fun, body);
+  if (body == NULL_TREE || body == error_mark_node)
+    {
+      error ("body of constexpr function %qD not a return-statement", fun);
+      DECL_DECLARED_CONSTEXPR_P (fun) = false;
+      return NULL;
     }
 
   if (!potential_rvalue_constant_expression (body))
@@ -5700,6 +5736,44 @@ register_constexpr_fundef (tree fun, tree body)
   return fun;
 }
 
+/* FUN is a non-constexpr function called in a context that requires a
+   constant expression.  If it comes from a constexpr template, explain why
+   the instantiation isn't constexpr.  */
+
+void
+explain_invalid_constexpr_fn (tree fun)
+{
+  static struct pointer_set_t *diagnosed;
+  tree body;
+  location_t save_loc;
+  /* Only diagnose instantiations of constexpr templates.  */
+  if (!is_instantiation_of_constexpr (fun))
+    return;
+  if (diagnosed == NULL)
+    diagnosed = pointer_set_create ();
+  if (pointer_set_insert (diagnosed, fun) != 0)
+    /* Already explained.  */
+    return;
+
+  save_loc = input_location;
+  input_location = DECL_SOURCE_LOCATION (fun);
+  inform (0, "%q+D is not constexpr because it does not satisfy the "
+	  "requirements:", fun);
+  /* First check the declaration.  */
+  if (is_valid_constexpr_fn (fun, true))
+    {
+      /* Then if it's OK, the body.  */
+      if (DECL_DEFAULTED_FN (fun))
+	explain_implicit_non_constexpr (fun);
+      else
+	{
+	  body = massage_constexpr_body (fun, DECL_SAVED_TREE (fun));
+	  require_potential_rvalue_constant_expression (body);
+	}
+    }
+  input_location = save_loc;
+}
+
 /* Objects of this type represent calls to constexpr functions
    along with the bindings of parameters to their arguments, for
    the purpose of compile time evaluation.  */
@@ -6005,7 +6079,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
     }
   if (TREE_CODE (fun) != FUNCTION_DECL)
     {
-      if (!allow_non_constant)
+      if (!allow_non_constant && !*non_constant_p)
 	error_at (loc, "expression %qE does not designate a constexpr "
 		  "function", fun);
       *non_constant_p = true;
@@ -6020,11 +6094,8 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
     {
       if (!allow_non_constant)
 	{
-	  error_at (loc, "%qD is not a constexpr function", fun);
-	  if (DECL_TEMPLATE_INFO (fun)
-	      && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
-					    (DECL_TI_TEMPLATE (fun))))
-	    is_valid_constexpr_fn (fun, true);
+	  error_at (loc, "call to non-constexpr function %qD", fun);
+	  explain_invalid_constexpr_fn (fun);
 	}
       *non_constant_p = true;
       return t;
@@ -7023,8 +7094,11 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
       if (!literal_type_p (TREE_TYPE (t)))
 	{
 	  if (!allow_non_constant)
-	    error ("temporary of non-literal type %qT in a "
-		   "constant expression", TREE_TYPE (t));
+	    {
+	      error ("temporary of non-literal type %qT in a "
+		     "constant expression", TREE_TYPE (t));
+	      explain_non_literal_class (TREE_TYPE (t));
+	    }
 	  *non_constant_p = true;
 	  break;
 	}
@@ -7574,7 +7648,11 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
 		    && !morally_constexpr_builtin_function_p (fun))
 		  {
 		    if (flags & tf_error)
-		      error ("%qD is not %<constexpr%>", fun);
+		      {
+			error_at (EXPR_LOC_OR_HERE (t),
+				  "call to non-constexpr function %qD", fun);
+			explain_invalid_constexpr_fn (fun);
+		      }
 		    return false;
 		  }
 		/* A call to a non-static member function takes the address
@@ -7588,12 +7666,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
 		    if (is_this_parameter (x))
 		      /* OK.  */;
 		    else if (!potential_constant_expression_1 (x, rval, flags))
-		      {
-			if (flags & tf_error)
-			  error ("object argument is not a potential "
-				 "constant expression");
-			return false;
-		      }
+		      return false;
 		    i = 1;
 		  }
 	      }
@@ -7609,22 +7682,13 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
 	    if (potential_constant_expression_1 (fun, rval, flags))
 	      /* Might end up being a constant function pointer.  */;
 	    else
-	      {
-		if (flags & tf_error)
-		  error ("%qE is not a function name", fun);
-		return false;
-	      }
+	      return false;
           }
         for (; i < nargs; ++i)
           {
             tree x = get_nth_callarg (t, i);
 	    if (!potential_constant_expression_1 (x, rval, flags))
-	      {
-		if (flags & tf_error)
-		  error ("argument in position %qP is not a "
-			 "potential constant expression", i);
-		return false;
-              }
+	      return false;
           }
         return true;
       }
@@ -7853,8 +7917,11 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
       if (!literal_type_p (TREE_TYPE (t)))
 	{
 	  if (flags & tf_error)
-	    error ("temporary of non-literal type %qT in a "
-		   "constant expression", TREE_TYPE (t));
+	    {
+	      error ("temporary of non-literal type %qT in a "
+		     "constant expression", TREE_TYPE (t));
+	      explain_non_literal_class (TREE_TYPE (t));
+	    }
 	  return false;
 	}
     case INIT_EXPR:
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
index 183d3f7..44e6bc7 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
@@ -13,7 +13,7 @@ struct B { B(); operator int(); };
 constexpr A<int> ai = { 42 };
 constexpr int i = ai.f();
 
-constexpr int b = A<B>().f();	// { dg-error "not a constexpr function" }
+constexpr int b = A<B>().f();	// { dg-error "non-constexpr function" }
 
 template <class T>
 constexpr int f (T t) { return 42; } // { dg-error "parameter" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
new file mode 100644
index 0000000..100c17e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
@@ -0,0 +1,54 @@
+// PR c++/45923
+// { dg-options -std=c++0x }
+
+int f(int);
+
+template <class T>
+constexpr T g(T t) { return f(t); } // { dg-error "f.int" }
+
+int main()
+{
+  constexpr int i = g(1);	// { dg-error "g.T" }
+}
+
+// --------------------
+
+struct complex 			// { dg-message "no constexpr constructor" }
+{
+  complex(double r, double i) : re(r), im(i) { }
+  constexpr double real() { return re; } // { dg-error "not a literal type" }
+  double imag() const { return im; }
+
+private:
+  double re;
+  double im;
+};
+
+constexpr complex co1(0, 1);	   // { dg-error "not literal" }
+constexpr double dd2 = co1.real(); // { dg-error "non-constexpr function" }
+
+// --------------------
+
+struct base		       // { dg-message "no constexpr constructor" }
+{
+  int _M_i;
+  base() : _M_i(5) { }
+};
+
+struct derived : public base	// { dg-message "base class" }
+{
+  constexpr derived(): base() { } // { dg-error "non-constexpr function" }
+};
+
+constexpr derived obj;		// { dg-error "not literal" }
+
+// --------------------
+
+struct Def
+{
+  int _M_i;			// { dg-message "does not initialize" }
+
+  constexpr Def() = default;	// { dg-error "implicit declaration is not constexpr" }
+};
+
+constexpr Def defobj;		// { dg-error "uninitialized" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
index 4ab4677..584a5a0 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
@@ -88,7 +88,7 @@ struct resource {
   }
 };
 constexpr resource f(resource d)
-{ return d; }                  // { dg-error "not .constexpr" }
+{ return d; }                  // { dg-error "non-constexpr" }
 constexpr resource d = f(9);   // { dg-error "resource" }
 
 // 4.4 floating-point constant expressions
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C
index f1d9cce..1831a2b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C
@@ -19,5 +19,5 @@ struct C
 
 constexpr int i = f(C<int>());
 constexpr int j = C<int>().m(C<int>());
-constexpr int k = C<double>().m(A()); // { dg-error "not a constexpr function" }
-constexpr int l = g(C<double>(),A()); // { dg-error "not a constexpr function" }
+constexpr int k = C<double>().m(A()); // { dg-error "non-constexpr function" }
+constexpr int l = g(C<double>(),A()); // { dg-error "non-constexpr function" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
index dc0b742..f61535f 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
@@ -28,4 +28,4 @@ struct D
   C<D> c;
 };
 
-constexpr D d {};		// { dg-error "not a constexpr function" }
+constexpr D d {};		// { dg-error "non-constexpr function" }
commit c9a13d6adc25c488c6b87d13cbd032171bb86605
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 27 17:00:17 2011 -0400

    	* class.c (finalize_literal_type_property): Update conditions.
    	* method.c (defaulted_late_check): Set TYPE_HAS_CONSTEXPR_CTOR.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 9e387a6..9054b5c 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4566,12 +4566,10 @@ 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.
-	 || !TYPE_HAS_TRIVIAL_COPY_CTOR (t)
-	 || TYPE_HAS_COMPLEX_MOVE_CTOR (t)*/ )
+      || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
     CLASSTYPE_LITERAL_P (t) = false;
   else if (CLASSTYPE_LITERAL_P (t) && !TYPE_HAS_TRIVIAL_DFLT (t)
+	   && CLASSTYPE_NON_AGGREGATE (t)
 	   && !TYPE_HAS_CONSTEXPR_CTOR (t))
     CLASSTYPE_LITERAL_P (t) = false;
 
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 48b9c74..de43a38 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1571,10 +1571,14 @@ defaulted_late_check (tree fn)
 	}
       TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
       if (DECL_DECLARED_CONSTEXPR_P (implicit_fn))
-	/* Hmm...should we do this for out-of-class too? Should it be OK to
-	   add constexpr later like inline, rather than requiring
-	   declarations to match?  */
-	DECL_DECLARED_CONSTEXPR_P (fn) = true;
+	{
+	  /* Hmm...should we do this for out-of-class too? Should it be OK to
+	     add constexpr later like inline, rather than requiring
+	     declarations to match?  */
+	  DECL_DECLARED_CONSTEXPR_P (fn) = true;
+	  if (kind == sfk_constructor)
+	    TYPE_HAS_CONSTEXPR_CTOR (ctx) = true;
+	}
     }
 
   if (!DECL_DECLARED_CONSTEXPR_P (implicit_fn)
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-is_literal.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-is_literal.C
index d1b9543..82514ed 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-is_literal.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-is_literal.C
@@ -33,6 +33,7 @@ YES(NotLiteral (NotLiteral::*)(NotLiteral));
 
 struct A {
   A(const A&) = default;
+  A(int);
 };
 
 NO(A);				// no constexpr ctor other than copy
commit a195d63c43cb3e8d83388c7c4344e52d6f395b4c
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jun 28 14:22:48 2011 -0400

    	* tree.c (build_vec_init_expr): Don't add TARGET_EXPR.
    	* typeck2.c (digest_init_r): Handle VEC_INIT_EXPR.
    	* semantics.c (cxx_eval_vec_init_1): Correct type.

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index d1af0c6..8121a00 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -6646,7 +6646,7 @@ cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
 
   if (!*non_constant_p)
     {
-      init = build_constructor (TREE_TYPE (atype), n);
+      init = build_constructor (atype, n);
       TREE_CONSTANT (init) = true;
       return init;
     }
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 3100508..c50751f 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -541,9 +541,6 @@ build_vec_init_expr (tree type, tree init, tsubst_flags_t complain)
     VEC_INIT_EXPR_IS_CONSTEXPR (init) = true;
   VEC_INIT_EXPR_VALUE_INIT (init) = value_init;
 
-  init = build_target_expr (slot, init, complain);
-  TARGET_EXPR_IMPLICIT_P (init) = 1;
-
   return init;
 }
 
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 8bb938e..023fab3 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -925,7 +925,7 @@ digest_init_r (tree type, tree init, bool nested, int flags,
 	{
 	  /* Allow the result of build_array_copy and of
 	     build_value_init_noctor.  */
-	  if ((TREE_CODE (init) == TARGET_EXPR
+	  if ((TREE_CODE (init) == VEC_INIT_EXPR
 	       || TREE_CODE (init) == CONSTRUCTOR)
 	      && (same_type_ignoring_top_level_qualifiers_p
 		  (type, TREE_TYPE (init))))
commit f232088231360150e73f7506cb37a696447d23e8
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 27 16:30:02 2011 -0400

    	* method.c (maybe_explain_implicit_delete): Use pointer_set
    	instead of htab.

diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index de43a38..ec1c502 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1320,21 +1320,17 @@ maybe_explain_implicit_delete (tree decl)
   if (DECL_DEFAULTED_FN (decl))
     {
       /* Not marked GTY; it doesn't need to be GC'd or written to PCH.  */
-      static htab_t explained_htab;
-      void **slot;
+      static struct pointer_set_t *explained;
 
       special_function_kind sfk;
       location_t loc;
       bool informed;
       tree ctype;
 
-      if (!explained_htab)
-	explained_htab = htab_create (37, htab_hash_pointer,
-				      htab_eq_pointer, NULL);
-      slot = htab_find_slot (explained_htab, decl, INSERT);
-      if (*slot)
+      if (!explained)
+	explained = pointer_set_create ();
+      if (pointer_set_insert (explained, decl))
 	return true;
-      *slot = decl;
 
       sfk = special_function_p (decl);
       ctype = DECL_CONTEXT (decl);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]