Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) ||
Expand Down
56 changes: 55 additions & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5590,7 +5590,61 @@ 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 to 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 NameLocPointsToPattern = [&] {
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.
return PatternNameLoc;
}

TypeSourceInfo *TSI = Function->getNameInfo().getNamedTypeInfo();
// TSI might be null if the function is named by a constructor template id.
// E.g. S<T>() {} for class template S with a template parameter T.
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.
return PatternNameLoc;
}

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());
return DeclarationNameLoc::makeNamedTypeLoc(
TLB.getTypeSourceInfo(Context, InstT));
};
Function->setDeclarationNameLoc(NameLocPointsToPattern());

EnterExpressionEvaluationContext EvalContext(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
Expand Down
74 changes: 73 additions & 1 deletion clang/test/SemaTemplate/instantiate-local-class.cpp
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -60,7 +63,7 @@ namespace PR8801 {
class X;
typedef int (X::*pmf_type)();
class X : public T { };

pmf_type pmf = &T::foo;
}

Expand Down Expand Up @@ -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
Loading