Bug 92735 - unused member variable causes code to compile for member to function for undefined function
Summary: unused member variable causes code to compile for member to function for unde...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: accepts-invalid
Depends on:
Blocks:
 
Reported: 2019-11-30 00:58 UTC by Marc Pawlowsky
Modified: 2020-01-30 12:07 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-01-30 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Marc Pawlowsky 2019-11-30 00:58:05 UTC
Marc Pawlowsky <marcpawl@gmail.com>
Thu, Nov 28, 8:25 PM (23 hours ago)
to gcc-bugzilla-account-request

https://godbolt.org/z/SFZmZJ

In clang you get 
no member names 'hello' in 'Bad'
which is the expected result.

In all GCC versions using --std=c++17 from 5.2 onwards the code compiles.

#include <type_traits>
#include <cstdio>
struct Foo {
virtual void hello(int) = 0;
};

struct Bar : public Foo {
void hello(int) override {};
};

struct Bad { };

template <typename T>
struct is_Foo {
using hello_fn_t = void (T::*)(int);
constexpr static void (T::*hello)(int) = &T::hello;
static constexpr bool value=true;
};

template <typename T>
auto say(T& t) -> std::enable_if_t<is_Foo<T>::value, void>{
//U u; // Line 22
//t.hello(4); // Line 23
puts("hello\n");
}

int main()
{
//Bar b;;
//Foo& f = b;
//say(b);
//say(f);
Bad bad;
say(bad);
}

If you change say to
template <typename T, typename U=is_Foo<T>>
void say(T& t)
{
    U u; // Line 22
    //t.hello(4); // Line 23
}
you get the same errors in clang, but no errors in gcc.

== 
on a related not I sent to clang bug report where if value is not static the code will compile.
Comment 1 Jonathan Wakely 2019-12-03 10:06:55 UTC
(In reply to Marc Pawlowsky from comment #0)
> on a related not I sent to clang bug report where if value is not static the
> code will compile.

https://bugs.llvm.org/show_bug.cgi?id=44175 (I think that's not a bug).
Comment 2 Jonathan Wakely 2019-12-03 10:18:00 UTC
For the case reported here, Clang and EDG do reject it, but I'm not yet convinced GCC is wrong to accept it.

The implicit instantiation of is_Foo<Bad> causes:

"the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends;"

and:

"in particular, the initialization (and any associated side effects) of a
static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist."

Nothing requires the instantiation of is_Foo<Bad>::hello.
Comment 3 Jonathan Wakely 2019-12-03 19:43:56 UTC
Related to http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1396
Comment 4 Marc Pawlowsky 2019-12-04 03:00:45 UTC
(In reply to Jonathan Wakely from comment #2)
> For the case reported here, Clang and EDG do reject it, but I'm not yet
> convinced GCC is wrong to accept it.
> 
> The implicit instantiation of is_Foo<Bad> causes:
> 
> "the implicit instantiation of the declarations, but not of the definitions,
> of the non-deleted class member functions, member classes, scoped member
> enumerations, static data members, member templates, and friends;"
> 
> and:
> 
> "in particular, the initialization (and any associated side effects) of a
> static data member does not occur unless the static data member is itself
> used in a way that requires the definition of the static data member to
> exist."
> 
> Nothing requires the instantiation of is_Foo<Bad>::hello.

FYI, Forcing the use of hello does cause a compile time error.
template <typename T>
struct is_Foo {
    using hello_fn_t = void (T::*)(int);
    constexpr static void (T::*hello)(int) = &T::hello;
    static constexpr bool value=(!!hello);
};
source>:16:46: error: 'hello' is not a member of 'Bad'

   16 |     constexpr static void (T::*hello)(int) = &T::hello;