Skip to content

[Macros] Ensure that macro expansion parsing has appropriate context. #61972

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
Nov 8, 2022
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
7 changes: 6 additions & 1 deletion include/swift/Parse/LocalContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@ class LocalContext {
/// True if we saw any anonymous closures. This is useful when
/// parsing an initializer context, because such contexts only
/// need to exist if the initializer contains closures.
bool hasClosures() const { return NextClosureDiscriminator != 0; }
bool hasClosures() const { return NextClosureDiscriminator != 0; }

/// Override the next closure discriminator value.
void overrideNextClosureDiscriminator(unsigned discriminator) {
NextClosureDiscriminator = discriminator;
}
};

/// Information associated with parsing the top-level context.
Expand Down
49 changes: 22 additions & 27 deletions lib/Sema/DebuggerTestingTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,36 +32,31 @@

using namespace swift;

namespace {
ASTWalker::PostWalkResult<Expr *>
DiscriminatorFinder::walkToExprPost(Expr *E) {
auto *ACE = dyn_cast<AbstractClosureExpr>(E);
if (!ACE)
return Action::Continue(E);

/// Find available closure discriminators.
///
/// The parser typically takes care of assigning unique discriminators to
/// closures, but the parser is unavailable during semantic analysis.
class DiscriminatorFinder : public ASTWalker {
unsigned NextDiscriminator = 0;
unsigned Discriminator = ACE->getDiscriminator();
assert(Discriminator != AbstractClosureExpr::InvalidDiscriminator &&
"Existing closures should have valid discriminators");
if (Discriminator >= NextDiscriminator)
NextDiscriminator = Discriminator + 1;
if (FirstDiscriminator == AbstractClosureExpr::InvalidDiscriminator ||
Discriminator < FirstDiscriminator)
FirstDiscriminator = Discriminator;

public:
PostWalkResult<Expr *> walkToExprPost(Expr *E) override {
auto *ACE = dyn_cast<AbstractClosureExpr>(E);
if (!ACE)
return Action::Continue(E);

unsigned Discriminator = ACE->getDiscriminator();
assert(Discriminator != AbstractClosureExpr::InvalidDiscriminator &&
"Existing closures should have valid discriminators");
if (Discriminator >= NextDiscriminator)
NextDiscriminator = Discriminator + 1;
return Action::Continue(E);
}
return Action::Continue(E);
}

// Get the next available closure discriminator.
unsigned getNextDiscriminator() {
if (NextDiscriminator == AbstractClosureExpr::InvalidDiscriminator)
llvm::report_fatal_error("Out of valid closure discriminators");
return NextDiscriminator++;
}
};
unsigned DiscriminatorFinder::getNextDiscriminator() {
if (NextDiscriminator == AbstractClosureExpr::InvalidDiscriminator)
llvm::report_fatal_error("Out of valid closure discriminators");
return NextDiscriminator++;
}

namespace {

/// Instrument decls with sanity-checks which the debugger can evaluate.
class DebuggerTestingTransform : public ASTWalker {
Expand Down
20 changes: 20 additions & 0 deletions lib/Sema/TypeCheckMacros.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,26 @@ Expr *swift::expandMacroExpr(
// Parse the expression.
Parser parser(macroBufferID, *macroSourceFile, &ctx.Diags, nullptr, nullptr);
parser.consumeTokenWithoutFeedingReceiver();

// Set up a "local context" for parsing, so that we have a source of
// closure and local-variable discriminators.
LocalContext tempContext{};
parser.CurDeclContext = dc;
parser.CurLocalContext = &tempContext;
{
DiscriminatorFinder finder;
expr->walk(finder);

unsigned closureDiscriminator;
if (finder.getFirstDiscriminator() ==
AbstractClosureExpr::InvalidDiscriminator)
closureDiscriminator = 0;
else
closureDiscriminator = finder.getFirstDiscriminator() + 1;

tempContext.overrideNextClosureDiscriminator(closureDiscriminator);
}

auto parsedResult = parser.parseExpr(diag::expected_macro_expansion_expr);
if (parsedResult.isParseError() || parsedResult.isNull()) {
// Tack on a note to say where we expanded the macro from?
Expand Down
16 changes: 16 additions & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -1499,6 +1499,22 @@ diagnoseAndRemoveAttr(const Decl *D, const DeclAttribute *attr,
return diagnoseAttrWithRemovalFixIt(D, attr, std::forward<ArgTypes>(Args)...);
}

/// Look for closure discriminators within an AST.
class DiscriminatorFinder : public ASTWalker {
unsigned FirstDiscriminator = AbstractClosureExpr::InvalidDiscriminator;
unsigned NextDiscriminator = 0;

public:
PostWalkResult<Expr *> walkToExprPost(Expr *E) override;

// Get the next available closure discriminator.
unsigned getNextDiscriminator();

unsigned getFirstDiscriminator() const {
return FirstDiscriminator;
}
};

} // end namespace swift

#endif
5 changes: 5 additions & 0 deletions test/Macros/macros.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@ func test(a: Int, b: Int) {
// CHECK: macro_expansion_expr type='(Int, String)'{{.*}}name=stringify
// CHECK-NEXT: argument_list
// CHECK: tuple_expr type='(Int, String)' location=Macro expansion of #stringify

let (b, s2) = #stringify({ () -> Bool in return true })
// CHECK: macro_expansion_expr type='(() -> Bool, String)'{{.*}}name=stringify
// CHECK-NEXT: argument_list
// CHECK: tuple_expr type='(() -> Bool, String)' location=Macro expansion of #stringify
}