The SFINAE code in composite_pointer_type_r correctly avoids giving an
error in SFINAE context, but then it just uses the permissive fallback
without indicating to the caller that there was an error, so we get
wrong results. This patch fixes it to return error_mark_node when we
see an error.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 8b4f0e86bd63184f63ec3ca0e6960ea9d88f90fa
Author: Jason Merrill <ja...@redhat.com>
Date: Sun May 22 01:15:13 2011 -0400
PR c++/48647
* typeck.c (composite_pointer_type_r): Return error_mark_node
on error in SFINAE context.
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 7791efc..dd1cc3b 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -516,7 +516,8 @@ composite_pointer_type_r (tree t1, tree t2,
{
if (complain & tf_error)
composite_pointer_error (DK_PERMERROR, t1, t2, operation);
-
+ else
+ return error_mark_node;
result_type = void_type_node;
}
result_type = cp_build_qualified_type (result_type,
@@ -527,9 +528,13 @@ composite_pointer_type_r (tree t1, tree t2,
if (TYPE_PTR_TO_MEMBER_P (t1))
{
if (!same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
- TYPE_PTRMEM_CLASS_TYPE (t2))
- && (complain & tf_error))
- composite_pointer_error (DK_PERMERROR, t1, t2, operation);
+ TYPE_PTRMEM_CLASS_TYPE (t2)))
+ {
+ if (complain & tf_error)
+ composite_pointer_error (DK_PERMERROR, t1, t2, operation);
+ else
+ return error_mark_node;
+ }
result_type = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
result_type);
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae23.C b/gcc/testsuite/g++.dg/cpp0x/sfinae23.C
new file mode 100644
index 0000000..4e2ea88
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae23.C
@@ -0,0 +1,28 @@
+// PR c++/48647
+// { dg-options -std=c++0x }
+
+template< class T >
+T&& declval();
+
+template< class T, class U >
+decltype( true ? declval<T>() : declval<U>() ) test( int );
+
+template< class T, class U >
+void test( ... );
+
+
+template< class T, class U >
+struct is_same {
+ static const bool value = false;
+};
+
+template< class T >
+struct is_same<T, T> {
+ static const bool value = true;
+};
+
+#define SA(X) static_assert ((X),#X)
+
+typedef decltype( test<int*, double*>(0) ) void_expected;
+SA ((is_same<void_expected, void>::value));
+SA ((!is_same<void_expected, void*>::value));
diff --git a/gcc/testsuite/g++.dg/template/sfinae8.C b/gcc/testsuite/g++.dg/template/sfinae8.C
index 2ad68dc..5ac09c6 100644
--- a/gcc/testsuite/g++.dg/template/sfinae8.C
+++ b/gcc/testsuite/g++.dg/template/sfinae8.C
@@ -120,7 +120,7 @@ STATIC_ASSERT((!is_equality_comparable<Y, X>::value));
STATIC_ASSERT((!is_equality_comparable<Y>::value));
STATIC_ASSERT((is_equality_comparable<int X::*>::value));
STATIC_ASSERT((!is_equality_comparable<int X::*, int Y::*>::value));
-STATIC_ASSERT((is_equality_comparable<int*, float*>::value));
+STATIC_ASSERT((!is_equality_comparable<int*, float*>::value));
STATIC_ASSERT((is_equality_comparable<X*, Z*>::value));
STATIC_ASSERT((!is_equality_comparable<X*, Y*>::value));
@@ -139,7 +139,7 @@ STATIC_ASSERT((!is_not_equal_comparable<Y, X>::value));
STATIC_ASSERT((!is_not_equal_comparable<Y>::value));
STATIC_ASSERT((is_not_equal_comparable<int X::*>::value));
STATIC_ASSERT((!is_not_equal_comparable<int X::*, int Y::*>::value));
-STATIC_ASSERT((is_not_equal_comparable<int*, float*>::value));
+STATIC_ASSERT((!is_not_equal_comparable<int*, float*>::value));
STATIC_ASSERT((is_not_equal_comparable<X*, Z*>::value));
STATIC_ASSERT((!is_not_equal_comparable<X*, Y*>::value));