[clang] [Clang] Ensure default arguments in friend declarations are only allowed in defining declarations to prevent multiple reachable declarations (PR #113777)
Oleksandr T. via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 7 05:14:57 PST 2024
https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/113777
>From 2ef4cc6c16d2217053f90fe4c3d2f251a52e0c60 Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Thu, 7 Nov 2024 15:14:05 +0200
Subject: [PATCH] [Clang] skip default argument instantiation for non-defining
friend declarations without specialization info to meet [dcl.fct.default]p4
---
clang/docs/ReleaseNotes.rst | 2 ++
clang/lib/Sema/SemaExpr.cpp | 11 +++++++++++
clang/test/CXX/temp/temp.res/p4.cpp | 19 +++++++++++++++++++
3 files changed, 32 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 061a1fed3f7d48..220cfb222c49d4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -595,6 +595,8 @@ Bug Fixes to C++ Support
an implicitly instantiated class template specialization. (#GH51051)
- Fixed an assertion failure caused by invalid enum forward declarations. (#GH112208)
- Name independent data members were not correctly initialized from default member initializers. (#GH114069)
+- Fixed an assertion failure caused by invalid default argument substitutions in non-defining
+ friend declarations. (#GH113324).
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 49fdb5b5ab43da..df8f025030e2b1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6018,6 +6018,17 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl,
} else {
assert(Param && "can't use default arguments without a known callee");
+ // FIXME: We don't track member specialization info for non-defining
+ // friend declarations, so we will not be able to later find the function
+ // pattern. As a workaround, don't instantiate the default argument in
+ // this case. This is correct per wording and only an error recovery
+ // issue, as per [dcl.fct.default]p4:
+ // if a friend declaration D specifies a default argument expression,
+ // that declaration shall be a definition.
+ if (FDecl->getFriendObjectKind() != Decl::FOK_None &&
+ FDecl->getMemberSpecializationInfo() == nullptr)
+ return true;
+
ExprResult ArgExpr = BuildCXXDefaultArgExpr(CallLoc, FDecl, Param);
if (ArgExpr.isInvalid())
return true;
diff --git a/clang/test/CXX/temp/temp.res/p4.cpp b/clang/test/CXX/temp/temp.res/p4.cpp
index f54d8649f5da88..743ffed14d81a8 100644
--- a/clang/test/CXX/temp/temp.res/p4.cpp
+++ b/clang/test/CXX/temp/temp.res/p4.cpp
@@ -185,3 +185,22 @@ template<typename T> struct S {
friend void X::f(T::type);
};
}
+
+namespace GH113324 {
+template <typename = int> struct ct {
+ friend void f1(ct, int = 0); // expected-error {{friend declaration specifying a default argument must be a definition}}
+ friend void f2(ct a, ct = decltype(a){ }); // expected-error {{friend declaration specifying a default argument must be a definition}}
+};
+
+template<class T> using alias = int;
+template<typename T> struct C {
+ // FIXME: We miss diagnosing the default argument instantiation failure (forming reference to void)
+ friend void f3(C, int a = alias<T&>(1)); // expected-error {{friend declaration specifying a default argument must be a definition}}
+};
+
+void test() {
+ f1(ct<>{});
+ f2(ct<>{});
+ f3(C<void>());
+}
+} // namespace GH113324
More information about the cfe-commits
mailing list