public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/101140] New: [modules] no matching function for call to ‘operator new(sizetype, void*)’
@ 2021-06-20 14:52 ensadc at mailnesia dot com
  2021-09-06 11:05 ` [Bug c++/101140] " ensadc at mailnesia dot com
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: ensadc at mailnesia dot com @ 2021-06-20 14:52 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101140

            Bug ID: 101140
           Summary: [modules] no matching function for call to ‘operator
                    new(sizetype, void*)’
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ensadc at mailnesia dot com
  Target Milestone: ---

$ cat new.hpp
extern "C++" {
void* operator new(__SIZE_TYPE__, void* p);
}

$ cat foo.cpp
module;
#include "new.hpp"
export module foo;

export template<class T>
T* construct_at(T* p) {
    return ::new((void*)p) T();
}

$ cat bar.cpp
export module bar;

import foo;

void f(int* p) {
    construct_at(p);
}

$ g++ -std=c++20 -fmodules-ts -c foo.cpp
$ g++ -std=c++20 -fmodules-ts -c bar.cpp
In module foo, imported at bar.cpp:3:
foo.cpp: In instantiation of ‘T* construct_at@foo(T*) [with T = int]’:
bar.cpp:6:17:   required from here
foo.cpp:7:12: error: no matching function for call to ‘operator new(sizetype,
void*)’
    7 |     return ::new((void*)p) T();
      |            ^~~~~~~~~~~~~~~~~~~
<built-in>: note: candidate: ‘void* operator new(long unsigned int)’
<built-in>: note:   candidate expects 1 argument, 2 provided
<built-in>: note: candidate: ‘void* operator new(long unsigned int,
std::align_val_t)’
<built-in>: note:   no known conversion for argument 2 from ‘void*’ to
‘std::align_val_t’
bar.cpp:1:8: warning: not writing module ‘bar’ due to errors
    1 | export module bar;
      |        ^~~~~~

====

The error disappears if "new.hpp" is included or imported in `bar.cpp`.

I originally encountered this problem when using `std::construct_at` (defined
in`<memory>`) in a module.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug c++/101140] [modules] no matching function for call to ‘operator new(sizetype, void*)’
  2021-06-20 14:52 [Bug c++/101140] New: [modules] no matching function for call to ‘operator new(sizetype, void*)’ ensadc at mailnesia dot com
@ 2021-09-06 11:05 ` ensadc at mailnesia dot com
  2022-02-11 12:31 ` asynts+bugs at gmail dot com
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: ensadc at mailnesia dot com @ 2021-09-06 11:05 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101140

--- Comment #1 from ensadc at mailnesia dot com ---
https://godbolt.org/z/EaPf3anxx

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug c++/101140] [modules] no matching function for call to ‘operator new(sizetype, void*)’
  2021-06-20 14:52 [Bug c++/101140] New: [modules] no matching function for call to ‘operator new(sizetype, void*)’ ensadc at mailnesia dot com
  2021-09-06 11:05 ` [Bug c++/101140] " ensadc at mailnesia dot com
@ 2022-02-11 12:31 ` asynts+bugs at gmail dot com
  2024-03-26 13:54 ` nshead at gcc dot gnu.org
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: asynts+bugs at gmail dot com @ 2022-02-11 12:31 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101140

Paul Scharnofske <asynts+bugs at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |asynts+bugs at gmail dot com

--- Comment #2 from Paul Scharnofske <asynts+bugs at gmail dot com> ---
I had a very similar problem:

