Replace 'magic static' with a member variable for SCYL kernel names

I discovered when merging the __builtin_sycl_unique_stable_name into my
downstream that it is actually possible for the cc1 invocation to have
more than 1 Sema instance, if you pass it multiple input files, each
gets its own Sema instance and thus ASTContext instance.  The result was
that the call to Filter the SYCL kernels was using an
ItaniumMangleContext stored via a 'magic static', so it had an invalid
reference to ASTContext when processing the 2nd failure.

The failure is unfortunately flakey/transient, but the test that fails
was added anyway.

The magic-static was switched to a unique_ptr member variable in
ASTContext that is initialized when needed.
This commit is contained in:
Erich Keane 2021-05-27 13:40:15 -07:00
parent 0d5219feb9
commit cb66bf2c6d
3 changed files with 35 additions and 10 deletions

View File

@ -103,6 +103,7 @@ class DynTypedNode;
class DynTypedNodeList;
class Expr;
class GlobalDecl;
class ItaniumMangleContext;
class MangleContext;
class MangleNumberingContext;
class MaterializeTemporaryExpr;
@ -3166,7 +3167,7 @@ public:
void AddSYCLKernelNamingDecl(const CXXRecordDecl *RD);
bool IsSYCLKernelNamingDecl(const NamedDecl *RD) const;
unsigned GetSYCLKernelNamingIndex(const NamedDecl *RD) const;
unsigned GetSYCLKernelNamingIndex(const NamedDecl *RD);
/// A SourceLocation to store whether we have evaluated a kernel name already,
/// and where it happened. If so, we need to diagnose an illegal use of the
/// builtin.
@ -3185,6 +3186,10 @@ private:
llvm::DenseMap<const DeclContext *,
llvm::SmallPtrSet<const CXXRecordDecl *, 4>>
SYCLKernelNamingTypes;
std::unique_ptr<ItaniumMangleContext> SYCLKernelFilterContext;
void FilterSYCLKernelNamingDecls(
const CXXRecordDecl *RD,
llvm::SmallVectorImpl<const CXXRecordDecl *> &Decls);
};
/// Insertion operator for diagnostics.

View File

@ -11715,25 +11715,27 @@ bool ASTContext::IsSYCLKernelNamingDecl(const NamedDecl *ND) const {
// Filters the Decls list to those that share the lambda mangling with the
// passed RD.
static void FilterSYCLKernelNamingDecls(
ASTContext &Ctx, const CXXRecordDecl *RD,
void ASTContext::FilterSYCLKernelNamingDecls(
const CXXRecordDecl *RD,
llvm::SmallVectorImpl<const CXXRecordDecl *> &Decls) {
static std::unique_ptr<ItaniumMangleContext> Mangler{
ItaniumMangleContext::create(Ctx, Ctx.getDiagnostics())};
if (!SYCLKernelFilterContext)
SYCLKernelFilterContext.reset(
ItaniumMangleContext::create(*this, getDiagnostics()));
llvm::SmallString<128> LambdaSig;
llvm::raw_svector_ostream Out(LambdaSig);
Mangler->mangleLambdaSig(RD, Out);
SYCLKernelFilterContext->mangleLambdaSig(RD, Out);
llvm::erase_if(Decls, [&LambdaSig](const CXXRecordDecl *LocalRD) {
llvm::erase_if(Decls, [this, &LambdaSig](const CXXRecordDecl *LocalRD) {
llvm::SmallString<128> LocalLambdaSig;
llvm::raw_svector_ostream LocalOut(LocalLambdaSig);
Mangler->mangleLambdaSig(LocalRD, LocalOut);
SYCLKernelFilterContext->mangleLambdaSig(LocalRD, LocalOut);
return LambdaSig != LocalLambdaSig;
});
}
unsigned ASTContext::GetSYCLKernelNamingIndex(const NamedDecl *ND) const {
unsigned ASTContext::GetSYCLKernelNamingIndex(const NamedDecl *ND) {
assert(getLangOpts().isSYCL() && "Only valid for SYCL programs");
assert(IsSYCLKernelNamingDecl(ND) &&
"Lambda not involved in mangling asked for a naming index?");
@ -11753,7 +11755,7 @@ unsigned ASTContext::GetSYCLKernelNamingIndex(const NamedDecl *ND) const {
// doesn't use the itanium mangler, and just sets the lambda mangling number
// incrementally, with no consideration to the signature.
if (Target->getCXXABI().getKind() != TargetCXXABI::Microsoft)
FilterSYCLKernelNamingDecls(const_cast<ASTContext &>(*this), RD, Decls);
FilterSYCLKernelNamingDecls(RD, Decls);
llvm::sort(Decls, [](const CXXRecordDecl *LHS, const CXXRecordDecl *RHS) {
return LHS->getLambdaManglingNumber() < RHS->getLambdaManglingNumber();

View File

@ -0,0 +1,18 @@
// RUN: %clang_cc1 %s %s -std=c++17 -triple x86_64-linux-gnu -fsycl-is-device -verify -fsyntax-only -Wno-unused
// This would crash due to the double-inputs, since the 'magic static' use in
// the AST Context SCYL Filtering would end up caching an old version of the
// ASTContext object, which no longer exists in the second file's invocation.
//
// expected-no-diagnostics
class Empty {};
template <typename, typename F> __attribute__((sycl_kernel)) void kernel(F) {
__builtin_sycl_unique_stable_name(F);
}
void use() {
[](Empty) {
auto lambda = []{};
kernel<class i>(lambda);
};
}