Bug 87748 - [8 Regression] G++-8 treats SFINAE as error
Summary: [8 Regression] G++-8 treats SFINAE as error
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 8.1.1
: P2 normal
Target Milestone: 8.4
Assignee: Jason Merrill
URL:
Keywords: rejects-valid
: 90080 (view as bug list)
Depends on:
Blocks:
 
Reported: 2018-10-25 11:03 UTC by Tim Janik
Modified: 2019-04-16 14:45 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work: 7.3.0
Known to fail: 8.2.0
Last reconfirmed: 2019-04-16 00:00:00


Attachments
g++-8 SFINAE Error Test Case (1.01 KB, text/x-csrc)
2018-10-25 11:03 UTC, Tim Janik
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Tim Janik 2018-10-25 11:03:05 UTC
Created attachment 44897 [details]
g++-8 SFINAE Error Test Case

The following (reduced) code example uses SFINAE to discern argument types in a visitor pattern. The original bug report is here: https://github.com/tim-janik/beast/issues/72#issuecomment-432874963

It works well under clang-6 and g++-7.3. With g++-8.1.1 (and reportedly g++-8.2.1) a template substitution failure during a method presence check on std::string is promoted to an error, even though a std::false_type substitution variant exists that should be picked up instead.

Not only do other compiler (versions) compile this correctly, but duplicating a seemingly unrelated static_assert in the code also "remedies" the g++-8 treatment of the failure as error, tested via -DWITHASSERT below.

EXPECTED:

$ g++ --version
g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0

$ g++ -std=gnu++14 -Wall -O2 aidavisit.cc && ./a.out 
visit_string: some_string="A std::string"

BUGGY BEHAVIOUR:

$ g++ --version
g++ (GCC) 8.1.1 20180712 (Red Hat 8.1.1-5)

$ g++ -std=gnu++14 -Wall -O2 aidavisit.cc && ./a.out 
aidavisit.cc:19:77: error: 'class std::__cxx11::basic_string<char>' has no member named '__aida_visit__'

$ g++ -std=gnu++14 -Wall -O2 aidavisit.cc -DWITHASSERT && ./a.out 
visit_string: some_string="A std::string"
Comment 1 Jonathan Wakely 2018-10-25 11:13:36 UTC
This regressed with r258824

            PR c++/78489 - wrong SFINAE behavior.
    
            PR c++/84489
            * pt.c (type_unification_real): Don't defer substitution failure.
Comment 2 Jakub Jelinek 2019-02-22 15:20:11 UTC
GCC 8.3 has been released.
Comment 3 Jason Merrill 2019-03-25 18:27:39 UTC
Author: jason
Date: Mon Mar 25 18:27:08 2019
New Revision: 269921

URL: https://gcc.gnu.org/viewcvs?rev=269921&root=gcc&view=rev
Log:
	PR c++/87748 - substitution failure error with decltype.

This issue is similar to PR 87480; in both cases we were doing non-dependent
substitution with processing_template_decl set, leading to member access
expressions seeming still instantiation-dependent, and therefore decltype
not being simplified to its actual type.  And as in that PR, the fix is to
clear processing_template_decl while substituting a default template
argument.

	* pt.c (most_specialized_partial_spec): Clear
	processing_template_decl.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/sfinae64.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/pt.c
Comment 4 Jason Merrill 2019-03-25 18:27:59 UTC
Fixed on trunk so far.
Comment 5 Jonathan Wakely 2019-04-16 14:43:49 UTC
*** Bug 90080 has been marked as a duplicate of this bug. ***
Comment 6 Jonathan Wakely 2019-04-16 14:45:29 UTC
Another reproducer from PR 90080:

struct false_type { static constexpr bool value = false; };
struct true_type { static constexpr bool value = true; };
template<bool, typename = void> struct enable_if { };
template<typename T> struct enable_if<true, T> { using type = T; };
template<typename T> T&& declval();

template<typename T, typename U, typename = U>
struct is_static_castable : false_type
{};

template<typename T, typename U>
struct is_static_castable<T, U, decltype(static_cast<U>(declval<T>()))> : true_type
{};

template<typename To, typename From, typename enable_if<is_static_castable<From*, To*>::value, int>::type = 0>
To* safePtrCast(From* from)
{
    return static_cast<To*>(from);
}

template<typename To, typename From, typename enable_if<!is_static_castable<From*, To*>::value, int>::type = 0>
To* safePtrCast(From* from)
{
    return dynamic_cast<To*>(from);
}

struct BarBase{ virtual ~BarBase() = default;};
struct Bar : virtual BarBase{};

Bar* foo(BarBase* b){
    return safePtrCast<Bar>(b);
}


90080.cc: In instantiation of ‘struct is_static_castable<BarBase*, Bar*, Bar*>’:
90080.cc:21:57:   required by substitution of ‘template<class To, class From, typename enable_if<(! is_static_castable<From*, To*>::value), int>::type <anonymous> > To* safePtrCast(From*) [with To = Bar; From = BarBase; typename enable_if<(! is_static_castable<From*, To*>::value), int>::type <anonymous> = <missing>]’
90080.cc:31:30:   required from here
90080.cc:12:42: error: cannot convert from pointer to base class ‘BarBase’ to pointer to derived class ‘Bar’ because the base is virtual
   12 | struct is_static_castable<T, U, decltype(static_cast<U>(declval<T>()))> : true_type
      |                                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
90080.cc:12:42: error: cannot convert from pointer to base class ‘BarBase’ to pointer to derived class ‘Bar’ because the base is virtual
90080.cc: In instantiation of ‘To* safePtrCast(From*) [with To = Bar; From = BarBase; typename enable_if<is_static_castable<From*, To*>::value, int>::type <anonymous> = 0]’:
90080.cc:31:30:   required from here
90080.cc:18:12: error: cannot convert from pointer to base class ‘BarBase’ to pointer to derived class ‘Bar’ because the base is virtual
   18 |     return static_cast<To*>(from);
      |            ^~~~~~~~~~~~~~~~~~~~~~