Skip to content
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
2 changes: 1 addition & 1 deletion include/swift/AST/IfConfigClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ struct IfConfigClause {
ArrayRef<ASTNode> Elements;

/// True if this is the active clause of the #if block.
bool isActive;
const bool isActive;

IfConfigClause(SourceLoc Loc, Expr *Cond,
ArrayRef<ASTNode> Elements, bool isActive)
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/SourceFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,9 @@ class SourceFile final : public FileUnit {

OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName) override;

/// Do not call when inside an inactive clause (\c
/// InInactiveClauseEnvironment)) because it will later on result in a lookup
/// to something that won't be in the ASTScope tree.
void addUnvalidatedDeclWithOpaqueResultType(ValueDecl *vd) {
UnvalidatedDeclsWithOpaqueReturnTypes.insert(vd);
}
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ class Parser {

bool InPoundLineEnvironment = false;
bool InPoundIfEnvironment = false;
/// Do not call \c addUnvalidatedDeclWithOpaqueResultType when in an inactive
/// clause because ASTScopes are not created in those contexts and lookups to
/// those decls will fail.
bool InInactiveClauseEnvironment = false;
bool InSwiftKeyPath = false;

LocalContext *CurLocalContext = nullptr;
Expand Down
46 changes: 46 additions & 0 deletions lib/AST/ASTScopeLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ using namespace swift;
using namespace namelookup;
using namespace ast_scope;

static bool isLocWithinAnInactiveClause(const SourceLoc loc, SourceFile *SF);

llvm::SmallVector<const ASTScopeImpl *, 0> ASTScopeImpl::unqualifiedLookup(
SourceFile *sourceFile, const DeclName name, const SourceLoc loc,
const DeclContext *const startingContext, DeclConsumer consumer) {
Expand Down Expand Up @@ -82,6 +84,12 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup(
if (!startingScope) {
llvm::errs() << "ASTScopeImpl: resorting to startingScope hack, file: "
<< sourceFile->getFilename() << "\n";
// The check is costly, and inactive lookups will end up here, so don't
// do the check unless we can't find the startingScope.
const bool isInInactiveClause =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t understand why we need this part, of the parser isn’t going to add these decls in the first place for inactive regions?

Copy link
Contributor Author

@davidungar davidungar Oct 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tx for looking this over.

The idea is that lookups to things in inactive clauses may creep back in at some point. If they do, this part will output a more specific message for debugging, and also, as per your preference, will crash the compilation. It only runs when the ASTScope code cannot find the starting scope anyway, so it doesn't slow down compilation unless there's an error.

When someday, we rip out all the code that passed DeclContexts into UnqualifiedLookup, the whole did-not-find starting scope stuff will get ripped out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay!

isLocWithinAnInactiveClause(loc, sourceFile);
if (isInInactiveClause)
llvm::errs() << " because location is within an inactive clause\n";
llvm::errs() << "'";
name.print(llvm::errs());
llvm::errs() << "' ";
Expand All @@ -98,6 +106,11 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup(
// Might distort things
// if (fileScope->crossCheckWithAST())
// llvm::errs() << "Tree creation missed some DeclContexts.\n";

// Crash compilation even if NDEBUG
if (isInInactiveClause)
llvm::report_fatal_error(
"A lookup was attempted into an inactive clause");
}

ASTScopeAssert(startingScope, "ASTScopeImpl: could not find startingScope");
Expand Down Expand Up @@ -694,3 +707,36 @@ Optional<bool> PatternEntryInitializerScope::resolveIsCascadingUseForThisScope(

return isCascadingUse;
}

bool isLocWithinAnInactiveClause(const SourceLoc loc, SourceFile *SF) {
class InactiveClauseTester : public ASTWalker {
const SourceLoc loc;
const SourceManager &SM;

public:
bool wasFoundWithinInactiveClause = false;

InactiveClauseTester(const SourceLoc loc, const SourceManager &SM)
: loc(loc), SM(SM) {}

bool walkToDeclPre(Decl *D) override {
if (const auto *ifc = dyn_cast<IfConfigDecl>(D)) {
for (const auto &clause : ifc->getClauses()) {
if (clause.isActive)
continue;
for (const auto n : clause.Elements) {
SourceRange sr = n.getSourceRange();
if (sr.isValid() && SM.rangeContainsTokenLoc(sr, loc)) {
wasFoundWithinInactiveClause = true;
return false;
}
}
}
}
return ASTWalker::walkToDeclPre(D);
}
};
InactiveClauseTester tester(loc, SF->getASTContext().SourceMgr);
SF->walk(tester);
return tester.wasFoundWithinInactiveClause;
}
8 changes: 5 additions & 3 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5163,7 +5163,7 @@ Parser::parseDeclVar(ParseDeclOptions Flags,
VD->getAttrs() = Attributes;
setLocalDiscriminator(VD);
Decls.push_back(VD);
if (hasOpaqueReturnTy && sf) {
if (hasOpaqueReturnTy && sf && !InInactiveClauseEnvironment) {
sf->addUnvalidatedDeclWithOpaqueResultType(VD);
}
});
Expand Down Expand Up @@ -5479,7 +5479,8 @@ ParserResult<FuncDecl> Parser::parseDeclFunc(SourceLoc StaticLoc,
CurDeclContext);

// Let the source file track the opaque return type mapping, if any.
if (FuncRetTy && isa<OpaqueReturnTypeRepr>(FuncRetTy)) {
if (FuncRetTy && isa<OpaqueReturnTypeRepr>(FuncRetTy) &&
!InInactiveClauseEnvironment) {
if (auto sf = CurDeclContext->getParentSourceFile()) {
sf->addUnvalidatedDeclWithOpaqueResultType(FD);
}
Expand Down Expand Up @@ -6354,7 +6355,8 @@ Parser::parseDeclSubscript(SourceLoc StaticLoc,
Subscript->getAttrs() = Attributes;

// Let the source file track the opaque return type mapping, if any.
if (ElementTy.get() && isa<OpaqueReturnTypeRepr>(ElementTy.get())) {
if (ElementTy.get() && isa<OpaqueReturnTypeRepr>(ElementTy.get()) &&
!InInactiveClauseEnvironment) {
if (auto sf = CurDeclContext->getParentSourceFile()) {
sf->addUnvalidatedDeclWithOpaqueResultType(Subscript);
}
Expand Down
2 changes: 2 additions & 0 deletions lib/Parse/ParseIfConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,8 @@ ParserResult<IfConfigDecl> Parser::parseIfConfig(

// Parse elements
SmallVector<ASTNode, 16> Elements;
llvm::SaveAndRestore<bool> S(InInactiveClauseEnvironment,
InInactiveClauseEnvironment || !isActive);
if (isActive || !isVersionCondition) {
parseElements(Elements, isActive);
} else if (SyntaxContext->isEnabled()) {
Expand Down
14 changes: 14 additions & 0 deletions test/NameBinding/disabled_opaque_decl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Ensure scope construction does not crash
// RUN: %target-swift-frontend -emit-module %s

public protocol P { }

extension Int: P { }

#if false
public struct Foo {
public func getP() -> some P {
return 17
}
}
#endif