```c++
// foo.cpp
export module foo;

using size_t = decltype(sizeof(int));

void* operator new(size_t, void *pointer) {
    return pointer;
}

export
template<typename T>
void foo() {
    T t;
    new (&t) T;
}
```
```c++
// bar.cpp
export module bar;

import foo;

void bar() {
    foo<int>();
}
```
```c++
// main.cpp
export module main;

import foo;
import bar;

int main() {

}
```
```none
$ ~/.local/lib/gcc-trunk/bin/g++ --version
g++ (GCC) 12.0.1 20220211 (experimental)
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ ~/.local/lib/gcc-trunk/bin/g++ -Wall -Wextra -std=c++20 -fmodules-ts foo.cpp
bar.cpp main.cpp
In module foo, imported at bar.cpp:4:
foo.cpp: In instantiation of 'void foo@foo() [with T = int]':
bar.cpp:7:13:   required from here
foo.cpp:14:5: error: no matching function for call to 'operator new(sizetype,
int*)'
   14 |     new (&t) T;
      |     ^~~~~~~~~~
<built-in>: note: candidate: 'void* operator new(long unsigned int)'
<built-in>: note:   candidate expects 1 argument, 2 provided
<built-in>: note: candidate: 'void* operator new(long unsigned int,
std::align_val_t)'
<built-in>: note:   no known conversion for argument 2 from 'int*' to
'std::align_val_t'
bar.cpp:2:8: warning: not writing module 'bar' due to errors
    2 | export module bar;
      |        ^~~~~~
In module imported at main.cpp:5:1:
bar: error: failed to read compiled module: No such file or directory
bar: note: compiled module file is 'gcm.cache/bar.gcm'
bar: note: imports must be built before being imported
bar: fatal error: returning to the gate for a mechanical issue
compilation terminated.
```
https://godbolt.org/z/es5he4hc4

It appears that the compiler tries to lookup the placement new operator in the
module
where the template instantiation happens.
In my mind, the correct behavior would be to look this up in the module where
the
template is defined.
However, I am not familiar with the standard.

There are several ways, this code can be changed to work:

 1. Add 'export' to the 'operator new'.
    However, this requires that the module that defines the operator new is
imported
    by the module directly.
    https://godbolt.org/z/nxY681PeK

 2. Remove the template parameter from 'foo'.
    https://godbolt.org/z/1T9Erjdz3

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug c++/101140] [modules] no matching function for call to ‘operator new(sizetype, void*)’
  2021-06-20 14:52 [Bug c++/101140] New: [modules] no matching function for call to ‘operator new(sizetype, void*)’ ensadc at mailnesia dot com
  2021-09-06 11:05 ` [Bug c++/101140] " ensadc at mailnesia dot com
  2022-02-11 12:31 ` asynts+bugs at gmail dot com
