Skip to content

Add support for nested ASTScopes inside of macro expansions. … @adrian-prantl #65402

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 1 commit into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all 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 include/swift/AST/ASTScope.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ class ASTSourceFileScope final : public ASTScopeImpl {
NullablePtr<const void> addressForPrinting() const override { return SF; }

ASTContext &getASTContext() const override;
bool ignoreInDebugInfo() const override { return true; }

protected:
ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override;
Expand Down
8 changes: 8 additions & 0 deletions lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2171,6 +2171,14 @@ void IRGenDebugInfoImpl::setCurrentLoc(IRBuilder &Builder,
assert(parentScopesAreSane(DS) && "parent scope sanity check failed");
auto DL = llvm::DILocation::get(IGM.getLLVMContext(), L.line, L.column, Scope,
InlinedAt);
#ifndef NDEBUG
{
llvm::DILocalScope *Scope = DL->getInlinedAtScope();
llvm::DISubprogram *SP = Scope->getSubprogram();
llvm::Function *F = Builder.GetInsertBlock()->getParent();
assert((!F || SP->describes(F)) && "location points to different function");
}
#endif
Builder.SetCurrentDebugLocation(DL);
}

Expand Down
139 changes: 77 additions & 62 deletions lib/SILGen/SILGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ SILGenFunction::SILGenFunction(SILGenModule &SGM, SILFunction &F,
SourceLoc SLoc = F.getLocation().getSourceLoc();
if (SF && SLoc) {
FnASTScope = ast_scope::ASTScopeImpl::findStartingScopeForLookup(SF, SLoc);
ScopeMap.insert({FnASTScope, F.getDebugScope()});
ScopeMap.insert({{FnASTScope, nullptr}, F.getDebugScope()});
}
}

Expand Down Expand Up @@ -215,47 +215,49 @@ const SILDebugScope *SILGenFunction::getOrCreateScope(SourceLoc SLoc) {
if (!astScope->getParent())
return nullptr;

const SILDebugScope *Scope = getOrCreateScope(astScope);
const SILDebugScope *Scope = getOrCreateScope(astScope, F.getDebugScope());
assert(Scope && "failed to construct SILDebugScope from ASTScope");
return Scope;
}

namespace {
struct MacroInfo {
MacroInfo(SourceLoc SLoc) : Loc(SLoc) {}
RegularLocation Loc;
std::string Name;
MacroInfo(SourceLoc SLoc, SourceLoc ExpansionSLoc)
: SLoc(SLoc), ExpansionSLoc(ExpansionSLoc) {}
SourceLoc SLoc;
SourceLoc ExpansionSLoc;
RegularLocation ExpansionLoc = RegularLocation((Decl*)nullptr);
std::string Name = "__unknown_macro__";
bool Freestanding = false;
};
}

/// Return location of the macro expansion and the macro name.
static MacroInfo getMacroInfo(GeneratedSourceInfo &Info) {
SourceLoc MacroSLoc = Info.generatedSourceRange.getStart();
MacroInfo Result(MacroSLoc);
Result.Name = "__unknown_macro__";
MacroInfo Result(Info.generatedSourceRange.getStart(),
Info.originalSourceRange.getStart());
if (!Info.astNode)
return Result;

// Keep this in sync with ASTMangler::appendMacroExpansionContext().
Mangle::ASTMangler mangler;
switch (Info.kind) {
case GeneratedSourceInfo::ExpressionMacroExpansion: {
auto parent = ASTNode::getFromOpaqueValue(Info.astNode);
if (auto expr =
cast_or_null<MacroExpansionExpr>(parent.dyn_cast<Expr *>())) {
Result.Loc = RegularLocation(expr);
Result.ExpansionLoc = RegularLocation(expr);
Result.Name = mangler.mangleMacroExpansion(expr);
} else {
auto decl = cast<MacroExpansionDecl>(parent.get<Decl *>());
Result.Loc = RegularLocation(decl);
Result.ExpansionLoc = RegularLocation(decl);
Result.Name = mangler.mangleMacroExpansion(decl);
}
break;
}
case GeneratedSourceInfo::FreestandingDeclMacroExpansion: {
auto expansion = cast<MacroExpansionDecl>(
ASTNode::getFromOpaqueValue(Info.astNode).get<Decl *>());
Result.Loc = RegularLocation(expansion);
Result.ExpansionLoc = RegularLocation(expansion);
Result.Name = mangler.mangleMacroExpansion(expansion);
Result.Freestanding = true;
break;
Expand All @@ -268,7 +270,7 @@ static MacroInfo getMacroInfo(GeneratedSourceInfo &Info) {
auto decl = ASTNode::getFromOpaqueValue(Info.astNode).get<Decl *>();
auto attr = Info.attachedMacroCustomAttr;
if (auto *macroDecl = decl->getResolvedMacro(attr)) {
Result.Loc = RegularLocation(macroDecl);
Result.ExpansionLoc = RegularLocation(macroDecl);
Result.Name = macroDecl->getBaseName().userFacingName();
Result.Freestanding = true;
}
Expand Down Expand Up @@ -297,61 +299,67 @@ const SILDebugScope *SILGenFunction::getMacroScope(SourceLoc SLoc) {
if (Macro.Freestanding)
return nullptr;

SourceLoc OrigSLoc = GeneratedSourceInfo->originalSourceRange.getStart();
if (!OrigSLoc)
return nullptr;

const SILDebugScope *TopLevelScope;
auto It = InlinedScopeMap.find(BufferID);
if (It != InlinedScopeMap.end())
return It->second;
TopLevelScope = It->second;
else {
// Recursively create one inlined function + scope per layer of generated
// sources. Chains of Macro expansions are representad as flat
// function-level scopes.
SILGenFunctionBuilder B(SGM);
auto &ASTContext = SGM.M.getASTContext();
auto ExtInfo = SILFunctionType::ExtInfo::getThin();
auto FunctionType = SILFunctionType::get(
nullptr, ExtInfo, SILCoroutineKind::None,
ParameterConvention::Direct_Unowned, /*Params*/ {},
/*yields*/
{},
/*Results*/ {}, None, SubstitutionMap(), SubstitutionMap(), ASTContext);
StringRef MacroName = ASTContext.getIdentifier(Macro.Name).str();
RegularLocation MacroLoc(Macro.SLoc);
// Use the ExpansionLoc as the location so IRGenDebugInfo can extract the
// human-readable macro name from the MacroExpansionDecl.
SILFunction *MacroFn = B.getOrCreateFunction(
Macro.ExpansionLoc, MacroName,
SILLinkage::DefaultForDeclaration, FunctionType, IsNotBare,
IsNotTransparent, IsNotSerialized, IsNotDynamic, IsNotDistributed,
IsNotRuntimeAccessible);
// At the end of the chain ExpansionLoc should be a macro expansion node.
const SILDebugScope *InlinedAt = nullptr;
const SILDebugScope *ExpansionScope = getOrCreateScope(Macro.ExpansionSLoc);

// Inject an extra scope to hold the inlined call site.
if (ExpansionScope)
InlinedAt = new (SGM.M)
SILDebugScope(Macro.ExpansionLoc, nullptr, ExpansionScope,
ExpansionScope->InlinedCallSite);

TopLevelScope =
new (SGM.M) SILDebugScope(MacroLoc, MacroFn, nullptr, InlinedAt);

InlinedScopeMap.insert({BufferID, TopLevelScope});
}

// Recursively create one inlined function + scope per layer of generated
// sources. Chains of Macro expansions are representad as flat function-level
// scopes.
SILGenFunctionBuilder B(SGM);
auto &ASTContext = SGM.M.getASTContext();
auto ExtInfo = SILFunctionType::ExtInfo::getThin();
auto FunctionType = SILFunctionType::get(
nullptr, ExtInfo, SILCoroutineKind::None,
ParameterConvention::Direct_Unowned, /*Params*/ {},
/*yields*/
{},
/*Results*/ {}, None, SubstitutionMap(), SubstitutionMap(), ASTContext);
StringRef MacroName = ASTContext.getIdentifier(Macro.Name).str();

SILFunction *MacroFn = B.getOrCreateFunction(
Macro.Loc, MacroName, SILLinkage::DefaultForDeclaration, FunctionType,
IsNotBare, IsNotTransparent, IsNotSerialized, IsNotDynamic,
IsNotDistributed, IsNotRuntimeAccessible);
// At the end of the chain OrigSLoc should be a macro expansion node.
const SILDebugScope *InlinedAt = nullptr;
const SILDebugScope *OrigScope = getOrCreateScope(OrigSLoc);
RegularLocation OrigLoc(OrigSLoc);
// Inject an extra scope to hold the inlined call site.
if (OrigScope)
InlinedAt = new (SGM.M)
SILDebugScope(Macro.Freestanding ? Macro.Loc : OrigLoc, nullptr,
OrigScope, OrigScope->InlinedCallSite);

const SILDebugScope *Scope =
new (SGM.M) SILDebugScope(Macro.Loc, MacroFn, nullptr, InlinedAt);

InlinedScopeMap.insert({BufferID, Scope});
return Scope;
// Create the scope hierarchy inside the macro expansion.
auto *MacroAstScope =
ast_scope::ASTScopeImpl::findStartingScopeForLookup(SF, Macro.SLoc);
return getOrCreateScope(MacroAstScope, TopLevelScope,
TopLevelScope->InlinedCallSite);
}

const SILDebugScope *
SILGenFunction::getOrCreateScope(const ast_scope::ASTScopeImpl *ASTScope) {
const SILDebugScope *FnScope = F.getDebugScope();

SILGenFunction::getOrCreateScope(const ast_scope::ASTScopeImpl *ASTScope,
const SILDebugScope *FnScope,
const SILDebugScope *InlinedAt) {
if (!ASTScope)
return FnScope;

// Top-level function scope?
if (ASTScope == FnASTScope)
return FnScope;

auto It = ScopeMap.find(ASTScope);
auto It = ScopeMap.find({ASTScope, InlinedAt});
if (It != ScopeMap.end())
return It->second;

Expand All @@ -374,20 +382,21 @@ SILGenFunction::getOrCreateScope(const ast_scope::ASTScopeImpl *ASTScope) {
// Since the arguments to Constructor aren't marked as implicit,
// argument b is in the scope of v, but the call to Constructor
// isn't, which correctly triggers the scope hole verifier.
return B.getCurrentDebugScope();
auto *CurScope = B.getCurrentDebugScope();
return CurScope->InlinedCallSite != InlinedAt ? FnScope : CurScope;
}

// Collapse BraceStmtScopes whose parent is a .*BodyScope.
if (auto Parent = ASTScope->getParent().getPtrOrNull())
if (Parent->getSourceRangeOfThisASTNode() ==
ASTScope->getSourceRangeOfThisASTNode())
return getOrCreateScope(Parent);
return getOrCreateScope(Parent, FnScope, InlinedAt);

// The calls to defer closures have cleanup source locations pointing to the
// defer. Reparent them into the current debug scope.
auto *AncestorScope = ASTScope->getParent().getPtrOrNull();
while (AncestorScope && AncestorScope != FnASTScope &&
!ScopeMap.count(AncestorScope)) {
!ScopeMap.count({AncestorScope, InlinedAt})) {
if (auto *FD = dyn_cast_or_null<FuncDecl>(
AncestorScope->getDeclIfAny().getPtrOrNull())) {
if (cast<DeclContext>(FD) != FunctionDC)
Expand All @@ -404,10 +413,16 @@ SILGenFunction::getOrCreateScope(const ast_scope::ASTScopeImpl *ASTScope) {
};

const SILDebugScope *Parent =
getOrCreateScope(ASTScope->getParent().getPtrOrNull());
RegularLocation Loc(ASTScope->getSourceRangeOfThisASTNode().Start);
SILScope = new (SGM.M) SILDebugScope(Loc, &F, Parent);
ScopeMap.insert({ASTScope, SILScope});
getOrCreateScope(ASTScope->getParent().getPtrOrNull(), FnScope, InlinedAt);
SourceLoc SLoc = ASTScope->getSourceRangeOfThisASTNode().Start;
RegularLocation Loc(SLoc);
SILScope = new (SGM.M)
SILDebugScope(Loc, FnScope->getParentFunction(), Parent, InlinedAt);
ScopeMap.insert({{ASTScope, InlinedAt}, SILScope});

assert(SILScope->getParentFunction() == &F &&
"inlinedAt points to other function");

return SILScope;
}

Expand Down
10 changes: 7 additions & 3 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
using ASTScopeTy = ast_scope::ASTScopeImpl;
const ASTScopeTy *FnASTScope = nullptr;
/// Caches one SILDebugScope for each ASTScope.
llvm::SmallDenseMap<const ASTScopeTy *, const SILDebugScope *, 16> ScopeMap;
/// Caches one inline SILDebugScope for each macro BufferID.
llvm::SmallDenseMap<std::pair<const ASTScopeTy *, const SILDebugScope *>,
const SILDebugScope *, 16>
ScopeMap;
/// Caches one toplevel inline SILDebugScope for each macro BufferID.
llvm::SmallDenseMap<unsigned, const SILDebugScope *, 16> InlinedScopeMap;

/// The cleanup depth and BB for when the operand of a
Expand Down Expand Up @@ -720,7 +722,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
const SILDebugScope *getOrCreateScope(SourceLoc SLoc);
const SILDebugScope *getMacroScope(SourceLoc SLoc);
const SILDebugScope *
getOrCreateScope(const ast_scope::ASTScopeImpl *ASTScope);
getOrCreateScope(const ast_scope::ASTScopeImpl *ASTScope,
const SILDebugScope *FnScope,
const SILDebugScope *InlinedAt = nullptr);

public:
/// Enter the debug scope for \p Loc, creating it if necessary.
Expand Down
4 changes: 2 additions & 2 deletions test/Macros/macro_expand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ struct Bad {}
func testFileID(a: Int, b: Int) {
// CHECK: MacroUser/macro_expand.swift
print("Result is \(#customFileID)")
// CHECK-SIL: sil_scope [[SRC_SCOPE:[0-9]+]] { loc "{{.*}}macro_expand.swift":[[@LINE-3]]
// CHECK-SIL: sil_scope [[SRC_SCOPE:[0-9]+]] { loc "{{.*}}macro_expand.swift":[[@LINE-3]]:6 parent {{.*}}testFileID
// CHECK-SIL: sil_scope [[EXPANSION_SCOPE:[0-9]+]] { loc "{{.*}}macro_expand.swift":[[@LINE-2]]:22 parent [[SRC_SCOPE]]
// CHECK-SIL: sil_scope [[MACRO_SCOPE:[0-9]+]] { loc "{{.*}}":[[@LINE-3]]:22 parent @$s9MacroUser10testFileID1a1bySi_SitF06customdE0fMf_ {{.*}} inlined_at [[EXPANSION_SCOPE]] }
// CHECK-SIL: sil_scope [[MACRO_SCOPE:[0-9]+]] { loc "@__swiftmacro{{.*}}":1:1 parent @$s9MacroUser10testFileID1a1bySi_SitF06customdE0fMf_ {{.*}} inlined_at [[EXPANSION_SCOPE]] }
// CHECK-SIL: string_literal utf8 "MacroUser/macro_expand.swift", loc "@__swiftmacro_9MacroUser10testFileID1a1bySi_SitF06customdE0fMf_.swift":1:1, scope [[MACRO_SCOPE]]
// CHECK-IR-DAG: !DISubprogram(name: "customFileID", linkageName: "$s9MacroUser10testFileID1a1bySi_SitF06customdE0fMf_"

Expand Down