14

Consider the following snippet:

int main() {
  struct Local {
    virtual void foo() = 0;
  };

  void (Local::* ptr)() = &Local::foo;
}

When compiling with C++20, GCC 13.3.0 and Clang 18.1.3 both compile this code, but MSVC 19.39 thru 19.43 generate the following compiler error:

<source>(3): error C3640: 'main::Local::[thunk]: __cdecl `int __cdecl main(void)'::`2'::Local::`vcall'{0,{flat}}' }'': a referenced or virtual member function of a local class must be defined

I could not find anything in the C++20 standard to prove either compiler right. Is the code snippet well-formed?

Example on Compiler Explorer

15
  • 1
    The only thing I can find in the standard (see 11.7.4 Abstract classes [class.abstract]) is that: A pure virtual function need be defined only if called with, or as if with (11.4.7), the qualified-id syntax (7.5.4.3). But you are not calling Local::foo here, so I'd say your code is fine. Having said that, you can make msvc happy by adding a definition for Local::foo (see [demo]).(godbolt.org/z/3rq4jqrTn)). Commented Oct 31 at 12:57
  • 2
    In your demo, the class is no longer local. If you remove the definition entirely but don't move the class back inside main(), MSVC doesn't begin complaining. Commented Oct 31 at 13:04
  • 2
    Pointers are just that, you can make them at any time. Dereferencing them and using the result is something else. As to the error, do you by any chance compile with /W4 (treat warnings as errors?) Commented Oct 31 at 14:48
  • 2
    A: Using std::thread to call an overriden method from a derived class suggests this code is okay, but without reference to the standard (i.e., not language-lawyer). If it turns out to be ill-formed (going back to C++11), a new answer to that question might be warranted (depending on details, of course). Commented Nov 1 at 1:32
  • 2
    MSVC permits virtual void foo() = 0 {} unlike other compilers: gcc.godbolt.org/z/dr8nh8nfn Commented Nov 1 at 20:42

1 Answer 1

4

I do not see anything in C++20 standard that makes the code in question ill-formed.

Microsoft admitted that it is a bug in the implementation of MSVC: https://developercommunity.visualstudio.com/t/Wrong-error-C3640-in-getting-a-pointer-o/10992438

And it is not hard to make the above program compile with MSVC by making member-function pointer not directly in the function containing the local class, but in some other function getFooPtr():

template<class T>
auto getFooPtr() {
    return &T::foo;
}

int main() {
  struct Local {
    virtual void foo() = 0;
  };

  void (Local::* ptr)() = getFooPtr<Local>();
  return ptr != nullptr;
}

Now the program is accepted in MSVC, as well as in GCC, Clang and EDG. Online demo: https://gcc.godbolt.org/z/cvPrn41b6

Sign up to request clarification or add additional context in comments.

3 Comments

The link to the bug report doesn't have a response from the MSVC team admitting it's a bug. Is that something visible only to you, or to someone with a Visual Studio account, or something like that?
Initially any MSVC bug report appear in the status "New". Then it changes to "Triaged" after first screening. And only after a professional from the compiler team checks (and admits) it, the status changes to "Under Consideration". However, a bug in this status can live for years.
Ah, I didn't know that "Under consideration" means a human looked at it and agrees it's a bug. Thanks, that means it's an MSVC bug (regardless of when/if they fix it).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.