mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Stop parsing into IfConfiDecl nodes in the C++ parser
When parsing #if...#endif regions, parse the active clause directly into place in the AST without ever producing an IfConfigDecl instance.
This commit is contained in:
@@ -977,10 +977,10 @@ public:
|
|||||||
|
|
||||||
void consumeDecl(ParserPosition BeginParserPosition, bool IsTopLevel);
|
void consumeDecl(ParserPosition BeginParserPosition, bool IsTopLevel);
|
||||||
|
|
||||||
ParserResult<Decl> parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
|
ParserStatus parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
|
||||||
bool IfConfigsAreDeclAttrs,
|
bool IfConfigsAreDeclAttrs,
|
||||||
llvm::function_ref<void(Decl *)> Handler,
|
llvm::function_ref<void(Decl *)> Handler,
|
||||||
bool fromASTGen = false);
|
bool fromASTGen = false);
|
||||||
|
|
||||||
std::pair<std::vector<Decl *>, std::optional<Fingerprint>>
|
std::pair<std::vector<Decl *>, std::optional<Fingerprint>>
|
||||||
parseDeclListDelayed(IterableDeclContext *IDC);
|
parseDeclListDelayed(IterableDeclContext *IDC);
|
||||||
@@ -1018,9 +1018,9 @@ public:
|
|||||||
|
|
||||||
/// Parse a #if ... #endif directive.
|
/// Parse a #if ... #endif directive.
|
||||||
/// Delegate callback function to parse elements in the blocks.
|
/// Delegate callback function to parse elements in the blocks.
|
||||||
ParserResult<IfConfigDecl> parseIfConfig(
|
ParserStatus parseIfConfig(
|
||||||
IfConfigContext ifConfigContext,
|
IfConfigContext ifConfigContext,
|
||||||
llvm::function_ref<void(SmallVectorImpl<ASTNode> &, bool)> parseElements);
|
llvm::function_ref<void(bool)> parseElements);
|
||||||
|
|
||||||
/// Parse an #if ... #endif containing only attributes.
|
/// Parse an #if ... #endif containing only attributes.
|
||||||
ParserStatus parseIfConfigDeclAttributes(
|
ParserStatus parseIfConfigDeclAttributes(
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ BridgedExpr BridgedLegacyParser_parseExpr(BridgedLegacyParser p,
|
|||||||
return result.getPtrOrNull();
|
return result.getPtrOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: We need to be able to return multiple declarations here.
|
||||||
BridgedDecl BridgedLegacyParser_parseDecl(BridgedLegacyParser p,
|
BridgedDecl BridgedLegacyParser_parseDecl(BridgedLegacyParser p,
|
||||||
BridgedSourceLoc loc,
|
BridgedSourceLoc loc,
|
||||||
BridgedDeclContext DC) {
|
BridgedDeclContext DC) {
|
||||||
@@ -47,11 +48,16 @@ BridgedDecl BridgedLegacyParser_parseDecl(BridgedLegacyParser p,
|
|||||||
// FIXME: IsAtStartOfLineOrPreviousHadSemi should be passed in from ASTGen.
|
// FIXME: IsAtStartOfLineOrPreviousHadSemi should be passed in from ASTGen.
|
||||||
// IfConfigsAreDeclAttrs: true because ASTGen thinks the current location is
|
// IfConfigsAreDeclAttrs: true because ASTGen thinks the current location is
|
||||||
// a start of a decl.
|
// a start of a decl.
|
||||||
ParserResult<Decl> result = P.parseDecl(
|
Decl *resultDecl = nullptr;
|
||||||
|
P.parseDecl(
|
||||||
/*IsAtStartOfLineOrPreviousHadSemi=*/true,
|
/*IsAtStartOfLineOrPreviousHadSemi=*/true,
|
||||||
/*IfConfigsAreDeclAttrs=*/true, [&](Decl *decl) {},
|
/*IfConfigsAreDeclAttrs=*/true, [&](Decl *decl) {
|
||||||
|
// FIXME: We need to capture all of these declarations, not just
|
||||||
|
// the last one.
|
||||||
|
resultDecl = decl;
|
||||||
|
},
|
||||||
/*fromASTGen=*/true);
|
/*fromASTGen=*/true);
|
||||||
return result.getPtrOrNull();
|
return resultDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
BridgedStmt BridgedLegacyParser_parseStmt(BridgedLegacyParser p,
|
BridgedStmt BridgedLegacyParser_parseStmt(BridgedLegacyParser p,
|
||||||
|
|||||||
@@ -6247,13 +6247,17 @@ static Parser::ParseDeclOptions getParseDeclOptions(DeclContext *DC) {
|
|||||||
///
|
///
|
||||||
/// \param fromASTGen If true , this function in called from ASTGen as the
|
/// \param fromASTGen If true , this function in called from ASTGen as the
|
||||||
/// fallback, so do not attempt a callback to ASTGen.
|
/// fallback, so do not attempt a callback to ASTGen.
|
||||||
ParserResult<Decl> Parser::parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
|
ParserStatus Parser::parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
|
||||||
bool IfConfigsAreDeclAttrs,
|
bool IfConfigsAreDeclAttrs,
|
||||||
llvm::function_ref<void(Decl *)> Handler,
|
llvm::function_ref<void(Decl *)> Handler,
|
||||||
bool fromASTGen) {
|
bool fromASTGen) {
|
||||||
#if SWIFT_BUILD_SWIFT_SYNTAX
|
#if SWIFT_BUILD_SWIFT_SYNTAX
|
||||||
if (IsForASTGen && !fromASTGen)
|
if (IsForASTGen && !fromASTGen) {
|
||||||
return parseDeclFromSyntaxTree();
|
auto result = parseDeclFromSyntaxTree();
|
||||||
|
if (auto resultDecl = result.getPtrOrNull())
|
||||||
|
Handler(resultDecl);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
ParseDeclOptions Flags = getParseDeclOptions(CurDeclContext);
|
ParseDeclOptions Flags = getParseDeclOptions(CurDeclContext);
|
||||||
ParserPosition BeginParserPosition;
|
ParserPosition BeginParserPosition;
|
||||||
@@ -6263,13 +6267,17 @@ ParserResult<Decl> Parser::parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
|
|||||||
if (Tok.is(tok::pound_if) && !ifConfigContainsOnlyAttributes()) {
|
if (Tok.is(tok::pound_if) && !ifConfigContainsOnlyAttributes()) {
|
||||||
auto IfConfigResult = parseIfConfig(
|
auto IfConfigResult = parseIfConfig(
|
||||||
IfConfigContext::DeclItems,
|
IfConfigContext::DeclItems,
|
||||||
[&](SmallVectorImpl<ASTNode> &Decls, bool IsActive) {
|
[&](bool IsActive) {
|
||||||
ParserStatus Status;
|
ParserStatus Status;
|
||||||
bool PreviousHadSemi = true;
|
bool PreviousHadSemi = true;
|
||||||
while (Tok.isNot(tok::pound_else, tok::pound_endif, tok::pound_elseif,
|
while (Tok.isNot(tok::pound_else, tok::pound_endif, tok::pound_elseif,
|
||||||
tok::r_brace, tok::eof)) {
|
tok::r_brace, tok::eof)) {
|
||||||
Status |= parseDeclItem(PreviousHadSemi,
|
Status |= parseDeclItem(PreviousHadSemi,
|
||||||
[&](Decl *D) { Decls.emplace_back(D); });
|
[&](Decl *D) {
|
||||||
|
if (IsActive) {
|
||||||
|
Handler(D);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (IfConfigResult.hasCodeCompletion() && isIDEInspectionFirstPass()) {
|
if (IfConfigResult.hasCodeCompletion() && isIDEInspectionFirstPass()) {
|
||||||
@@ -6277,19 +6285,7 @@ ParserResult<Decl> Parser::parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
|
|||||||
return makeParserError();
|
return makeParserError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto ICD = IfConfigResult.getPtrOrNull()) {
|
return makeParserSuccess();
|
||||||
// The IfConfigDecl is ahead of its members in source order.
|
|
||||||
Handler(ICD);
|
|
||||||
// Copy the active members into the entries list.
|
|
||||||
for (auto activeMember : ICD->getActiveClauseElements()) {
|
|
||||||
auto *D = activeMember.get<Decl*>();
|
|
||||||
if (isa<IfConfigDecl>(D))
|
|
||||||
// Don't hoist nested '#if'.
|
|
||||||
continue;
|
|
||||||
Handler(D);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return IfConfigResult;
|
|
||||||
}
|
}
|
||||||
if (Tok.isAny(tok::pound_warning, tok::pound_error)) {
|
if (Tok.isAny(tok::pound_warning, tok::pound_error)) {
|
||||||
auto Result = parseDeclPoundDiagnostic();
|
auto Result = parseDeclPoundDiagnostic();
|
||||||
@@ -7050,15 +7046,19 @@ ParserStatus Parser::parseDeclItem(bool &PreviousHadSemi,
|
|||||||
return LineDirectiveStatus;
|
return LineDirectiveStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParserResult<Decl> Result =
|
Decl *LastResultDecl = nullptr;
|
||||||
|
ParserStatus Result =
|
||||||
parseDecl(IsAtStartOfLineOrPreviousHadSemi,
|
parseDecl(IsAtStartOfLineOrPreviousHadSemi,
|
||||||
/* IfConfigsAreDeclAttrs=*/false, handler);
|
/* IfConfigsAreDeclAttrs=*/false, [&](Decl *decl) {
|
||||||
if (Result.isParseErrorOrHasCompletion())
|
handler(decl);
|
||||||
|
LastResultDecl = decl;
|
||||||
|
});
|
||||||
|
if (Result.isErrorOrHasCompletion())
|
||||||
skipUntilDeclRBrace(tok::semi, tok::pound_endif);
|
skipUntilDeclRBrace(tok::semi, tok::pound_endif);
|
||||||
SourceLoc SemiLoc;
|
SourceLoc SemiLoc;
|
||||||
PreviousHadSemi = consumeIf(tok::semi, SemiLoc);
|
PreviousHadSemi = consumeIf(tok::semi, SemiLoc);
|
||||||
if (PreviousHadSemi && Result.isNonNull())
|
if (PreviousHadSemi && LastResultDecl)
|
||||||
Result.get()->TrailingSemiLoc = SemiLoc;
|
LastResultDecl->TrailingSemiLoc = SemiLoc;
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1478,10 +1478,11 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
|
|||||||
.fixItInsert(getEndOfPreviousLoc(), "\n");
|
.fixItInsert(getEndOfPreviousLoc(), "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::TinyPtrVector<ASTNode> activeElements;
|
||||||
llvm::SmallPtrSet<Expr *, 4> exprsWithBindOptional;
|
llvm::SmallPtrSet<Expr *, 4> exprsWithBindOptional;
|
||||||
auto ICD = parseIfConfig(
|
auto ICD = parseIfConfig(
|
||||||
IfConfigContext::PostfixExpr,
|
IfConfigContext::PostfixExpr,
|
||||||
[&](SmallVectorImpl<ASTNode> &elements, bool isActive) {
|
[&](bool isActive) {
|
||||||
// Although we know the '#if' body starts with period,
|
// Although we know the '#if' body starts with period,
|
||||||
// '#elseif'/'#else' bodies might start with invalid tokens.
|
// '#elseif'/'#else' bodies might start with invalid tokens.
|
||||||
if (isAtStartOfPostfixExprSuffix() || Tok.is(tok::pound_if)) {
|
if (isAtStartOfPostfixExprSuffix() || Tok.is(tok::pound_if)) {
|
||||||
@@ -1491,13 +1492,14 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
|
|||||||
exprHasBindOptional);
|
exprHasBindOptional);
|
||||||
if (exprHasBindOptional)
|
if (exprHasBindOptional)
|
||||||
exprsWithBindOptional.insert(expr.get());
|
exprsWithBindOptional.insert(expr.get());
|
||||||
elements.push_back(expr.get());
|
|
||||||
|
if (isActive)
|
||||||
|
activeElements.push_back(expr.get());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (ICD.isNull())
|
if (ICD.isErrorOrHasCompletion())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
auto activeElements = ICD.get()->getActiveClauseElements();
|
|
||||||
if (activeElements.empty())
|
if (activeElements.empty())
|
||||||
// There's no active clause, or it was empty. Keep the current result.
|
// There's no active clause, or it was empty. Keep the current result.
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -972,31 +972,22 @@ Result Parser::parseIfConfigRaw(
|
|||||||
return finish(EndLoc, HadMissingEnd);
|
return finish(EndLoc, HadMissingEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse and populate a #if ... #endif directive.
|
// Parse and populate a #if ... #endif directive.
|
||||||
/// Delegate callback function to parse elements in the blocks.
|
/// Delegate callback function to parse elements in the blocks.
|
||||||
ParserResult<IfConfigDecl> Parser::parseIfConfig(
|
ParserStatus Parser::parseIfConfig(
|
||||||
IfConfigContext ifConfigContext,
|
IfConfigContext ifConfigContext,
|
||||||
llvm::function_ref<void(SmallVectorImpl<ASTNode> &, bool)> parseElements) {
|
llvm::function_ref<void(bool)> parseElements) {
|
||||||
SmallVector<IfConfigClause, 4> clauses;
|
ParserStatus status = makeParserSuccess();
|
||||||
return parseIfConfigRaw<ParserResult<IfConfigDecl>>(
|
return parseIfConfigRaw<ParserStatus>(
|
||||||
ifConfigContext,
|
ifConfigContext,
|
||||||
[&](SourceLoc clauseLoc, Expr *condition, bool isActive,
|
[&](SourceLoc clauseLoc, Expr *condition, bool isActive,
|
||||||
IfConfigElementsRole role) {
|
IfConfigElementsRole role) {
|
||||||
SmallVector<ASTNode, 16> elements;
|
|
||||||
if (role != IfConfigElementsRole::Skipped)
|
if (role != IfConfigElementsRole::Skipped)
|
||||||
parseElements(elements, isActive);
|
parseElements(isActive);
|
||||||
if (role == IfConfigElementsRole::SyntaxOnly)
|
|
||||||
elements.clear();
|
|
||||||
|
|
||||||
clauses.emplace_back(
|
|
||||||
clauseLoc, condition, Context.AllocateCopy(elements), isActive);
|
|
||||||
},
|
},
|
||||||
[&](SourceLoc endLoc, bool hadMissingEnd) {
|
[&](SourceLoc endLoc, bool hadMissingEnd) {
|
||||||
auto *ICD = new (Context) IfConfigDecl(CurDeclContext,
|
return status;
|
||||||
Context.AllocateCopy(clauses),
|
});
|
||||||
endLoc, hadMissingEnd);
|
|
||||||
return makeParserResult(ICD);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ParserStatus Parser::parseIfConfigDeclAttributes(
|
ParserStatus Parser::parseIfConfigDeclAttributes(
|
||||||
|
|||||||
@@ -369,35 +369,31 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
|
|||||||
// Parse the decl, stmt, or expression.
|
// Parse the decl, stmt, or expression.
|
||||||
PreviousHadSemi = false;
|
PreviousHadSemi = false;
|
||||||
if (Tok.is(tok::pound_if) && !isStartOfSwiftDecl()) {
|
if (Tok.is(tok::pound_if) && !isStartOfSwiftDecl()) {
|
||||||
|
SmallVector<ASTNode, 16> activeElements;
|
||||||
auto IfConfigResult = parseIfConfig(
|
auto IfConfigResult = parseIfConfig(
|
||||||
IfConfigContext::BraceItems,
|
IfConfigContext::BraceItems,
|
||||||
[&](SmallVectorImpl<ASTNode> &Elements, bool IsActive) {
|
[&](bool IsActive) {
|
||||||
parseBraceItems(Elements, Kind,
|
SmallVector<ASTNode, 16> elements;
|
||||||
|
parseBraceItems(elements, Kind,
|
||||||
IsActive
|
IsActive
|
||||||
? BraceItemListKind::ActiveConditionalBlock
|
? BraceItemListKind::ActiveConditionalBlock
|
||||||
: BraceItemListKind::InactiveConditionalBlock,
|
: BraceItemListKind::InactiveConditionalBlock,
|
||||||
IsFollowingGuard);
|
IsFollowingGuard);
|
||||||
|
|
||||||
|
if (IsActive)
|
||||||
|
activeElements = std::move(elements);
|
||||||
});
|
});
|
||||||
if (IfConfigResult.hasCodeCompletion() && isIDEInspectionFirstPass()) {
|
if (IfConfigResult.hasCodeCompletion() && isIDEInspectionFirstPass()) {
|
||||||
consumeDecl(BeginParserPosition, IsTopLevel);
|
consumeDecl(BeginParserPosition, IsTopLevel);
|
||||||
return IfConfigResult;
|
return IfConfigResult;
|
||||||
}
|
}
|
||||||
BraceItemsStatus |= IfConfigResult;
|
BraceItemsStatus |= IfConfigResult;
|
||||||
if (auto ICD = IfConfigResult.getPtrOrNull()) {
|
if (IfConfigResult.isError()) {
|
||||||
Result = ICD;
|
|
||||||
// Add the #if block itself
|
|
||||||
Entries.push_back(ICD);
|
|
||||||
|
|
||||||
for (auto &Entry : ICD->getActiveClauseElements()) {
|
|
||||||
if (Entry.is<Decl *>() && isa<IfConfigDecl>(Entry.get<Decl *>()))
|
|
||||||
// Don't hoist nested '#if'.
|
|
||||||
continue;
|
|
||||||
Entries.push_back(Entry);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
NeedParseErrorRecovery = true;
|
NeedParseErrorRecovery = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entries.append(activeElements);
|
||||||
} else if (Tok.is(tok::pound_line)) {
|
} else if (Tok.is(tok::pound_line)) {
|
||||||
ParserStatus Status = parseLineDirective(true);
|
ParserStatus Status = parseLineDirective(true);
|
||||||
BraceItemsStatus |= Status;
|
BraceItemsStatus |= Status;
|
||||||
@@ -408,7 +404,7 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
|
|||||||
NeedParseErrorRecovery = Status.isErrorOrHasCompletion();
|
NeedParseErrorRecovery = Status.isErrorOrHasCompletion();
|
||||||
} else if (isStartOfSwiftDecl()) {
|
} else if (isStartOfSwiftDecl()) {
|
||||||
SmallVector<Decl*, 8> TmpDecls;
|
SmallVector<Decl*, 8> TmpDecls;
|
||||||
ParserResult<Decl> DeclResult =
|
ParserStatus DeclResult =
|
||||||
parseDecl(IsAtStartOfLineOrPreviousHadSemi,
|
parseDecl(IsAtStartOfLineOrPreviousHadSemi,
|
||||||
/*IfConfigsAreDeclAttrs=*/true, [&](Decl *D) {
|
/*IfConfigsAreDeclAttrs=*/true, [&](Decl *D) {
|
||||||
TmpDecls.push_back(D);
|
TmpDecls.push_back(D);
|
||||||
@@ -423,7 +419,7 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
|
|||||||
FD->setHasTopLevelLocalContextCaptures();
|
FD->setHasTopLevelLocalContextCaptures();
|
||||||
});
|
});
|
||||||
BraceItemsStatus |= DeclResult;
|
BraceItemsStatus |= DeclResult;
|
||||||
if (DeclResult.isParseErrorOrHasCompletion()) {
|
if (DeclResult.isErrorOrHasCompletion()) {
|
||||||
NeedParseErrorRecovery = true;
|
NeedParseErrorRecovery = true;
|
||||||
if (DeclResult.hasCodeCompletion() && IsTopLevel &&
|
if (DeclResult.hasCodeCompletion() && IsTopLevel &&
|
||||||
isIDEInspectionFirstPass()) {
|
isIDEInspectionFirstPass()) {
|
||||||
@@ -431,8 +427,14 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
|
|||||||
return DeclResult;
|
return DeclResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Result = DeclResult.getPtrOrNull();
|
|
||||||
Entries.append(TmpDecls.begin(), TmpDecls.end());
|
Entries.append(TmpDecls.begin(), TmpDecls.end());
|
||||||
|
|
||||||
|
// HACK: If any declarations were parsed, make the last one the "result".
|
||||||
|
// We should know whether this was in an #if or not.
|
||||||
|
if (!TmpDecls.empty()) {
|
||||||
|
Result = TmpDecls.back();
|
||||||
|
}
|
||||||
|
|
||||||
} else if (IsTopLevel) {
|
} else if (IsTopLevel) {
|
||||||
// If this is a statement or expression at the top level of the module,
|
// If this is a statement or expression at the top level of the module,
|
||||||
// Parse it as a child of a TopLevelCodeDecl.
|
// Parse it as a child of a TopLevelCodeDecl.
|
||||||
@@ -2661,25 +2663,15 @@ Parser::parseStmtCases(SmallVectorImpl<ASTNode> &cases, bool IsActive) {
|
|||||||
// clauses.
|
// clauses.
|
||||||
auto IfConfigResult =
|
auto IfConfigResult =
|
||||||
parseIfConfig(IfConfigContext::SwitchStmt,
|
parseIfConfig(IfConfigContext::SwitchStmt,
|
||||||
[&](SmallVectorImpl<ASTNode> &Elements, bool IsActive) {
|
[&](bool IsActive) {
|
||||||
parseStmtCases(Elements, IsActive);
|
SmallVector<ASTNode, 16> elements;
|
||||||
|
parseStmtCases(elements, IsActive);
|
||||||
|
|
||||||
|
if (IsActive) {
|
||||||
|
cases.append(elements);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
Status |= IfConfigResult;
|
Status |= IfConfigResult;
|
||||||
if (auto ICD = IfConfigResult.getPtrOrNull()) {
|
|
||||||
cases.emplace_back(ICD);
|
|
||||||
|
|
||||||
for (auto &Entry : ICD->getActiveClauseElements()) {
|
|
||||||
if (Entry.is<Decl*>() &&
|
|
||||||
(isa<IfConfigDecl>(Entry.get<Decl*>())))
|
|
||||||
// Don't hoist nested '#if'.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
assert((Entry.is<Stmt*>() && isa<CaseStmt>(Entry.get<Stmt*>())) ||
|
|
||||||
(Entry.is<Decl*>() &&
|
|
||||||
isa<PoundDiagnosticDecl>(Entry.get<Decl*>())));
|
|
||||||
cases.push_back(Entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (Tok.is(tok::pound_warning) || Tok.is(tok::pound_error)) {
|
} else if (Tok.is(tok::pound_warning) || Tok.is(tok::pound_error)) {
|
||||||
auto PoundDiagnosticResult = parseDeclPoundDiagnostic();
|
auto PoundDiagnosticResult = parseDeclPoundDiagnostic();
|
||||||
Status |= PoundDiagnosticResult;
|
Status |= PoundDiagnosticResult;
|
||||||
|
|||||||
@@ -822,9 +822,11 @@ bool Parser::parseEndIfDirective(SourceLoc &Loc) {
|
|||||||
Loc = PreviousLoc;
|
Loc = PreviousLoc;
|
||||||
skipUntilConditionalBlockClose();
|
skipUntilConditionalBlockClose();
|
||||||
return true;
|
return true;
|
||||||
} else if (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof))
|
} else if (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) {
|
||||||
diagnose(Tok.getLoc(),
|
diagnose(Tok.getLoc(),
|
||||||
diag::extra_tokens_conditional_compilation_directive);
|
diag::extra_tokens_conditional_compilation_directive);
|
||||||
|
skipUntilTokenOrEndOfLine(tok::NUM_TOKENS);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ func bar() {
|
|||||||
// CHECK-LABEL: (enum_decl{{.*}}trailing_semi "TrailingSemi"
|
// CHECK-LABEL: (enum_decl{{.*}}trailing_semi "TrailingSemi"
|
||||||
enum TrailingSemi {
|
enum TrailingSemi {
|
||||||
|
|
||||||
// CHECK-LABEL: (enum_case_decl{{.*}}trailing_semi
|
// CHECK-LABEL: (enum_case_decl
|
||||||
// CHECK-NOT: (enum_element_decl{{.*}}trailing_semi
|
// CHECK-NOT: (enum_element_decl{{.*}}trailing_semi
|
||||||
// CHECK: (enum_element_decl{{.*}}"A")
|
// CHECK: (enum_element_decl{{.*}}"A")
|
||||||
// CHECK: (enum_element_decl{{.*}}"B")
|
// CHECK: (enum_element_decl{{.*}}"B")
|
||||||
@@ -41,7 +41,7 @@ enum TrailingSemi {
|
|||||||
// CHECK-NOT: (func_decl{{.*}}trailing_semi <anonymous @ 0x{{[0-9a-f]+}}> get for="subscript(_:)"
|
// CHECK-NOT: (func_decl{{.*}}trailing_semi <anonymous @ 0x{{[0-9a-f]+}}> get for="subscript(_:)"
|
||||||
// CHECK: (accessor_decl{{.*}} <anonymous @ 0x{{[0-9a-f]+}}> get for="subscript(_:)"
|
// CHECK: (accessor_decl{{.*}} <anonymous @ 0x{{[0-9a-f]+}}> get for="subscript(_:)"
|
||||||
subscript(x: Int) -> Int {
|
subscript(x: Int) -> Int {
|
||||||
// CHECK-LABEL: (pattern_binding_decl{{.*}}trailing_semi
|
// CHECK-LABEL: (pattern_binding_decl{{.*}}
|
||||||
// CHECK-NOT: (var_decl{{.*}}trailing_semi "y"
|
// CHECK-NOT: (var_decl{{.*}}trailing_semi "y"
|
||||||
// CHECK: (var_decl{{.*}}"y"
|
// CHECK: (var_decl{{.*}}"y"
|
||||||
var y = 1;
|
var y = 1;
|
||||||
|
|||||||
@@ -3,15 +3,13 @@
|
|||||||
|
|
||||||
// More blah blah.
|
// More blah blah.
|
||||||
|
|
||||||
#if FOO
|
|
||||||
import Swift
|
import Swift
|
||||||
|
|
||||||
|
#if FOO
|
||||||
class FooEnabled {}
|
class FooEnabled {}
|
||||||
|
|
||||||
typealias MyN = Int
|
typealias MyN = Int
|
||||||
#else
|
#else
|
||||||
import Swift
|
|
||||||
|
|
||||||
class FooDisabled {}
|
class FooDisabled {}
|
||||||
|
|
||||||
typealias MyN = Int
|
typealias MyN = Int
|
||||||
|
|||||||
@@ -710,12 +710,12 @@ func returnBranches6PoundIf() -> Int {
|
|||||||
|
|
||||||
func returnBranches6PoundIf2() -> Int {
|
func returnBranches6PoundIf2() -> Int {
|
||||||
// We don't allow multiple expressions.
|
// We don't allow multiple expressions.
|
||||||
let i = if .random() {
|
let i = if .random() { // expected-error{{expected expression in branch of 'if' expression}}
|
||||||
#if false
|
#if false
|
||||||
print("hello")
|
print("hello")
|
||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
} else { // expected-error {{non-expression branch of 'if' expression may only end with a 'throw'}}
|
} else {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
@@ -849,11 +849,11 @@ func testPoundIfBranch2() -> Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testPoundIfBranch3() -> Int {
|
func testPoundIfBranch3() -> Int {
|
||||||
let x = if .random() {
|
let x = if .random() { // expected-error{{expected expression in branch of 'if' expression}}
|
||||||
#if false
|
#if false
|
||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
} else { // expected-error {{non-expression branch of 'if' expression may only end with a 'throw'}}
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
@@ -872,25 +872,25 @@ func testPoundIfBranch4() -> Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testPoundIfBranch5() -> Int {
|
func testPoundIfBranch5() -> Int {
|
||||||
// Not allowed (matches the behavior of implict expression returns)
|
// Inactive #if regions don't count
|
||||||
if .random() {
|
if .random() {
|
||||||
#if false
|
#if false
|
||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
0 // expected-warning {{integer literal is unused}}
|
0
|
||||||
} else {
|
} else {
|
||||||
1 // expected-warning {{integer literal is unused}}
|
1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPoundIfBranch6() -> Int {
|
func testPoundIfBranch6() -> Int {
|
||||||
// Not allowed (matches the behavior of implict expression returns)
|
// Inactive #if regions don't count
|
||||||
let x = if .random() {
|
let x = if .random() {
|
||||||
#if false
|
#if false
|
||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
0 // expected-warning {{integer literal is unused}}
|
0
|
||||||
} else { // expected-error {{non-expression branch of 'if' expression may only end with a 'throw'}}
|
} else {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
|
|||||||
@@ -855,14 +855,14 @@ func returnBranches6PoundIf() -> Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func returnBranches6PoundIf2() -> Int {
|
func returnBranches6PoundIf2() -> Int {
|
||||||
// We don't allow multiple expressions.
|
// We don't allow multiple expressions, but inactive #ifs don't count.
|
||||||
let i = switch Bool.random() {
|
let i = switch Bool.random() {
|
||||||
case true:
|
case true:
|
||||||
#if false
|
#if false
|
||||||
print("hello")
|
print("hello")
|
||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
// expected-error@-1 {{non-expression branch of 'switch' expression may only end with a 'throw' or 'fallthrough'}}
|
// expected-error@-1 {{expected expression in branch of 'switch' expression}}
|
||||||
case false:
|
case false:
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
@@ -1071,7 +1071,7 @@ func testPoundIfBranch3() -> Int {
|
|||||||
#if false
|
#if false
|
||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
// expected-error@-1 {{non-expression branch of 'switch' expression may only end with a 'throw' or 'fallthrough'}}
|
// expected-error@-1 {{expected expression in branch of 'switch' expression}}
|
||||||
case false:
|
case false:
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
@@ -1092,27 +1092,26 @@ func testPoundIfBranch4() -> Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testPoundIfBranch5() -> Int {
|
func testPoundIfBranch5() -> Int {
|
||||||
// Not allowed (matches the behavior of implict expression returns)
|
// Okay, inactive #ifs don't count.
|
||||||
switch Bool.random() {
|
switch Bool.random() {
|
||||||
case true:
|
case true:
|
||||||
#if false
|
#if false
|
||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
0 // expected-warning {{integer literal is unused}}
|
0
|
||||||
case false:
|
case false:
|
||||||
1 // expected-warning {{integer literal is unused}}
|
1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPoundIfBranch6() -> Int {
|
func testPoundIfBranch6() -> Int {
|
||||||
// Not allowed (matches the behavior of implict expression returns)
|
// Okay, inactive #ifs don't count.
|
||||||
let x = switch Bool.random() {
|
let x = switch Bool.random() {
|
||||||
case true:
|
case true:
|
||||||
#if false
|
#if false
|
||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
0 // expected-warning {{integer literal is unused}}
|
0
|
||||||
// expected-error@-1 {{non-expression branch of 'switch' expression may only end with a 'throw' or 'fallthrough'}}
|
|
||||||
case false:
|
case false:
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user