Patchwork C++ PATCH for c++/48500 (C++0x crash on non-type-dependent but non-constant call in template)

login
register
mail settings
Submitter Jason Merrill
Date April 8, 2011, 2:17 a.m.
Message ID <4D9E7039.2080305@redhat.com>
Download mbox | patch
Permalink /patch/90244/
State New
Headers show

Comments

Jason Merrill - April 8, 2011, 2:17 a.m.
constexpr fallout.  In fold_non_dependent_expr, we determined that the 
expression is not type-dependent, is potentially constant, and is not 
value-dependent, so we try to fold it.  But it isn't potentially 
constant.  So this patch fixes that determination.

Tested x86_64-pc-linux-gnu, applying to trunk and 4.6 (regression).
commit e49c0a722ad7226f7dabfc4a2fea9e47f8fc235f
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Apr 7 14:52:08 2011 -0400

    	PR c++/48500
    	* semantics.c (potential_constant_expression_1) [CALL_EXPR]: Check
    	arguments even if we don't know the function.

Patch

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 2184a53..0b4d1ec 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -7358,6 +7358,8 @@  potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
             class member access expression, including the result of the
             implicit transformation in the body of the non-static
             member function (9.3.1);  */
+      /* FIXME this restriction seems pointless since the standard dropped
+	 "potential constant expression".  */
       if (is_this_parameter (t))
         {
           if (flags & tf_error)
@@ -7373,51 +7375,63 @@  potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
       {
         tree fun = get_function_named_in_call (t);
         const int nargs = call_expr_nargs (t);
-        if (TREE_CODE (fun) != FUNCTION_DECL)
+	i = 0;
+
+	if (is_overloaded_fn (fun))
+	  {
+	    if (TREE_CODE (fun) == FUNCTION_DECL)
+	      {
+		if (builtin_valid_in_constant_expr_p (fun))
+		  return true;
+		if (!DECL_DECLARED_CONSTEXPR_P (fun)
+		    && !morally_constexpr_builtin_function_p (fun))
+		  {
+		    if (flags & tf_error)
+		      error ("%qD is not %<constexpr%>", fun);
+		    return false;
+		  }
+		/* A call to a non-static member function takes the address
+		   of the object as the first argument.  But in a constant
+		   expression the address will be folded away, so look
+		   through it now.  */
+		if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
+		    && !DECL_CONSTRUCTOR_P (fun))
+		  {
+		    tree x = get_nth_callarg (t, 0);
+		    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;
+		      }
+		    i = 1;
+		  }
+	      }
+	    else
+	      fun = get_first_fn (fun);
+	    /* Skip initial arguments to base constructors.  */
+	    if (DECL_BASE_CONSTRUCTOR_P (fun))
+	      i = num_artificial_parms_for (fun);
+	    fun = DECL_ORIGIN (fun);
+	  }
+	else
           {
 	    if (potential_constant_expression_1 (fun, rval, flags))
-	      /* Might end up being a constant function pointer.  */
-	      return true;
-            if (flags & tf_error)
-              error ("%qE is not a function name", fun);
-            return false;
-          }
-	/* Skip initial arguments to base constructors.  */
-	if (DECL_BASE_CONSTRUCTOR_P (fun))
-	  i = num_artificial_parms_for (fun);
-	else
-	  i = 0;
-	fun = DECL_ORIGIN (fun);
-        if (builtin_valid_in_constant_expr_p (fun))
-          return true;
-        if (!DECL_DECLARED_CONSTEXPR_P (fun)
-            && !morally_constexpr_builtin_function_p (fun))
-          {
-            if (flags & tf_error)
-              error ("%qD is not %<constexpr%>", fun);
-            return false;
+	      /* Might end up being a constant function pointer.  */;
+	    else
+	      {
+		if (flags & tf_error)
+		  error ("%qE is not a function name", fun);
+		return false;
+	      }
           }
         for (; i < nargs; ++i)
           {
             tree x = get_nth_callarg (t, i);
-            /* A call to a non-static member function takes the
-               address of the object as the first argument.
-               But in a constant expression the address will be folded
-	       away, so look through it now.  */
-            if (i == 0 && DECL_NONSTATIC_MEMBER_P (fun)
-                && !DECL_CONSTRUCTOR_P (fun))
-	      {
-		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;
-		  }
-              }
-	    else if (!potential_constant_expression_1 (x, rval, flags))
+	    if (!potential_constant_expression_1 (x, rval, flags))
 	      {
 		if (flags & tf_error)
 		  error ("argument in position %qP is not a "
diff --git a/gcc/testsuite/g++.dg/cpp0x/regress/call1.C b/gcc/testsuite/g++.dg/cpp0x/regress/call1.C
new file mode 100644
index 0000000..833318b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/regress/call1.C
@@ -0,0 +1,13 @@ 
+// PR c++/48500
+// { dg-options -std=c++0x }
+
+struct linked_ptr {
+};
+template <typename T> linked_ptr make_linked_ptr(T* ptr);
+struct Concrete;
+struct NewedClass {
+  NewedClass(const Concrete& req){}
+};
+template<typename ArgT> void AddObjToChange(const ArgT& req) {
+  linked_ptr p = make_linked_ptr(new NewedClass(req));
+}