llvm / llvm/llvm-project

[C++ Modules] Access control failure: Exported template calling non-exported friend function template

Open
#174,769 2 comments 0 reactions 1 assignee Claimed by @ChuanqiXu9 View on GitHub
clang:modules
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

**Description:**
I have encountered a bug where Clang fails to respect a `friend` declaration when the friend function is a **non-exported template** called by an **exported template** within the same module.

When the exported template (`Func2`) is instantiated from an external consumer (e.g., `main`), it calls the internal friend function (`Func1`). Clang correctly finds `Func1` but fails the access check for the private constructor it attempts to access, acting as if the friendship does not exist.

**Variations observed:**

* **Fails:** `Func1` is *not exported* + `Func2` *is a template* (The reproduction below).
* **Works:** If `Func1` is also `export`ed.
* **Works:** If `Func2` is a regular function (not a template).

**Environment:**

* **Compiler:** Clang 21.1.8
* **Target:** x86_64-pc-windows-msvc
* **Standard:** `-std=c++26`

**Reproduction:**

**`L1.cppm`**

```cpp
module;
export module L1;

template
class Class
{
// Friend declaration
template friend void Func1();
Class() {}; // Private constructor
};

// Non-exported friend function template
template
void Func1()
{
// Should have access to Class private constructor
Class();
}

// Exported interface template
export template
void Func2()
{
// Calls the non-exported friend
Func1<0>();
};

```

**`main.cpp`**

```cpp
import L1;

int main()
{
// Triggers instantiation of Func2, which calls Func1
Func2<0>();
}

```

**Compilation Command:**

```cmd
clang++ -std=c++26 --precompile -x c++-module L1.cppm -o L1.pcm
clang++ -std=c++26 main.cpp -fmodule-file=L1=L1.pcm -o test.exe

```

**Actual Results (Error Log):**

```text
In file included from main.cpp:1:
L1.cppm:15:2: error: calling a private constructor of class 'Class<0>'
15 | Class();
| ^
L1.cppm:21:2: note: in instantiation of function template specialization 'Func1<0>' requested here
21 | Func1<0>();
| ^
main.cpp:5:2: note: in instantiation of function template specialization 'Func2<0>' requested here
5 | Func2<0>();
| ^
L1.cppm:8:2: note: implicitly declared private here
8 | Class() {};
| ^
1 error generated.

```

**Expected Results:**
The code should compile successfully. `Func1` is defined in the same module unit as `Class` and is explicitly declared as a friend. The fact that `Func2` is a template instantiated from outside the module should not break the visibility of the friendship inside `L1`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.