Skip to content

Commit

Permalink
[C++20] [Modules] Allow ADL in dependent context for modules
Browse files Browse the repository at this point in the history
Close llvm/llvm-project#60488.

Previously, when we instantiate a template, the argument dependent
lookup is performed in the context of the instantiation, which implies that the
functions not visible in the context can't be found by the argument
dependent lookup.

But this is not true, according to [module.context]p3, the instantiation
context for the implicit instantiation of a template should contain the
context of the primary module interface if the template is defined in
the module interface unit.

Note that the fix didn't implemnet [module.context]p3 precisely, see the
comments for example.
  • Loading branch information
ChuanqiXu9 authored and CarlosAlbertoEnciso committed Feb 8, 2023
1 parent 4b4e8cf commit 3ce6686
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 3 deletions.
42 changes: 39 additions & 3 deletions clang/lib/Sema/SemaLookup.cpp
Expand Up @@ -3883,10 +3883,46 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
if (isVisible(D)) {
Visible = true;
break;
} else if (getLangOpts().CPlusPlusModules &&
D->isInExportDeclContext()) {
}

if (!getLangOpts().CPlusPlusModules)
continue;

// A partial mock implementation for instantiation context for
// modules. [module.context]p1:
// The instantiation context is a set of points within the program
// that determines which declarations are found by
// argument-dependent name lookup...
//
// FIXME: This didn't implement [module.context] well. For example,
// [module.context]p3 says:
// During the implicit instantiation of a template whose point of
// instantiation is specified as that of an enclosing
// specialization 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.
//
// But we didn't check if the template is defined in a module
// interface unit nor we check the context for the primary module
// interface.
Module *FM = D->getOwningModule();
if (FM && !FM->isHeaderLikeModule()) {
// LookupModules will contain all the modules we visited during the
// template instantiation (if any). And if LookupModules contains
// FM, the declarations in FM should be visible for the
// instantiation.
const auto &LookupModules = getLookupModules();
// Note: We can't use 'Module::isModuleVisible()' since that is for
// clang modules.
if (LookupModules.count(FM->getTopLevelModule())) {
Visible = true;
break;
}
}

if (D->isInExportDeclContext()) {
// C++20 [basic.lookup.argdep] p4.3 .. are exported ...
Module *FM = D->getOwningModule();
// exports are only valid in module purview and outside of any
// PMF (although a PMF should not even be present in a module
// with an import).
Expand Down
41 changes: 41 additions & 0 deletions clang/test/Modules/named-modules-adl-2.cppm
@@ -0,0 +1,41 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: cd %t
//
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=%t/a.pcm -emit-module-interface -o %t/b.pcm
// RUN: %clang_cc1 -std=c++20 %t/c.cppm -fmodule-file=%t/b.pcm -fsyntax-only -verify

//--- a.cppm
export module a;

export template<typename T>
void a(T x) {
+x;
}

//--- b.h
struct s {
};
void operator+(s) {
}

//--- b.cppm
module;
#include "b.h"
export module b;
import a;

export template<typename T>
void b() {
a(s());
}

//--- c.cppm
// expected-no-diagnostics
export module c;
import b;

void c() {
b<int>();
}
35 changes: 35 additions & 0 deletions clang/test/Modules/named-modules-adl.cppm
@@ -0,0 +1,35 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: cd %t
//
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=%t/a.pcm -fsyntax-only -verify

//--- a.h
namespace n {

struct s { };

void operator+(s, int) {
}

} // namespace n

//--- a.cppm
module;
#include "a.h"
export module a;

export template<typename T>
void a(T x) {
n::s() + x;
}

//--- b.cppm
// expected-no-diagnostics
export module b;
import a;

void b() {
a(0);
}

0 comments on commit 3ce6686

Please sign in to comment.