Skip to content

Commit 358165d

Browse files
authored
[Clang][Concepts] Correct the CurContext for friend declarations (llvm#106890)
`FindInstantiatedDecl()` relies on the `CurContext` to find the corresponding class template instantiation for a class template declaration. Previously, we pushed the semantic declaration context for constraint comparison, which is incorrect for constraints on friend declarations. In issue llvm#78101, the semantic context of the friend is the TU, so we missed the implicit template specialization `Template<void, 4>` when looking for the instantiation of the primary template `Template` at the time of checking the member instantiation; instead, we mistakenly picked up the explicit specialization `Template<float, 5>`, hence the error. As a bonus, this also fixes a crash when diagnosing constraints. The DeclarationName is not necessarily an identifier, so it's incorrect to call `getName()` on e.g. overloaded operators. Since the DiagnosticBuilder has correctly handled Decl printing, we don't need to find the printable name ourselves. Fixes llvm#78101
1 parent 647f892 commit 358165d

File tree

6 files changed

+35
-5
lines changed

6 files changed

+35
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ Bug Fixes to C++ Support
338338
- Fixed an assertion failure when converting vectors to int/float with invalid expressions. (#GH105486)
339339
- Template parameter names are considered in the name lookup of out-of-line class template
340340
specialization right before its declaration context. (#GH64082)
341+
- Fixed a constraint comparison bug for friend declarations. (#GH78101)
341342

342343
Bug Fixes to AST Handling
343344
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5603,7 +5603,7 @@ def note_checking_constraints_for_function_here : Note<
56035603
def note_constraint_substitution_here : Note<
56045604
"while substituting template arguments into constraint expression here">;
56055605
def note_constraint_normalization_here : Note<
5606-
"while calculating associated constraint of template '%0' here">;
5606+
"while calculating associated constraint of template %0 here">;
56075607
def note_parameter_mapping_substitution_here : Note<
56085608
"while substituting into concept arguments here; substitution failures not "
56095609
"allowed in concept arguments">;

clang/lib/Sema/SemaConcept.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,14 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
10121012
// possible that e.g. constraints involving C<Class<T>> and C<Class> are
10131013
// perceived identical.
10141014
std::optional<Sema::ContextRAII> ContextScope;
1015-
if (auto *RD = dyn_cast<CXXRecordDecl>(DeclInfo.getDeclContext())) {
1015+
const DeclContext *DC = [&] {
1016+
if (!DeclInfo.getDecl())
1017+
return DeclInfo.getDeclContext();
1018+
return DeclInfo.getDecl()->getFriendObjectKind()
1019+
? DeclInfo.getLexicalDeclContext()
1020+
: DeclInfo.getDeclContext();
1021+
}();
1022+
if (auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
10161023
ThisScope.emplace(S, const_cast<CXXRecordDecl *>(RD), Qualifiers());
10171024
ContextScope.emplace(S, const_cast<DeclContext *>(cast<DeclContext>(RD)),
10181025
/*NewThisContext=*/false);

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,8 +1226,7 @@ void Sema::PrintInstantiationStack() {
12261226
case CodeSynthesisContext::ConstraintNormalization:
12271227
Diags.Report(Active->PointOfInstantiation,
12281228
diag::note_constraint_normalization_here)
1229-
<< cast<NamedDecl>(Active->Entity)->getName()
1230-
<< Active->InstantiationRange;
1229+
<< cast<NamedDecl>(Active->Entity) << Active->InstantiationRange;
12311230
break;
12321231
case CodeSynthesisContext::ParameterMappingSubstitution:
12331232
Diags.Report(Active->PointOfInstantiation,

clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ template<typename T> requires Bar2<T> struct S2 { };
1515
// expected-note@-1{{template is declared here}}
1616
template<typename T> requires Bar2<T> && true struct S2<T> { };
1717
// expected-error@-1{{class template partial specialization is not more specialized than the primary template}}
18-
// expected-note@-2{{while calculating associated constraint of template 'S2' here}}
18+
// expected-note@-2{{while calculating associated constraint of template 'S2<T>' here}}
1919

2020
namespace type_pack {
2121
template<typename... Args>

clang/test/SemaTemplate/concepts-friends.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,3 +525,26 @@ struct S {
525525
};
526526

527527
}
528+
529+
namespace GH78101 {
530+
531+
template <typename T, int i>
532+
concept True = true;
533+
534+
template <typename T, int I> struct Template {
535+
static constexpr int i = I;
536+
537+
friend constexpr auto operator+(True<i> auto f) { return i; }
538+
};
539+
540+
template <int I> struct Template<float, I> {
541+
static constexpr int i = I;
542+
543+
friend constexpr auto operator+(True<i> auto f) { return i; }
544+
};
545+
546+
Template<void, 4> f{};
547+
548+
static_assert(+Template<float, 5>{} == 5);
549+
550+
} // namespace GH78101

0 commit comments

Comments
 (0)