Patchwork C++ PATCH for c++/44967 (sfinae and variadic templates)

login
register
mail settings
Submitter Jason Merrill
Date July 20, 2010, 6:22 p.m.
Message ID <4C45E974.7090802@redhat.com>
Download mbox | patch
Permalink /patch/59351/
State New
Headers show

Comments

Jason Merrill - July 20, 2010, 6:22 p.m.
This testcase was running into problems because we were effectively 
assuming that when we tsubst into a CALL_EXPR we're producing a 
non-dependent result.  This is not the case in this testcase, where we 
do a partial substitution of the explicit template args but can deduce 
more from the function arguments.

Fixed by adding early exit as in cp_parser_postfix_expression.

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

Patch

2010-07-20  Jason Merrill  <jason@redhat.com>

	PR c++/44967
	* pt.c (tsubst_copy_and_build): Rework last change.

	PR c++/44967
	* pt.c (tsubst_copy_and_build): Handle partial substitution of
	CALL_EXPR.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 0ccd8d9..b618907 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12531,15 +12531,24 @@  tsubst_copy_and_build (tree t,
 	  ret = build_offset_ref_call_from_tree (function, &call_args);
 	else if (TREE_CODE (function) == COMPONENT_REF)
 	  {
-	    if (!BASELINK_P (TREE_OPERAND (function, 1)))
+	    tree instance = TREE_OPERAND (function, 0);
+	    tree fn = TREE_OPERAND (function, 1);
+
+	    if (processing_template_decl
+		&& (type_dependent_expression_p (instance)
+		    || (!BASELINK_P (fn)
+			&& TREE_CODE (fn) != FIELD_DECL)
+		    || type_dependent_expression_p (fn)
+		    || any_type_dependent_arguments_p (call_args)))
+	      ret = build_nt_call_vec (function, call_args);
+	    else if (!BASELINK_P (fn))
 	      ret = finish_call_expr (function, &call_args,
 				       /*disallow_virtual=*/false,
 				       /*koenig_p=*/false,
 				       complain);
 	    else
 	      ret = (build_new_method_call
-		      (TREE_OPERAND (function, 0),
-		       TREE_OPERAND (function, 1),
+		      (instance, fn,
 		       &call_args, NULL_TREE,
 		       qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL,
 		       /*fn_p=*/NULL,
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae2.C b/gcc/testsuite/g++.dg/cpp0x/sfinae2.C
new file mode 100644
index 0000000..b9ef70d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae2.C
@@ -0,0 +1,39 @@ 
+// PR c++/44967
+// { dg-options -std=c++0x }
+
+template <typename T> T&& declval();
+
+template<typename T1, typename T2, typename... Args>
+struct has_construct
+{
+    typedef char one;
+    typedef struct {char _m[2]; } two;
+
+    template<typename U1, typename U2, typename... Args2>
+    static decltype(declval<U1>().construct(declval<U2*>(), declval<Args2>()...), one()) test(int);
+    template<typename, typename, typename...>
+    static two test(...);
+
+    static const bool value = sizeof(test<T1, T2, Args...>(0)) == 1;
+};
+
+
+struct A0
+{};
+
+struct A1
+{
+    void construct(int*, int);
+};
+
+template<typename _Tp>
+struct A2
+{
+  template<typename _Tp1, typename... _Args>
+  void construct(_Tp1*, _Args&&...) {}
+};
+
+#define SA(X) static_assert(X,#X)
+SA((!has_construct<A0, int, int>::value)); // ok
+SA((has_construct<A1, int, int>::value)); // bang
+SA((has_construct<A2<int>, int>::value)); // bang