Skip to content

Commit 879a10b

Browse files
committed
[Macros] Ensure that the type refinement context accounts for macros
Make sure that we include all of the AST nodes from a macro expansion buffer when building the type refinement context, not just the declarations.
1 parent aa127f7 commit 879a10b

File tree

3 files changed

+71
-9
lines changed

3 files changed

+71
-9
lines changed

lib/AST/TypeRefinementContext.cpp

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,25 @@ TypeRefinementContext::createRoot(SourceFile *SF,
4646
assert(SF);
4747

4848
ASTContext &Ctx = SF->getASTContext();
49+
50+
SourceRange range;
51+
TypeRefinementContext *parentContext = nullptr;
52+
AvailabilityContext availabilityContext = Info;
53+
if (auto parentExpansion = SF->getMacroExpansion()) {
54+
if (auto parentTRC =
55+
SF->getEnclosingSourceFile()->getTypeRefinementContext()) {
56+
auto charRange = Ctx.SourceMgr.getRangeForBuffer(*SF->getBufferID());
57+
range = SourceRange(charRange.getStart(), charRange.getEnd());
58+
parentContext = parentTRC->findMostRefinedSubContext(
59+
parentExpansion.getStartLoc(), Ctx.SourceMgr);
60+
availabilityContext = parentContext->getAvailabilityInfo();
61+
}
62+
}
63+
4964
return new (Ctx)
50-
TypeRefinementContext(Ctx, SF,
51-
/*Parent=*/nullptr, SourceRange(),
52-
Info, AvailabilityContext::alwaysAvailable());
65+
TypeRefinementContext(Ctx, SF, parentContext, range,
66+
availabilityContext,
67+
AvailabilityContext::alwaysAvailable());
5368
}
5469

5570
TypeRefinementContext *
@@ -147,12 +162,34 @@ TypeRefinementContext::createForWhileStmtBody(ASTContext &Ctx, WhileStmt *S,
147162
Ctx, S, Parent, S->getBody()->getSourceRange(), Info, /* ExplicitInfo */Info);
148163
}
149164

165+
/// Determine whether the child location is somewhere within the parent
166+
/// range.
167+
static bool rangeContainsTokenLocWithGeneratedSource(
168+
SourceManager &sourceMgr, SourceRange parentRange, SourceLoc childLoc) {
169+
auto parentBuffer = sourceMgr.findBufferContainingLoc(parentRange.Start);
170+
auto childBuffer = sourceMgr.findBufferContainingLoc(childLoc);
171+
while (parentBuffer != childBuffer) {
172+
auto info = sourceMgr.getGeneratedSourceInfo(childBuffer);
173+
if (!info)
174+
return false;
175+
176+
childLoc = info->originalSourceRange.getStart();
177+
if (childLoc.isInvalid())
178+
return false;
179+
180+
childBuffer = sourceMgr.findBufferContainingLoc(childLoc);
181+
}
182+
183+
return sourceMgr.rangeContainsTokenLoc(parentRange, childLoc);
184+
}
185+
150186
TypeRefinementContext *
151187
TypeRefinementContext::findMostRefinedSubContext(SourceLoc Loc,
152188
SourceManager &SM) {
153189
assert(Loc.isValid());
154190

155-
if (SrcRange.isValid() && !SM.rangeContainsTokenLoc(SrcRange, Loc))
191+
if (SrcRange.isValid() &&
192+
!rangeContainsTokenLocWithGeneratedSource(SM, SrcRange, Loc))
156193
return nullptr;
157194

158195
// For the moment, we perform a linear search here, but we can and should

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,8 +1232,13 @@ void TypeChecker::buildTypeRefinementContextHierarchy(SourceFile &SF) {
12321232
// Build refinement contexts, if necessary, for all declarations starting
12331233
// with StartElem.
12341234
TypeRefinementContextBuilder Builder(RootTRC, Context);
1235-
for (auto D : SF.getTopLevelDecls()) {
1236-
Builder.build(D);
1235+
for (auto item : SF.getTopLevelItems()) {
1236+
if (auto decl = item.dyn_cast<Decl *>())
1237+
Builder.build(decl);
1238+
else if (auto expr = item.dyn_cast<Expr *>())
1239+
Builder.build(expr);
1240+
else if (auto stmt = item.dyn_cast<Stmt *>())
1241+
Builder.build(stmt);
12371242
}
12381243
}
12391244

@@ -1272,7 +1277,11 @@ AvailabilityContext
12721277
TypeChecker::overApproximateAvailabilityAtLocation(SourceLoc loc,
12731278
const DeclContext *DC,
12741279
const TypeRefinementContext **MostRefined) {
1275-
SourceFile *SF = DC->getParentSourceFile();
1280+
SourceFile *SF;
1281+
if (loc.isValid())
1282+
SF = DC->getParentModule()->getSourceFileContainingLocation(loc);
1283+
else
1284+
SF = DC->getParentSourceFile();
12761285
auto &Context = DC->getASTContext();
12771286

12781287
// If our source location is invalid (this may be synthesized code), climb

test/Macros/macro_availability_macosx.swift

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
// REQUIRES: swift_swift_parser, OS=macosx
1+
// REQUIRES: swift_swift_parser, executable_test, OS=macosx
22

3-
// RUN: %target-typecheck-verify-swift -swift-version 5 -module-name MacrosTest -target %target-cpu-apple-macosx11
3+
// RUN: %empty-directory(%t)
4+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath -swift-version 5
5+
6+
// RUN: %target-typecheck-verify-swift -swift-version 5 -module-name MacrosTest -target %target-cpu-apple-macosx11 -load-plugin-library %t/%target-library-name(MacroDefinition)
47

58
@available(macOS 12.0, *)
69
struct X { }
@@ -11,3 +14,16 @@ struct X { }
1114
@available(macOS 12.0, *)
1215
@freestanding(expression) macro m2() -> X = #externalMacro(module: "A", type: "B")
1316
// expected-warning@-1{{external macro implementation type 'A.B' could not be found for macro 'm2()'}}
17+
18+
@freestanding(expression) macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")
19+
20+
@available(macOS 12.0, *)
21+
func onlyInMacOS12() { }
22+
23+
func test() {
24+
_ = #stringify({
25+
if #available(macOS 12.0, *) {
26+
onlyInMacOS12()
27+
}
28+
})
29+
}

0 commit comments

Comments
 (0)