[clang] 9daf10f - Reland [Clang] skip default argument instantiation for non-defining friend declarations to meet [dcl.fct.default] p4 (#115487)

via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 18 02:36:26 PST 2024


Author: Oleksandr T.
Date: 2024-12-18T12:36:23+02:00
New Revision: 9daf10ff8f29ba3a88a105aaa9d2379c21b77d35

URL: https://github.com/llvm/llvm-project/commit/9daf10ff8f29ba3a88a105aaa9d2379c21b77d35
DIFF: https://github.com/llvm/llvm-project/commit/9daf10ff8f29ba3a88a105aaa9d2379c21b77d35.diff

LOG: Reland [Clang] skip default argument instantiation for non-defining friend declarations to meet [dcl.fct.default] p4 (#115487)

This fixes a crash when instantiating default arguments for templated
friend function declarations which lack a definition.
There are implementation limits which prevents us from finding the
pattern for such functions, and this causes difficulties
setting up the instantiation scope for the function parameters.

This patch skips instantiating the default argument in these cases,
which causes a minor regression in error recovery, but otherwise avoids
the crash.

The previous attempt #113777 accidentally skipped all default argument
constructions, causing some regressions. This patch resolves that by
moving the guard to InstantiateDefaultArgument() where the handling of
templates takes place.

Fixes https://github.com/llvm/llvm-project/issues/113324

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/test/CXX/temp/temp.res/p4.cpp
    clang/test/CodeGenCXX/default-arguments.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 956b5532b48f65..3645dff2e6fe88 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -837,6 +837,8 @@ Bug Fixes to C++ Support
   missing placeholder return type. (#GH78694)
 - Fixed a bug where bounds of partially expanded pack indexing expressions were checked too early. (#GH116105)
 - Fixed an assertion failure caused by using ``consteval`` in condition in consumed analyses. (#GH117385)
+- Fixed an assertion failure caused by invalid default argument substitutions in non-defining
+  friend declarations. (#GH113324)
 - Fix a crash caused by incorrect argument position in merging deduced template arguments. (#GH113659)
 - Fixed a parser crash when using pack indexing as a nested name specifier. (#GH119072) 
 - Fixed a null pointer dereference issue when heuristically computing ``sizeof...(pack)`` expressions. (#GH81436)

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index c70ee73a2d8e11..e058afe81da589 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4703,6 +4703,17 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
                                       ParmVarDecl *Param) {
   assert(Param->hasUninstantiatedDefaultArg());
 
+  // 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 the standard and only an issue for recovery
+  // purposes. [dcl.fct.default]p4:
+  //   if a friend declaration D specifies a default argument expression,
+  //   that declaration shall be a definition.
+  if (FD->getFriendObjectKind() != Decl::FOK_None &&
+      !FD->getTemplateInstantiationPattern())
+    return true;
+
   // Instantiate the expression.
   //
   // FIXME: Pass in a correct Pattern argument, otherwise

diff  --git a/clang/test/CXX/temp/temp.res/p4.cpp b/clang/test/CXX/temp/temp.res/p4.cpp
index f54d8649f5da88..9dbdd235e925d1 100644
--- a/clang/test/CXX/temp/temp.res/p4.cpp
+++ b/clang/test/CXX/temp/temp.res/p4.cpp
@@ -185,3 +185,23 @@ template<typename T> struct S {
   friend void X::f(T::type);
 };
 }
+
+namespace GH113324 {
+template <typename = int> struct S1 {
+  friend void f1(S1, int = 0); // expected-error {{friend declaration specifying a default argument must be a definition}}
+  friend void f2(S1 a, S1 = decltype(a){}); // expected-error {{friend declaration specifying a default argument must be a definition}}
+};
+
+template <class T> using alias = int;
+template <typename T> struct S2 {
+  // FIXME: We miss diagnosing the default argument instantiation failure
+  // (forming reference to void)
+  friend void f3(S2, int a = alias<T &>(1)); // expected-error {{friend declaration specifying a default argument must be a definition}}
+};
+
+void test() {
+  f1(S1<>{});
+  f2(S1<>{});
+  f3(S2<void>());
+}
+} // namespace GH113324

diff  --git a/clang/test/CodeGenCXX/default-arguments.cpp b/clang/test/CodeGenCXX/default-arguments.cpp
index 215bcd882e9625..2459ef1ad41fcd 100644
--- a/clang/test/CodeGenCXX/default-arguments.cpp
+++ b/clang/test/CodeGenCXX/default-arguments.cpp
@@ -12,6 +12,17 @@ void g() {
 }
 }
 
+namespace GH113324 {
+struct S1 {
+  friend void f(S1, int = 42) {}
+};
+
+void test() {
+  S1 s1;
+  f(s1);
+}
+};
+
 struct A1 {
  A1();
  ~A1();


        


More information about the cfe-commits mailing list