@ 2024-03-26 13:54 ` nshead at gcc dot gnu.org
  2024-03-26 14:50 ` ppalka at gcc dot gnu.org
  2024-03-26 23:54 ` nshead at gcc dot gnu.org
  4 siblings, 0 replies; 6+ messages in thread
From: nshead at gcc dot gnu.org @ 2024-03-26 13:54 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101140

Nathaniel Shead <nshead at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |NEW
     Ever confirmed|0                           |1
                 CC|                            |nshead at gcc dot gnu.org
   Last reconfirmed|                            |2024-03-26

--- Comment #3 from Nathaniel Shead <nshead at gcc dot gnu.org> ---
I believe this should be valid. The declaration of `::operator new` should be
reachable within the instantiation context of 'construct_at' , and thus
shouldn't need to be exported to be called. (See [module.context] and
[module.reach].)

The issue looks to be that `tsubst_expr` when handling a NEW_EXPR just calls
`build_new`, which ultimately does `build_operator_new_call` that uses normal
`lookup_qualified_name (global_namespace, fnname)` that doesn't consider
non-exported entities. We need some way to signify that lookup should also
consider declarations reachable from other points in the template's
instantiation context.

This could be related to one of the issues causing PR114275, but in that cases
it's failing to find instantiations of friend classes in the instantiation
context.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug c++/101140] [modules] no matching function for call to ‘operator new(sizetype, void*)’
  2021-06-20 14:52 [Bug c++/101140] New: [modules] no matching function for call to ‘operator new(sizetype, void*)’ ensadc at mailnesia dot com
                   ` (2 preceding siblings ...)
  2024-03-26 13:54 ` nshead at gcc dot gnu.org
@ 2024-03-26 14:50 ` ppalka at gcc dot gnu.org
  2024-03-26 23:54 ` nshead at gcc dot gnu.org
  4 siblings, 0 replies; 6+ messages in thread
From: ppalka at gcc dot gnu.org @ 2024-03-26 14:50 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101140

Patrick Palka <ppalka at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jason at gcc dot gnu.org,
                   |                            |ppalka at gcc dot gnu.org

--- Comment #4 from Patrick Palka <ppalka at gcc dot gnu.org> ---
FWIW I was thinking we might want to perform two-phase name lookup for
new-expressions like we do for other operator expressions, wherein unqualified
lookup is performed at template definition time, saved inside the expression
(via DEPENDENT_OPERATOR_TYPE) and then reused at instantiation time.

But name lookup for a new-expression doesn't do unqualified lookup, it does
qualified lookup in the global namespace ::.  And unlike true two-phase name
lookup which prevents operator overloads declared after the template definition
from being considered, it seems GCC/Clang/MSVC all consider later-declared
global operator new declarations during instantiation of a new-expression:
https://godbolt.org/z/o6r9MYbKc.

So it seems two-phase name lookup isn't appropriate for new-expressions, and
something like your idea is the way to go?  I wonder what Jason thinks.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug c++/101140] [modules] no matching function for call to ‘operator new(sizetype, void*)’
  2021-06-20 14:52 [Bug c++/101140] New: [modules] no matching function for call to ‘operator new(sizetype, void*)’ ensadc at mailnesia dot com
                   ` (3 preceding siblings ...)
  2024-03-26 14:50 ` ppalka at gcc dot gnu.org
@ 2024-03-26 23:54 ` nshead at gcc dot gnu.org
  4 siblings, 0 replies; 6+ messages in thread
From: nshead at gcc dot gnu.org @ 2024-03-26 23:54 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101140

--- Comment #5 from Nathaniel Shead <nshead at gcc dot gnu.org> ---
(In reply to Patrick Palka from comment #4)
> FWIW I was thinking we might want to perform two-phase name lookup for
> new-expressions like we do for other operator expressions, wherein
> unqualified lookup is performed at template definition time, saved inside
> the expression (via DEPENDENT_OPERATOR_TYPE) and then reused at
> instantiation time.

I actually wonder if this is even correct. [basic.argdep.lookup] p4 says:

> If the lookup is for a dependent name ([temp.dep], [temp.dep.candidate]), the
> above lookup is also performed from each point in the instantiation context
> ([module.context]) of the lookup, additionally ignoring any declaration that
> appears in another translation unit, is attached to the global module, and is
> either discarded ([module.global.frag]) or has internal linkage.

And the instantiation context is defined to include ([module.context] p3):

> ...if the template is defined in a module interface unit of a module M and
> the point of instantiation is not in a module interface unit of M, the point
> at the end of the declaration-seq of the primary module interface unit of M
> (prior to the private-module-fragment, if any).

Which implies to me that the following sample should work:

  export module M;

  export template <typename T>
  void f(T t) { g(t); }

  namespace ns {
    export struct X {};
    void g(X);
  }

//

  import M;
  int main() {
    f(ns::X{});  // should compile?
  }

but we currently error. Whether this is a sensible thing to support is another
question...

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-03-26 23:54 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-20 14:52 [Bug c++/101140] New: [modules] no matching function for call to ‘operator new(sizetype, void*)’ ensadc at mailnesia dot com
2021-09-06 11:05 ` [Bug c++/101140] " ensadc at mailnesia dot com
2022-02-11 12:31 ` asynts+bugs at gmail dot com
2024-03-26 13:54 ` nshead at gcc dot gnu.org
2024-03-26 14:50 ` ppalka at gcc dot gnu.org
2024-03-26 23:54 ` nshead at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).