| Issue |
182975
|
| Summary |
One more "dependent lookup context that isn't the current instantiation" failure
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
snarkmaster
|
This looks different from #175296 (open, but different ingredients) and #95778 (fixed in 2024). I hit it while writing real code.
It's live on trunk, and was introduced after 19: https://godbolt.org/z/8rhYTx3xc
## Essential ingredients
1. Class template with an **anonymous union** member
2. Constructor with a **`requires` clause** that accesses the union member via a parameter of the class's own type (e.g. `other.value`)
3. A **deduction guide** for the class template
## Minimal repro & error
```
template <typename T>
struct S {
union {
T value;
};
S(S&& other)
requires requires { other.value; } = default;
};
S(int) -> S<int>;
```
```
clang/lib/Sema/SemaExprMember.cpp:1007:
Assertion `(SS.isEmpty() ? !BaseType->isDependentType() || computeDeclContext(BaseType)
: !isDependentScopeSpecifier(SS) || computeDeclContext(SS))
&& "dependent lookup context that isn't the current instantiation?"' failed.
```
## Workaround
I used a `declval` dummy in the `requires` clause instead. This is less legible and likely costlier to build?
## Fix (against 20) due to @lanza
The author unfortunately doesn't have time to put this up as a PR, but this was reviewed by @bcardosolopes as reasonable:
```patch
diff --git a/20/llvm-project/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/20/llvm-project/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
--- a/20/llvm-project/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/20/llvm-project/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -459,16 +459,21 @@
// requires-clause, if any.
Expr *FunctionTrailingRC = nullptr;
if (Expr *RC = CD->getTrailingRequiresClause()) {
- MultiLevelTemplateArgumentList Args;
- Args.setKind(TemplateSubstitutionKind::Rewrite);
- Args.addOuterTemplateArguments(Depth1Args);
- Args.addOuterRetainedLevel();
- if (NestedPattern)
- Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());
- ExprResult E = SemaRef.SubstConstraintExprWithoutSatisfaction(RC, Args);
- if (!E.isUsable())
- return nullptr;
- FunctionTrailingRC = E.get();
+ if (FTD) {
+ MultiLevelTemplateArgumentList Args;
+ Args.setKind(TemplateSubstitutionKind::Rewrite);
+ Args.addOuterTemplateArguments(Depth1Args);
+ Args.addOuterRetainedLevel();
+ if (NestedPattern)
+ Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());
+ ExprResult E =
+ SemaRef.SubstConstraintExprWithoutSatisfaction(RC, Args);
+ if (!E.isUsable())
+ return nullptr;
+ FunctionTrailingRC = E.get();
+ } else {
+ FunctionTrailingRC = RC;
+ }
}
// C++ [over.match.class.deduct]p1:
diff --git a/20/llvm-project/clang/test/SemaTemplate/constrained-deduction-guide-crash.cpp b/20/llvm-project/clang/test/SemaTemplate/constrained-deduction-guide-crash.cpp
new file mode 100644
--- /dev/null
+++ b/20/llvm-project/clang/test/SemaTemplate/constrained-deduction-guide-crash.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// Test that non-template constructors with trailing requires clauses
+// don't crash during deduction guide synthesis.
+
+// Anonymous union with constrained defaulted move constructor.
+template <typename T>
+struct AnonymousUnionConstrainedDefaultedMove {
+ union {
+ T value;
+ };
+ AnonymousUnionConstrainedDefaultedMove(
+ AnonymousUnionConstrainedDefaultedMove&& other)
+ requires requires { other.value; } = default;
+};
+
+AnonymousUnionConstrainedDefaultedMove(int)
+ -> AnonymousUnionConstrainedDefaultedMove<int>;
+
+// Direct member with constrained constructor.
+template <typename T>
+struct DirectMemberConstrainedCtor {
+ T value;
+ DirectMemberConstrainedCtor(DirectMemberConstrainedCtor&& other)
+ requires requires { other.value; } = default;
+};
+
+DirectMemberConstrainedCtor(int) -> DirectMemberConstrainedCtor<int>;
+
+// Non-defaulted constrained constructor.
+template <typename T>
+struct NonDefaultedConstrainedCtor {
+ T data;
+ NonDefaultedConstrainedCtor(NonDefaultedConstrainedCtor&& other)
+ requires requires { other.data; } : data(static_cast<T&&>(other.data)) {}
+};
+
+NonDefaultedConstrainedCtor(int) -> NonDefaultedConstrainedCtor<int>;
+
+// CTAD triggering deduction guide synthesis.
+template <typename T>
+struct CTADTrigger {
+ union {
+ T value;
+ };
+ CTADTrigger(T v) : value(v) {}
+ CTADTrigger(CTADTrigger&& other)
+ requires requires { other.value; } = default;
+};
+
+void testCTAD() {
+ CTADTrigger c(42);
+}
+
+// Ensure template constructors with requires clauses still work (CWG 2628).
+template <typename T>
+struct TemplateCtorWithRequiresStillWorks {
+ T value;
+ template <typename U>
+ requires requires { static_cast<T>(U{}); }
+ TemplateCtorWithRequiresStillWorks(U u) : value(static_cast<T>(u)) {}
+};
+
+TemplateCtorWithRequiresStillWorks(int)
+ -> TemplateCtorWithRequiresStillWorks<int>;
+
+void testTemplateCtor() {
+ TemplateCtorWithRequiresStillWorks t(42);
+}
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs