Skip to content

[Clang] Fix dependent local class instantiation bugs #134038

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

Merged
merged 6 commits into from
Apr 15, 2025

Conversation

zyn0217
Copy link
Contributor

@zyn0217 zyn0217 commented Apr 2, 2025

This patch fixes two long-standing bugs that prevent Clang from instantiating local class members inside a dependent context. These bugs were introduced in commits 21eb1af and 919df9d.

21eb1af introduced a concept called eligible methods such that it did an attempt to skip past ineligible method instantiation when instantiating class members. Unfortunately, this broke the instantiation chain for local classes - getTemplateInstantiationPattern() would fail to find the correct definition pattern if the class was defined within a partially transformed dependent context.

919df9d introduced a separate issue by incorrectly copying the DeclarationNameInfo during function definition instantiation from the template pattern, even though that DNI might contain a transformed TypeSourceInfo. Since that TSI was already updated when the declaration was instantiated, this led to inconsistencies. As a result, the final instantiated function could lose track of the transformed declarations, hence we crash: https://compiler-explorer.com/z/vjvoG76Tf.

This PR corrects them by

  1. Removing the bypass logic for method instantiation. The eligible flag is independent of instantiation and can be updated properly afterward, so skipping instantiation is unnecessary.

  2. Carefully handling TypeSourceInfo by creating a new instance that preserves the pattern's source location while using the already transformed type.

Fixes #59734
Fixes #132208

@zyn0217 zyn0217 added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Apr 2, 2025
Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This once again looks like an attempt at hacking around our lack of delayed lambda body instantiation... And this one has some pretty sizable negatives as far as I can see. I'm not sure I really like this direction.

@zyn0217
Copy link
Contributor Author

zyn0217 commented Apr 2, 2025

This once again looks like an attempt at hacking around our lack of delayed lambda body instantiation... And this one has some pretty sizable negatives as far as I can see. I'm not sure I really like this direction.

Yeah, admittedly this is another workaround of not having that mechanism. But the bug was a 15 regression, (which means we don't have to rely on that for it to work!) and due to some historic incorrect patches (which I'm fixing here) it ends up becoming hard to get the behavior correct as 14.

@erichkeane
Copy link
Collaborator

This once again looks like an attempt at hacking around our lack of delayed lambda body instantiation... And this one has some pretty sizable negatives as far as I can see. I'm not sure I really like this direction.

Yeah, admittedly this is another workaround of not having that mechanism. But the bug was a 15 regression, (which means we don't have to rely on that for it to work!) and due to some historic incorrect patches (which I'm fixing here) it ends up becoming hard to get the behavior correct as 14.

Oh, totally understood. This is just a 'stuck between a rock and a hard place' sort of situation, and I'm pretty uncomfortable here again.

I wouldn't be able to convince you to start work on the delayed lambda body instantiation instead, would I ? :-P

@zyn0217
Copy link
Contributor Author

zyn0217 commented Apr 2, 2025

I wouldn't be able to convince you to start work on the delayed lambda body instantiation instead, would I ? :-P

AFAIK @LYP951018 is already working on this region. Though I haven't test that patch with it yet 🥲

For Xref: #105953

@zyn0217
Copy link
Contributor Author

zyn0217 commented Apr 3, 2025

I talked to @erichkeane and updated the approach to make it feel less like a workaround and independent of lambda instantiation.

As noted, both cases worked prior to clang 15, which means they didn’t rely on deferred lambda body instantiation to compile correctly.

Regarding the lambda side of things - since @mizvekov is already working on a major ContextDecl refactoring in that area, I don’t think it's appropriate to initiate another large-scale change simultaneously. That would result in a lot of conflicts, as I can expect. It's also expected that much of the present issues will be alleviated once that gets landed and it's not too late for us to start working on the lambda deferral afterwards.

That said, this patch is aimed at fixing a regression and doesn't actually touch the lambda code itself (even though the bug involves lambdas), so it shouldn't become a burden that complicates future work on deferred lambda body instantiation. In fact, I think this should actually improve our test coverage overall.

There's little impact on the performance:

http://llvm-compile-time-tracker.com/compare.php?stat=instructions%3Au&from=fa5025b76034bcdd65d3a96eb29ae1edc18b876e&to=5aa9923638de93fedfbac1d8ea7f8677a88daaaf

@zyn0217 zyn0217 marked this pull request as ready for review April 3, 2025 08:00
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Apr 3, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 3, 2025

@llvm/pr-subscribers-clang

Author: Younan Zhang (zyn0217)

Changes

This patch fixes two long-standing bugs that prevent Clang from instantiating local class members inside a dependent context. These bugs were introduced in commits 21eb1af and 919df9d.

21eb1af introduced a concept called eligible methods such that it did an attempt to skip past ineligible method instantiation when instantiating class members. Unfortunately, this broke the instantiation chain for local classes - getTemplateInstantiationPattern() would fail to find the correct definition pattern if the class was defined within a partially transformed dependent context.

919df9d introduced a separate issue by incorrectly copying the DeclarationNameInfo during function definition instantiation from the template pattern, even though that DNI might contain a transformed TypeSourceInfo. Since that TSI was already updated when the declaration was instantiated, this led to inconsistencies. As a result, the final instantiated function could lose track of the transformed declarations, hence we crash: https://compiler-explorer.com/z/vjvoG76Tf.

This PR corrects them by

  1. Removing the bypass logic for method instantiation. The eligible flag is independent of instantiation and can be updated properly afterward, so skipping instantiation is unnecessary.

  2. Carefully handling TypeSourceInfo by creating a new instance that preserves the pattern's source location while using the already transformed type.

Fixes #59734
Fixes #132208


Full diff: https://github.com/llvm/llvm-project/pull/134038.diff

