-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[Clang] Stop changing DC when instantiating dependent friend specializations #139436
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Since 346077a, we began using the primary template's lexical DeclContext for template arguments in order to properly instantiate a friend definition. There is a missed peculiar case, as in a friend template is specialized within a dependent context. In this scenario, the primary template is not a definition, whereas the specialization is. So the primary template's DeclContext doesn't provide any meaningful for instantiation.
@llvm/pr-subscribers-clang Author: Younan Zhang (zyn0217) ChangesSince 346077a, we began using the primary template's lexical DeclContext for template arguments in order to properly instantiate a friend definition. There is a missed peculiar case, as in a friend template is specialized within a dependent context. In this scenario, the primary template is not a definition, whereas the specialization is. So the primary template's DeclContext doesn't provide any meaningful for instantiation. Fixes #139052 Full diff: https://github.com/llvm/llvm-project/pull/139436.diff 4 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1d0896f585fb4..c75ad0be8a8e6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -576,6 +576,8 @@ Bug Fixes in This Version
``#include`` directive. (#GH138094)
- Fixed a crash during constant evaluation involving invalid lambda captures
(#GH138832)
+- Fixed a crash when instantiating an invalid dependent friend template specialization.
+ (#GH139052)
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index cbccb567e2adf..d915448d0feb1 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18740,7 +18740,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// a template-id, the function name is not unqualified because these is
// no name. While the wording requires some reading in-between the
// lines, GCC, MSVC, and EDG all consider a friend function
- // specialization definitions // to be de facto explicit specialization
+ // specialization definitions to be de facto explicit specialization
// and diagnose them as such.
} else if (isTemplateId) {
Diag(NameInfo.getBeginLoc(), diag::err_friend_specialization_def);
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 08b3a423d1526..a8c3b28f8d185 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5751,14 +5751,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
RebuildTypeSourceInfoForDefaultSpecialMembers();
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
- NamedDecl *ND = Function;
- DeclContext *DC = ND->getLexicalDeclContext();
+ DeclContext *DC = Function->getLexicalDeclContext();
std::optional<ArrayRef<TemplateArgument>> Innermost;
- if (auto *Primary = Function->getPrimaryTemplate();
- Primary &&
+ bool NeedDCFromPrimaryTemplate =
!isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) &&
Function->getTemplateSpecializationKind() !=
- TSK_ExplicitSpecialization) {
+ TSK_ExplicitSpecialization &&
+ !PatternDecl->getDependentSpecializationInfo();
+
+ if (auto *Primary = Function->getPrimaryTemplate();
+ Primary && NeedDCFromPrimaryTemplate) {
auto It = llvm::find_if(Primary->redecls(),
[](const RedeclarableTemplateDecl *RTD) {
return cast<FunctionTemplateDecl>(RTD)
diff --git a/clang/test/SemaTemplate/GH55509.cpp b/clang/test/SemaTemplate/GH55509.cpp
index 773a84305a0cd..f421e5a8fc237 100644
--- a/clang/test/SemaTemplate/GH55509.cpp
+++ b/clang/test/SemaTemplate/GH55509.cpp
@@ -110,3 +110,41 @@ namespace regression2 {
}
template void A<void>::f<long>();
} // namespace regression2
+
+namespace GH139226 {
+
+struct FakeStream {};
+
+template <typename T>
+class BinaryTree;
+
+template <typename T>
+FakeStream& operator<<(FakeStream& os, BinaryTree<T>& b); // #1
+
+template <typename T>
+FakeStream& operator>>(FakeStream& os, BinaryTree<T>& b) {
+ return os;
+}
+
+template <typename T>
+struct BinaryTree {
+ T* root{};
+ // This template is described using a DependentSpecializationInfo, and its instantiations
+ // are tracked with TSK_ImplicitInstantiation kind.
+ // The primary template is declared at #1.
+ friend FakeStream& operator<< <T>(FakeStream& os, BinaryTree&) {
+ // expected-error@-1 {{friend function specialization cannot be defined}}
+ return os;
+ }
+
+ friend FakeStream& operator>> <T>(FakeStream& os, BinaryTree&);
+};
+
+void foo() {
+ FakeStream fakeout;
+ BinaryTree<int> a{};
+ fakeout << a;
+ fakeout >> a;
+}
+
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@mizvekov It's not a big deal to turn them into explicit specializations after all... I pushed a commit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect, thanks!
Since 346077a, we began using the primary template's lexical DeclContext for template arguments in order to properly instantiate a friend definition.
There is a missed peculiar case, as in a friend template is specialized within a dependent context. In this scenario, the primary template is not a definition, whereas the specialization is. So the primary template's DeclContext doesn't provide any meaningful for instantiation.
Fixes #139052