[clang] Fix linkage of nested lambdas.

patch from Philippe Daouadi <blastrock@free.fr>

This is an attempt to fix
[PR#44368](https://bugs.llvm.org/show_bug.cgi?id=44368)

This effectively reverts [D1783](https://reviews.llvm.org/D1783). It
doesn't break the current tests and fixes the test that this commit
adds.

We now decide of a lambda linkage only depending on the visibility of
its parent context.

Differential Revision: https://reviews.llvm.org/D73701
This commit is contained in:
Michael Liao 2020-02-07 12:58:17 -05:00
parent cbe0c8299e
commit 2926917f43
2 changed files with 18 additions and 31 deletions

View File

@ -1318,19 +1318,6 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D,
LV.isVisibilityExplicit());
}
static inline const CXXRecordDecl*
getOutermostEnclosingLambda(const CXXRecordDecl *Record) {
const CXXRecordDecl *Ret = Record;
while (Record && Record->isLambda()) {
Ret = Record;
if (!Record->getParent()) break;
// Get the Containing Class of this Lambda Class
Record = dyn_cast_or_null<CXXRecordDecl>(
Record->getParent()->getParent());
}
return Ret;
}
LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D,
LVComputationKind computation,
bool IgnoreVarTypeLinkage) {
@ -1396,25 +1383,9 @@ LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D,
return getInternalLinkageFor(D);
}
// This lambda has its linkage/visibility determined:
// - either by the outermost lambda if that lambda has no mangling
// number.
// - or by the parent of the outer most lambda
// This prevents infinite recursion in settings such as nested lambdas
// used in NSDMI's, for e.g.
// struct L {
// int t{};
// int t2 = ([](int a) { return [](int b) { return b; };})(t)(t);
// };
const CXXRecordDecl *OuterMostLambda =
getOutermostEnclosingLambda(Record);
if (OuterMostLambda->hasKnownLambdaInternalLinkage() ||
!OuterMostLambda->getLambdaManglingNumber())
return getInternalLinkageFor(D);
return getLVForClosure(
OuterMostLambda->getDeclContext()->getRedeclContext(),
OuterMostLambda->getLambdaContextDecl(), computation);
Record->getDeclContext()->getRedeclContext(),
Record->getLambdaContextDecl(), computation);
}
break;

View File

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fblocks -emit-llvm -o - %s -fexceptions -std=c++11 | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fblocks -emit-llvm -o - %s -fexceptions -std=c++14 | FileCheck --check-prefixes=CHECK,CXX14 %s
// CHECK-LABEL: define void @_ZN19non_inline_function3fooEv()
// CHECK-LABEL: define internal void @"_ZZN19non_inline_function3fooEvENK3$_0clEi"(%class.anon
@ -51,3 +52,18 @@ inline int foo() {
}
int use = foo();
}
#if __cplusplus >= 201402L
// CXX14-LABEL: define internal void @"_ZZZN32lambda_capture_in_generic_lambda3fooIiEEDavENKUlT_E_clIZNS_L1fEvE3$_1EEDaS1_ENKUlvE_clEv"
namespace lambda_capture_in_generic_lambda {
template <typename T> auto foo() {
return [](auto func) {
[func] { func(); }();
};
}
static void f() {
foo<int>()([] { });
}
void f1() { f(); }
}
#endif