15 Commits

Author SHA1 Message Date
Chuanqi Xu
c5e4afe673
[C++20] [Modules] Support module level lookup (#122887) (#123281)
Close https://github.com/llvm/llvm-project/issues/90154

This patch is also an optimization to the lookup process to utilize the
information provided by `export` keyword.

Previously, in the lookup process, the `export` keyword only takes part
in the check part, it doesn't get involved in the lookup process. That
said, previously, in a name lookup for 'name', we would load all of
declarations with the name 'name' and check if these declarations are
valid or not. It works well. But it is inefficient since it may load
declarations that may not be wanted.

Note that this patch actually did a trick in the lookup process instead
of bring module information to DeclarationName or considering module
information when deciding if two declarations are the same. So it may
not be a surprise to me if there are missing cases. But it is not a
regression. It should be already the case. Issue reports are welcomed.

In this patch, I tried to split the big lookup table into a lookup table
as before and a module local lookup table, which takes a combination of
the ID of the DeclContext and hash value of the primary module name as
the key. And refactored `DeclContext::lookup()` method to take the
module information. So that a lookup in a DeclContext won't load
declarations that are local to **other** modules.

And also I think it is already beneficial to split the big lookup table
since it may reduce the conflicts during lookups in the hash table.

BTW, this patch introduced a **regression** for a reachability rule in
C++20 but it was false-negative. See
'clang/test/CXX/module/module.interface/p7.cpp' for details.

This patch is not expected to introduce any other
regressions for non-c++20-modules users since the module local lookup
table should be empty for them.
2025-01-17 13:41:44 +08:00
Chuanqi Xu
731db2a03e Revert "[C++20] [Modules] Support module level lookup (#122887)"
This reverts commit 7201cae106260aeb3e9bbbb7d5291ff30f05076a.
2025-01-16 10:23:11 +08:00
Chuanqi Xu
7201cae106
[C++20] [Modules] Support module level lookup (#122887)
Close https://github.com/llvm/llvm-project/issues/90154

This patch is also an optimization to the lookup process to utilize the
information provided by `export` keyword.

Previously, in the lookup process, the `export` keyword only takes part
in the check part, it doesn't get involved in the lookup process. That
said, previously, in a name lookup for 'name', we would load all of
declarations with the name 'name' and check if these declarations are
valid or not. It works well. But it is inefficient since it may load
declarations that may not be wanted.

Note that this patch actually did a trick in the lookup process instead
of bring module information to DeclarationName or considering module
information when deciding if two declarations are the same. So it may
not be a surprise to me if there are missing cases. But it is not a
regression. It should be already the case. Issue reports are welcomed.

In this patch, I tried to split the big lookup table into a lookup table
as before and a module local lookup table, which takes a combination of
the ID of the DeclContext and hash value of the primary module name as
the key. And refactored `DeclContext::lookup()` method to take the
module information. So that a lookup in a DeclContext won't load
declarations that are local to **other** modules.

And also I think it is already beneficial to split the big lookup table
since it may reduce the conflicts during lookups in the hash table.

BTW, this patch introduced a **regression** for a reachability rule in
C++20 but it was false-negative. See
'clang/test/CXX/module/module.interface/p7.cpp' for details.

This patch is not expected to introduce any other
regressions for non-c++20-modules users since the module local lookup
table should be empty for them.

---

On the API side, this patch unfortunately add a maybe-confusing argument
`Module *NamedModule` to
`ExternalASTSource::FindExternalVisibleDeclsByName()`. People may think
we can get the information from the first argument `const DeclContext
*DC`. But sadly there are declarations (e.g., namespace) can appear in
multiple different modules as a single declaration. So we have to add
additional information to indicate this.
2025-01-15 15:15:35 +08:00
Chuanqi Xu
82034aca30
[C++20] [Modules] Warn for importing implementation partition unit in interface units (#108493)
Recently, there are multiple false positive issue reports about the
reachability of implementation partition units:
- https://github.com/llvm/llvm-project/issues/105882
- https://github.com/llvm/llvm-project/issues/101348
- https://lists.isocpp.org/core/2024/08/16232.php

And according to our use experience for modules, we find it is a pretty
good practice to not import implementation partition units in the
interface units. It can help developers to have a pretty good mental
model for when to use an implementation partition unit: that any unit in
the module but not in the module interfaces can be in the implementation
partition unit.

So I think it is good to add the diagnostics.
2024-09-14 14:45:50 +08:00
Dmitry Polukhin
00fd188f37
[C++20][Modules] static data members of template classes should be allowed in header units (#98309)
Summary:
There is no sense to report these cases as an error or add `inline`
explicitly in these cases, if it is not required in normal headers.
Similar to #60079.

Test Plan: check-clang
2024-07-11 08:29:09 +01:00
Chuanqi Xu
0e7b30fa82 [C++20] [Modules] Enhance better diagnostic for implicit global module and module partitions
Due to an oversight, when users use an unexported declaration from
implicit global module, the diagnostic will show "please #include"
instead of "please import". This patch corrects the behavior.

Also previously, when users use an unexported declarations from module
partitions, the diagnostic message will always show the partition name
no matter if that partition name is visible to the users. Now the users
may only see the partition name if the users are in the same module with
the partition unit.
2023-11-10 10:58:07 +08:00
Iain Sandoe
b37233a253 [C++20][Modules] Complete implementation of module.import p7.
The following test fails to compile TU b.cpp because we are not making the transitively imported modules visible (per [module.import]/p7)

```
a.cppm:
export module a;

export int foo() {
   return 42;
}

b.cppm:
export module b;
import a;

export int bar();

b.cpp:
module b;

int bar() {
   return foo();
}

clang++ -c -std=c++2b -fmodule-output a.cppm
clang++ -c -std=c++2b -fmodule-output -fprebuilt-module-path=. b.cppm
clang++ -c -std=c++2b -fprebuilt-module-path=. b.cpp
b.cpp:4:12: error: declaration of 'foo' must be imported from module 'a' before it is required
   return foo();
```

This is fixed by the following patch (which also addresses a FIXME in basic.def.odr/p6.cppm).

Differential Revision: https://reviews.llvm.org/D152746
2023-06-25 08:33:39 +01:00
Iain Sandoe
cdd44e2c85 [C++20][Modules] Handle template declarations in header units.
This addresses part of https://github.com/llvm/llvm-project/issues/60079

The test for external functions was not considering function templates.

Differential Revision: https://reviews.llvm.org/D142704
2023-02-02 10:51:08 +00:00
Iain Sandoe
ff70e22f08 [C++20][Modules] Handle defaulted and deleted functions in header units.
Address part of https://github.com/llvm/llvm-project/issues/60079.

Deleted and Defaulted functions are implicitly inline, but that state
is not set at the point that we perform the diagnostic checks for externally-
visible non-inline functions; check the function body type explicitly in the
diagnostic.

Differential Revision: https://reviews.llvm.org/D141908
2023-01-21 12:55:52 +00:00
Chuanqi Xu
b3eb004ca7 [C++20] [Modules] Only diagnose the non-inline external variable
definitions in header units

Address part of https://github.com/llvm/llvm-project/issues/60079.

Since the the declaration of a non-inline static data member in its
class definition is not a definition. The following form:

```
class A {
public:
    static const int value = 43;
};
```

should be fine to appear in a header unit. From the perspective of
implementation, it looks like we simply forgot to check if the variable
is a definition...

Reviewed By: iains

Differential Revision: https://reviews.llvm.org/D141905
2023-01-17 17:48:09 +08:00
Iain Sandoe
335668b116 [C++20][Modules] Do not allow non-inline external definitions in header units.
[module.import/6] last sentence:
A header unit shall not contain a definition of a non-inline function or
variable whose name has external linkage.

Differential Revision: https://reviews.llvm.org/D140261
2023-01-08 12:19:23 +00:00
Chuanqi Xu
9c04851cf5 [C++20] [Module] Support reachable definition initially/partially
This patch introduces a new kind of ModuleOwnershipKind as
ReachableWhenImported. This intended the status for reachable described
at: https://eel.is/c++draft/module.reach#3.

Note that this patch is not intended to support all semantics about
reachable semantics. For example, this patch didn't implement discarded
declarations in GMF. (https://eel.is/c++draft/module.global.frag#3).

This fixes: https://bugs.llvm.org/show_bug.cgi?id=52281 and
https://godbolt.org/z/81f3ocjfW.

Reviewed By: rsmith, iains

Differential Revision: https://reviews.llvm.org/D113545
2022-06-29 12:48:48 +08:00
Chuanqi Xu
7a541406b5 Revert "[C++20] [Modules] Implement Reachable initiallly"
This reverts commit a223ba0a697c1598b434cf2495c9cd9ec5640fc7.

The previous commit don't contain additional information, which is bad.
2022-06-29 12:43:26 +08:00
Chuanqi Xu
a223ba0a69 [C++20] [Modules] Implement Reachable initiallly 2022-06-29 12:32:31 +08:00
Chuanqi Xu
ce2257d69f [C++20] [Modules] Judge current module correctly
Now the implementation would accept following code:
```
//--- impl.cppm
module M:impl;
class A {};

//--- M.cppm
export module M;
import :impl;

//--- Use.cpp
import M;
void test() {
    A a; // Expected error. A is not visible here.
}
```

which is clearly wrong.  The root cause is the implementation of
`isInCurrentModule` would return true if the module is a partition! So
in the above example, although Use.cpp is not a module unit,
`isInCurrentModule ` would still return true when the compiler tries to
see if the owning module of `A` is the current module. I believe this is
an oversight. This patch tries to fix this problem.

Reviewed By: iains

Differential Revision: https://reviews.llvm.org/D123837
2022-04-21 11:09:55 +08:00