4 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (-3)
  • (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+56-1)
  • (modified) clang/test/SemaTemplate/instantiate-local-class.cpp (+73-1)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e409f206f6eae..6107fd7667306 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -348,6 +348,7 @@ Bug Fixes to C++ Support
   by template argument deduction.
 - Clang is now better at instantiating the function definition after its use inside
   of a constexpr lambda. (#GH125747)
+- Fixed a local class member function instantiation bug inside dependent lambdas. (#GH59734), (#GH132208)
 - Clang no longer crashes when trying to unify the types of arrays with
   certain differences in qualifiers (this could happen during template argument
   deduction or when building a ternary operator). (#GH97005)
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 00dcadb41e8fb..5b502b494e410 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -4264,9 +4264,6 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
       if (FunctionDecl *Pattern =
               Function->getInstantiatedFromMemberFunction()) {
 
-        if (Function->isIneligibleOrNotSelected())
-          continue;
-
         if (Function->getTrailingRequiresClause()) {
           ConstraintSatisfaction Satisfaction;
           if (CheckFunctionConstraints(Function, Satisfaction) ||
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 8aaaea0bcdd66..a8d23fb2be6d5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5590,7 +5590,62 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
   Function->setLocation(PatternDecl->getLocation());
   Function->setInnerLocStart(PatternDecl->getInnerLocStart());
   Function->setRangeEnd(PatternDecl->getEndLoc());
-  Function->setDeclarationNameLoc(PatternDecl->getNameInfo().getInfo());
+  // Let the instantiation use the Pattern's DeclarationNameLoc, due to the
+  // following awkwardness:
+  //   1. There are out-of-tree users of getNameInfo().getSourceRange(), who
+  //   expect the source range of the instantiated declaration to be set to
+  //   point the definition.
+  //
+  //   2. That getNameInfo().getSourceRange() might return the TypeLocInfo's
+  //   location it tracked.
+  //
+  //   3. Function might come from an (implicit) declaration, while the pattern
+  //   comes from a definition. In these cases, we need the PatternDecl's source
+  //   location.
+  //
+  // To that end, we need to more or less tweak the DeclarationNameLoc. However,
+  // we can't blindly copy the DeclarationNameLoc from the PatternDecl to the
+  // function, since it contains associated TypeLocs that should have already
+  // been transformed. So, we rebuild the TypeLoc for that purpose. Technically,
+  // we should create a new function declaration and assign everything we need,
+  // but InstantiateFunctionDefinition updates the declaration in place.
+  auto CorrectNameLoc = [&] {
+    DeclarationNameInfo PatternName = PatternDecl->getNameInfo();
+    DeclarationNameLoc PatternNameLoc = PatternName.getInfo();
+    switch (PatternName.getName().getNameKind()) {
+    case DeclarationName::CXXConstructorName:
+    case DeclarationName::CXXDestructorName:
+    case DeclarationName::CXXConversionFunctionName:
+      break;
+    default:
+      // Cases where DeclarationNameLoc doesn't matter, as it merely contains a
+      // source range.
+      Function->setDeclarationNameLoc(PatternNameLoc);
+      return;
+    }
+
+    TypeSourceInfo *TSI = Function->getNameInfo().getNamedTypeInfo();
+    // !!! When could TSI be null?
+    if (!TSI) {
+      // We don't care about the DeclarationName of the instantiated function,
+      // but only the DeclarationNameLoc. So if the TypeLoc is absent, we do
+      // nothing.
+      Function->setDeclarationNameLoc(PatternNameLoc);
+      return;
+    }
+
+    QualType InstT = TSI->getType();
+    // We want to use a TypeLoc that reflects the transformed type while
+    // preserving the source location from the pattern.
+    TypeLocBuilder TLB;
+    TLB.pushTrivial(
+        Context, InstT,
+        PatternNameLoc.getNamedTypeInfo()->getTypeLoc().getBeginLoc());
+    Function->setDeclarationNameLoc(DeclarationNameLoc::makeNamedTypeLoc(
+        TLB.getTypeSourceInfo(Context, InstT)));
+  };
+
+  CorrectNameLoc();
 
   EnterExpressionEvaluationContext EvalContext(
       *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
diff --git a/clang/test/SemaTemplate/instantiate-local-class.cpp b/clang/test/SemaTemplate/instantiate-local-class.cpp
index 298233739900f..bd6ef84a2bc0a 100644
--- a/clang/test/SemaTemplate/instantiate-local-class.cpp
+++ b/clang/test/SemaTemplate/instantiate-local-class.cpp
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -verify -std=c++11 %s
 // RUN: %clang_cc1 -verify -std=c++11 -fdelayed-template-parsing %s
 // RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s
+// RUN: %clang_cc1 -std=c++17 %s -DCodeGen -emit-llvm -triple %itanium_abi_triple -o - | FileCheck %s -dump-input=always
+
+#ifndef CodeGen
 
 template<typename T>
 void f0() {
@@ -60,7 +63,7 @@ namespace PR8801 {
     class X;
     typedef int (X::*pmf_type)();
     class X : public T { };
-    
+
     pmf_type pmf = &T::foo;
   }
 
@@ -535,3 +538,72 @@ void foo() {
 } // namespace local_recursive_lambda
 
 #endif
+
+#endif // CodeGen
+
+#ifdef CodeGen
+
+namespace LambdaContainingLocalClasses {
+
+template <typename F>
+void GH59734() {
+  [&](auto param) {
+    struct Guard {
+      Guard() {
+        // Check that we're able to create DeclRefExpr to param at this point.
+        static_assert(__is_same(decltype(param), int), "");
+      }
+      ~Guard() {
+        static_assert(__is_same(decltype(param), int), "");
+      }
+      operator decltype(param)() {
+        return decltype(param)();
+      }
+    };
+    Guard guard;
+    param = guard;
+  }(42);
+}
+
+// Guard::Guard():
+// CHECK-DAG: define {{.*}} @_ZZZN28LambdaContainingLocalClasses7GH59734IiEEvvENKUlT_E_clIiEEDaS1_EN5GuardC2Ev
+// Guard::operator int():
+// CHECK-DAG: define {{.*}} @_ZZZN28LambdaContainingLocalClasses7GH59734IiEEvvENKUlT_E_clIiEEDaS1_EN5GuardcviEv
+// Guard::~Guard():
+// CHECK-DAG: define {{.*}} @_ZZZN28LambdaContainingLocalClasses7GH59734IiEEvvENKUlT_E_clIiEEDaS1_EN5GuardD2Ev
+
+struct S {};
+
+template <class T = void>
+auto GH132208 = [](auto param) {
+  struct OnScopeExit {
+    OnScopeExit() {
+      static_assert(__is_same(decltype(param), S), "");
+    }
+    ~OnScopeExit() {
+      static_assert(__is_same(decltype(param), S), "");
+    }
+    operator decltype(param)() {
+      return decltype(param)();
+    }
+  } pending;
+
+  param = pending;
+};
+
+void bar() {
+  GH59734<int>();
+
+  GH132208<void>(S{});
+}
+
+// OnScopeExit::OnScopeExit():
+// CHECK-DAG: define {{.*}} @_ZZNK28LambdaContainingLocalClasses8GH132208IvEMUlT_E_clINS_1SEEEDaS2_EN11OnScopeExitC2Ev
+// OnScopeExit::operator S():
+// CHECK-DAG: define {{.*}} @_ZZNK28LambdaContainingLocalClasses8GH132208IvEMUlT_E_clINS_1SEEEDaS2_EN11OnScopeExitcvS5_Ev
+// OnScopeExit::~OnScopeExit():
+// CHECK-DAG: define {{.*}} @_ZZNK28LambdaContainingLocalClasses8GH132208IvEMUlT_E_clINS_1SEEEDaS2_EN11OnScopeExitD2Ev
+
+} // namespace LambdaContainingLocalClasses
+
+#endif

@zyn0217
Copy link
Contributor Author

zyn0217 commented Apr 14, 2025

Review ping

Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woops! Sorry, I thought I had already approved this with teh nit about the tests. Sorry about that!

Copy link
Contributor

@mizvekov mizvekov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM as well.

@zyn0217 zyn0217 merged commit 83344da into llvm:main Apr 15, 2025
12 checks passed
@mysterymath
Copy link
Contributor

mysterymath commented Apr 15, 2025

This looks to be the likely culprit for a clang crash in the Fuchsia build:

[21173/168418](63) CXX host_x64/obj/src/developer/debug/zxdb/client/libclient.map_setting_store.cc.o
FAILED: [code=1] host_x64/obj/src/developer/debug/zxdb/client/libclient.map_setting_store.cc.o
../../prebuilt/third_party/clang/custom/bin/clang++ -MD -MF host_x64/obj/src/developer/debug/zxdb/client/libclient.map_setting_store.cc.o.d -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES -DCURL_NO_OLDIES -DLLVM_USING_OLD_PREBUILT -DRAPIDJSON_HAS_STDSTRING -DRAPIDJSON_HAS_CXX11_RANGE_FOR -DRAPIDJSON_HAS_CXX11_RVALUE_REFS -DRAPIDJSON_HAS_CXX11_TYPETRAITS -DRAPIDJSON...
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: ../../prebuilt/third_party/clang/custom/bin/clang++ -MD -MF host_x64/obj/src/developer/debug/zxdb/client/libclient.map_setting_store.cc.o.d -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES -DCURL_NO_OLDIES -DLLVM_USING_OLD_PREBUILT -DRAPIDJSON_HAS_STDSTRING -DRAPIDJSON_HAS_CXX11_RANGE_FOR -DRAPIDJSON_HAS_CXX11_RVALUE_REFS -DRAPIDJSON_HAS_CXX11_...
1.	<eof> parser at end of file
2.	../../src/lib/fxl/observer_list.h:193:54: instantiating function definition 'fxl::ObserverListBase<zxdb::SettingStoreObserver>::Iter<const fxl::ObserverListBase<zxdb::SettingStoreObserver>>::~Iter'
#0 0x000055e06ddeea18 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (../../prebuilt/third_party/clang/custom/bin/clang+++0x9164a18)
clang++: error: clang frontend command failed with exit code 139 (use -v to see invocation)
Fuchsia clang version 21.0.0git (https://llvm.googlesource.com/llvm-project 1cf9f764ac41fb3492e10c78640dd50e616388db)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: ../../prebuilt/third_party/clang/custom/bin
Build config: +assertions
clang++: note: diagnostic msg:
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang++: note: diagnostic msg: clang-crashreports/map_setting_store-0b592c.cpp
clang++: note: diagnostic msg: clang-crashreports/map_setting_store-0b592c.sh
clang++: note: diagnostic msg:

********************

Does it seem likely this PR is the culprit? If so, can this be fixed forward or reverted?

https://luci-milo.appspot.com/ui/p/fuchsia/builders/ci/clang_toolchain.ci.core.x64-debug/b8717549930672410881/overview

@mizvekov
Copy link
Contributor

Can you send reproducer and / or stack trace?

FYI you can use CLANG_CRASH_DIAGNOSTICS_DIR environment variable to make clang put these automatically generated reproducers up in a directory which will have its contents exported as artifacts.

@mysterymath
Copy link
Contributor

mysterymath commented Apr 15, 2025

Here's a link to a reproducer tar; I was able to verify that the issue reproduces locally using our toolchain from CI with the tarball.

https://storage.googleapis.com/fuchsia-artifacts/builds/8717549930672410881/build-debug/clang-crashreports/map_setting_store-0b592c.tar

@mizvekov
Copy link
Contributor

Yeah, I confirm this crashes clang, and reverting this commit does fix the crash.

For reference, this is the stack trace:

1.	<eof> parser at end of file
2.	../../src/lib/fxl/observer_list.h:193:54: instantiating function definition 'fxl::ObserverListBase<zxdb::SettingStoreObserver>::Iter<const fxl::ObserverListBase<zxdb::SettingStoreObserver>>::~Iter'
 #0 0x0000000104d687b8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x104a787b8)
 #1 0x0000000104d68cdc PrintStackTraceSignalHandler(void*) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x104a78cdc)
 #2 0x0000000104d66b9c llvm::sys::RunSignalHandlers() (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x104a76b9c)
 #3 0x0000000104d695a8 SignalHandler(int, __siginfo*, void*) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x104a795a8)
 #4 0x0000000184d77624 (/usr/lib/system/libsystem_platform.dylib+0x1804ab624)
 #5 0x0000000109f3dcac clang::Sema::InstantiateFunctionDefinition(clang::SourceLocation, clang::FunctionDecl*, bool, bool, bool)::$_4::operator()() const (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x109c4dcac)
 #6 0x0000000109f3dcac clang::Sema::InstantiateFunctionDefinition(clang::SourceLocation, clang::FunctionDecl*, bool, bool, bool)::$_4::operator()() const (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x109c4dcac)
 #7 0x0000000109f3d3d4 clang::Sema::InstantiateFunctionDefinition(clang::SourceLocation, clang::FunctionDecl*, bool, bool, bool) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x109c4d3d4)
 #8 0x0000000109f407a0 clang::Sema::PerformPendingInstantiations(bool, bool) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x109c507a0)
 #9 0x0000000108f23178 clang::Sema::ActOnEndOfTranslationUnitFragment(clang::Sema::TUFragmentKind) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x108c33178)
#10 0x0000000108f23788 clang::Sema::ActOnEndOfTranslationUnit() (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x108c33788)
#11 0x0000000108e236e0 clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, clang::Sema::ModuleImportState&) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x108b336e0)
#12 0x0000000108cfb610 clang::ParseAST(clang::Sema&, bool, bool) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x108a0b610)
#13 0x00000001066eeb34 clang::ASTFrontendAction::ExecuteAction() (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x1063feb34)
#14 0x0000000105bf3564 clang::CodeGenAction::ExecuteAction() (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x105903564)
#15 0x00000001066ee358 clang::FrontendAction::Execute() (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x1063fe358)
#16 0x00000001065cdb8c clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x1062ddb8c)
#17 0x0000000106960d30 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x106670d30)
#18 0x0000000100301a40 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x100011a40)
#19 0x00000001002f36e0 ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x1000036e0)
#20 0x00000001002f2404 clang_main(int, char**, llvm::ToolContext const&) (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x100002404)
#21 0x000000010032bb48 main (/Users/mizvekov/Repos/llvm/6/build/dbg/llvm/bin/clang-21+0x10003bb48)
#22 0x000000018499eb4c

@zyn0217 FYI

mizvekov added a commit that referenced this pull request Apr 15, 2025
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Apr 15, 2025
@zyn0217
Copy link
Contributor Author

zyn0217 commented Apr 16, 2025

Thanks for the revert.

I added an assertion to NameLocPointsToPattern after line 5637 and it fired because PatternName.getNamedTypeInfo is null. This is strange because the instantiated function does have a TypeSourceInfo, which is guarded by line 5630.

I need a reduced version to figure out what happened.

zyn0217 added a commit that referenced this pull request Apr 17, 2025
This reapplies #134038

Since the last patch, this fixes a null pointer dereference where the
TSI of the destructor wasn't properly propagated into the
DeclarationNameInfo. We now construct a LocInfoType for dependent cases,
as done elsewhere in getDestructorName, such that GetTypeFromParser can
correctly obtain the TSI.

---

This patch fixes two long-standing bugs that prevent Clang from
instantiating local class members inside a dependent context. These bugs
were introduced in commits
21eb1af
and
919df9d.


21eb1af
introduced a concept called eligible methods such that it did an attempt
to skip past ineligible method instantiation when instantiating class
members. Unfortunately, this broke the instantiation chain for local
classes - getTemplateInstantiationPattern() would fail to find the
correct definition pattern if the class was defined within a partially
transformed dependent context.


919df9d
introduced a separate issue by incorrectly copying the
DeclarationNameInfo during function definition instantiation from the
template pattern, even though that DNI might contain a transformed
TypeSourceInfo. Since that TSI was already updated when the declaration
was instantiated, this led to inconsistencies. As a result, the final
instantiated function could lose track of the transformed declarations,
hence we crash: https://compiler-explorer.com/z/vjvoG76Tf.

This PR corrects them by

1. Removing the bypass logic for method instantiation. The eligible flag
is independent of instantiation and can be updated properly afterward,
so skipping instantiation is unnecessary.

2. Carefully handling TypeSourceInfo by creating a new instance that
preserves the pattern's source location while using the already
transformed type.
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
This patch fixes two long-standing bugs that prevent Clang from
instantiating local class members inside a dependent context. These bugs
were introduced in commits 21eb1af and 919df9d.

21eb1af introduced a concept called eligible methods such that it
did an attempt to skip past ineligible method instantiation when
instantiating class members. Unfortunately, this broke the instantiation
chain for local classes - getTemplateInstantiationPattern() would fail
to find the correct definition pattern if the class was defined within a
partially transformed dependent context.

919df9d introduced a separate issue by incorrectly copying the
DeclarationNameInfo during function definition instantiation from the
template pattern, even though that DNI might contain a transformed
TypeSourceInfo. Since that TSI was already updated when the declaration
was instantiated, this led to inconsistencies. As a result, the final
instantiated function could lose track of the transformed declarations,
hence we crash: https://compiler-explorer.com/z/vjvoG76Tf.

This PR corrects them by

1. Removing the bypass logic for method instantiation. The eligible flag
is independent of instantiation and can be updated properly afterward,
so skipping instantiation is unnecessary.

2. Carefully handling TypeSourceInfo by creating a new instance that
preserves the pattern's source location while using the already
transformed type.

Fixes llvm#59734
Fixes llvm#132208
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
…135914)

This reapplies llvm#134038

Since the last patch, this fixes a null pointer dereference where the
TSI of the destructor wasn't properly propagated into the
DeclarationNameInfo. We now construct a LocInfoType for dependent cases,
as done elsewhere in getDestructorName, such that GetTypeFromParser can
correctly obtain the TSI.

---

This patch fixes two long-standing bugs that prevent Clang from
instantiating local class members inside a dependent context. These bugs
were introduced in commits
llvm@21eb1af
and
llvm@919df9d.


llvm@21eb1af
introduced a concept called eligible methods such that it did an attempt
to skip past ineligible method instantiation when instantiating class
members. Unfortunately, this broke the instantiation chain for local
classes - getTemplateInstantiationPattern() would fail to find the
correct definition pattern if the class was defined within a partially
transformed dependent context.


llvm@919df9d
introduced a separate issue by incorrectly copying the
DeclarationNameInfo during function definition instantiation from the
template pattern, even though that DNI might contain a transformed
TypeSourceInfo. Since that TSI was already updated when the declaration
was instantiated, this led to inconsistencies. As a result, the final
instantiated function could lose track of the transformed declarations,
hence we crash: https://compiler-explorer.com/z/vjvoG76Tf.

This PR corrects them by

1. Removing the bypass logic for method instantiation. The eligible flag
is independent of instantiation and can be updated properly afterward,
so skipping instantiation is unnecessary.

2. Carefully handling TypeSourceInfo by creating a new instance that
preserves the pattern's source location while using the already
transformed type.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
5 participants