[Clang][Windows] Nested class templates are not checked for multiple exported default constructors
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Under the Microsoft ABI, Clang emits a default constructor closure for an
exported constructor that can be called with an empty argument list. Clang
therefore rejects classes with more than one exported default constructor using
`err_attribute_dll_ambiguous_default_ctor`.
During parsing, `checkForMultipleExportedDefaultConstructors` is called for the
enclosing non-nested class, but it does not visit nested class templates. It is
also not called when a nested class template is instantiated. As a result,
Clang incorrectly accepts specializations containing multiple exported default
constructors and fails to emit the expected diagnostic.
For example:
```cpp
struct Outer {
template
struct Nested {
__declspec(dllexport) Nested(int = 0) {}
__declspec(dllexport) Nested(double = 0) {}
};
};
template struct Outer::Nested;
```
Clang currently accepts this specialization without diagnosing that both
constructors are exported and callable with an empty argument list.
## Why the check must run during instantiation
Calling `checkForMultipleExportedDefaultConstructors` on only the dependent
template pattern during parsing would be insufficient.
### Parameter packs
Clang cannot determine whether a constructor can be called with an empty
argument list until the class template is instantiated and the parameter pack
is expanded:
```cpp
struct Outer {
template
struct Nested {
__declspec(dllexport) Nested(T..., int x = 10) {}
};
};
Outer::Nested<> a; // Callable with an empty argument list.
Outer::Nested b{1}; // Not callable with an empty argument list.
```
### Constraints
Constructors with failed `requires` clauses must not participate in the
multiple-exported-default-constructor check:
```cpp
template
concept Small = sizeof(T) == 1;
struct Outer {
template
struct Nested {
__declspec(dllexport) Nested() requires Small {}
__declspec(dllexport) Nested(int = 0) {}
};
};
Outer::Nested value;
```
For `Nested`, the constrained constructor is not viable and should not
cause an ambiguous exported-default-constructor diagnostic.
### Constructor closure default arguments
Default arguments required by Microsoft ABI constructor closures must also be
instantiated for the concrete class specialization:
```cpp
struct HasDtor {
~HasDtor();
int value;
};
struct HasImplicitDtor {
HasDtor value;
};
struct Outer {
template
struct Nested {
__declspec(dllexport) Nested(const T &value = {}) {}
};
};
Outer::Nested value{{}};
```
## Expected behavior
For each fully non-dependent nested class-template specialization, Clang should:
1. Determine which exported constructors can be called with an empty argument
list after template instantiation.
2. Exclude constructors with failed `requires` clauses.
3. Diagnose multiple eligible exported default constructors.
4. Instantiate default arguments required by Microsoft ABI constructor
closures.
## Possible implementation direction
- Skip the parse-time check when the class is dependent.
- During instantiation, call `checkForMultipleExportedDefaultConstructors`.
- Process nested classes that are fully non-dependent.
For more context, please read comments in https://github.com/llvm/llvm-project/pull/214275.
Issue creation assisted by: Cursor / GPT-5.6 Sol, I have read every part of this report.
Contributor guide
Research direction
Read the comments in PR 214275, then trace where checkForMultipleExportedDefaultConstructors runs during parsing and template instantiation. Focus on nested class-template specializations, parameter packs, constraints, and constructor-closure default arguments. Done means fully non-dependent specializations diagnose multiple eligible exported default constructors and instantiate required default arguments.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100