[Clang][Sema] Fix a bug on type constraint checking (#84671)
Try to fix https://github.com/llvm/llvm-project/issues/84368
When visiting class members in
`TemplateDeclInstantiator::VisitClassTemplateDecl` during
`Sema::InstantiateClass`, we miss to set attribute of friend declaration
if it is(`isFriend` is true). This will lead to
`Sema::AreConstraintExpressionsEqual` return false when invoked in
`MatchTemplateParameterKind`. Because it makes
`Sema::getTemplateInstantiationArgs` returns incorrect template
argument(`MultiLevelTemplateArgumentList`). When we handle
`CXXRecordDecl` In `Sema::getTemplateInstantiationArgs`, friend
declaration(its parent context is `FileContext`) makes us to choose
`LexicalDeclContext` not `DeclContext` and this is what we want.
Co-authored-by: huqizhi <836744285@qq.com>
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0a963d1..abeb5a8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -376,6 +376,8 @@
- Fixed a crash in constant evaluation when trying to access a
captured ``this`` pointer in a lambda with an explicit object parameter.
Fixes (#GH80997)
+- Fix an issue where missing set friend declaration in template class instantiation.
+ Fixes (#GH84368).
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 8ef8bfd..dc97201 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1727,6 +1727,7 @@
assert(!Owner->isDependentContext());
Inst->setLexicalDeclContext(Owner);
RecordInst->setLexicalDeclContext(Owner);
+ Inst->setObjectOfFriendDecl();
if (PrevClassTemplate) {
Inst->setCommonPtr(PrevClassTemplate->getCommonPtr());
diff --git a/clang/test/Sema/PR84368.cpp b/clang/test/Sema/PR84368.cpp
new file mode 100644
index 0000000..6551df2
--- /dev/null
+++ b/clang/test/Sema/PR84368.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// RUN: %clang_cc1 -std=c++23 -verify %s
+// expected-no-diagnostics
+
+template<class T> concept IsOk = requires() { typename T::Float; };
+
+template<IsOk T> struct Thing;
+
+template<IsOk T> struct Foobar {
+ template<int> struct Inner {
+ template<IsOk T2> friend struct Thing;
+ };
+};
+
+struct MyType { using Float=float; };
+Foobar<MyType>::Inner<0> foobar;