mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #37472 from bnbarham/cleanup-allow-errors
[Serialization] Add whether allowing errors to the pretty stack output
This commit is contained in:
@@ -793,8 +793,9 @@ ERROR(serialization_fatal,Fatal,
|
||||
SWIFT_BUG_REPORT_MESSAGE,
|
||||
(StringRef))
|
||||
NOTE(serialization_misc_version,none,
|
||||
"module '%0' full misc version is '%1'",
|
||||
(StringRef, StringRef))
|
||||
"module '%0' full misc version is '%1'"
|
||||
"%select{ (built while allowing compiler errors)|}2",
|
||||
(StringRef, StringRef, bool))
|
||||
NOTE(serialization_compatibility_version_mismatch,none,
|
||||
"compiling as Swift %0, with '%1' built as Swift %2 "
|
||||
"(this is supported but may expose additional compiler issues)",
|
||||
|
||||
@@ -2046,6 +2046,11 @@ int swift::performFrontend(ArrayRef<const char *> Args,
|
||||
return finishDiagProcessing(1, /*verifierEnabled*/ false);
|
||||
}
|
||||
|
||||
Optional<llvm::PrettyStackTraceString> allowErrorsStackTrace;
|
||||
if (Invocation.getFrontendOptions().AllowModuleWithCompilerErrors)
|
||||
allowErrorsStackTrace.emplace("While allowing modules with compiler errors "
|
||||
"enabled");
|
||||
|
||||
// Make an array of PrettyStackTrace objects to dump the configuration files
|
||||
// we used to parse the arguments. These are RAII objects, so they and the
|
||||
// buffers they refer to must be kept alive in order to be useful. (That is,
|
||||
|
||||
@@ -169,8 +169,9 @@ static void skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) {
|
||||
void ModuleFile::fatal(llvm::Error error) {
|
||||
if (FileContext) {
|
||||
getContext().Diags.diagnose(SourceLoc(), diag::serialization_fatal, Core->Name);
|
||||
getContext().Diags.diagnose(SourceLoc(), diag::serialization_misc_version,
|
||||
Core->Name, Core->MiscVersion);
|
||||
getContext().Diags.diagnose(
|
||||
SourceLoc(), diag::serialization_misc_version, Core->Name,
|
||||
Core->MiscVersion, allowCompilerErrors());
|
||||
|
||||
if (!Core->CompatibilityVersion.empty()) {
|
||||
if (getContext().LangOpts.EffectiveLanguageVersion
|
||||
@@ -2512,7 +2513,7 @@ public:
|
||||
name = VD->getName();
|
||||
}
|
||||
|
||||
auto diagId = ctx.LangOpts.AllowModuleWithCompilerErrors
|
||||
auto diagId = MF.allowCompilerErrors()
|
||||
? diag::serialization_allowing_invalid_decl
|
||||
: diag::serialization_invalid_decl;
|
||||
ctx.Diags.diagnose(SourceLoc(), diagId, name,
|
||||
@@ -3092,7 +3093,7 @@ public:
|
||||
declOrOffset = param;
|
||||
|
||||
auto paramTy = MF.getType(interfaceTypeID);
|
||||
if (paramTy->hasError() && !MF.isAllowModuleWithCompilerErrorsEnabled()) {
|
||||
if (paramTy->hasError() && !MF.allowCompilerErrors()) {
|
||||
// FIXME: This should never happen, because we don't serialize
|
||||
// error types.
|
||||
DC->printContext(llvm::errs());
|
||||
@@ -5872,7 +5873,7 @@ public:
|
||||
return origTyOrError.takeError();
|
||||
|
||||
auto origTy = *origTyOrError;
|
||||
auto diagId = ctx.LangOpts.AllowModuleWithCompilerErrors
|
||||
auto diagId = MF.allowCompilerErrors()
|
||||
? diag::serialization_allowing_error_type
|
||||
: diag::serialization_error_type;
|
||||
// Generally not a super useful diagnostic, so only output once if there
|
||||
@@ -5910,8 +5911,7 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
PrettyStackTraceType trace(getContext(), "deserializing", typeOrOffset.get());
|
||||
if (typeOrOffset.get()->hasError() &&
|
||||
!isAllowModuleWithCompilerErrorsEnabled()) {
|
||||
if (typeOrOffset.get()->hasError() && !allowCompilerErrors()) {
|
||||
typeOrOffset.get()->dump(llvm::errs());
|
||||
llvm_unreachable("deserialization produced an invalid type "
|
||||
"(rdar://problem/30382791)");
|
||||
@@ -6372,7 +6372,7 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
|
||||
auto isConformanceReq = [](const Requirement &req) {
|
||||
return req.getKind() == RequirementKind::Conformance;
|
||||
};
|
||||
if (!isAllowModuleWithCompilerErrorsEnabled() &&
|
||||
if (!allowCompilerErrors() &&
|
||||
conformanceCount != llvm::count_if(proto->getRequirementSignature(),
|
||||
isConformanceReq)) {
|
||||
fatal(llvm::make_error<llvm::StringError>(
|
||||
@@ -6715,3 +6715,9 @@ Optional<ForeignAsyncConvention> ModuleFile::maybeReadForeignAsyncConvention() {
|
||||
completionHandlerErrorFlagParamIndex,
|
||||
errorFlagPolarity);
|
||||
}
|
||||
|
||||
void serialization::PrettyStackTraceModuleFile::outputModuleBuildInfo(
|
||||
raw_ostream &os) const {
|
||||
if (MF.compiledAllowingCompilerErrors())
|
||||
os << " (built while allowing compiler errors)";
|
||||
}
|
||||
|
||||
@@ -470,8 +470,12 @@ public:
|
||||
: PrettyStackTraceModuleFile("While reading from", module) {}
|
||||
|
||||
void print(raw_ostream &os) const override {
|
||||
os << Action << " \'" << getNameOfModule(&MF) << "'\n";
|
||||
os << Action << " \'" << getNameOfModule(&MF) << "'";
|
||||
outputModuleBuildInfo(os);
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void outputModuleBuildInfo(raw_ostream &os) const;
|
||||
};
|
||||
|
||||
class PrettyStackTraceModuleFileCore : public llvm::PrettyStackTraceEntry {
|
||||
|
||||
@@ -117,6 +117,10 @@ ModuleFile::ModuleFile(std::shared_ptr<const ModuleFileSharedCore> core)
|
||||
allocateBuffer(Identifiers, core->Identifiers);
|
||||
}
|
||||
|
||||
bool ModuleFile::allowCompilerErrors() const {
|
||||
return getContext().LangOpts.AllowModuleWithCompilerErrors;
|
||||
}
|
||||
|
||||
Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc,
|
||||
bool recoverFromIncompatibility) {
|
||||
PrettyStackTraceModuleFile stackEntry(*this);
|
||||
|
||||
@@ -478,10 +478,14 @@ public:
|
||||
|
||||
/// Whether this module is compiled while allowing errors
|
||||
/// ('-experimental-allow-module-with-compiler-errors').
|
||||
bool isAllowModuleWithCompilerErrorsEnabled() const {
|
||||
bool compiledAllowingCompilerErrors() const {
|
||||
return Core->Bits.IsAllowModuleWithCompilerErrorsEnabled;
|
||||
}
|
||||
|
||||
/// Whether currently allowing modules with compiler errors (ie.
|
||||
/// '-experimental-allow-module-with-compiler-errors' is currently enabled).
|
||||
bool allowCompilerErrors() const;
|
||||
|
||||
/// \c true if this module has incremental dependency information.
|
||||
bool hasIncrementalInfo() const { return Core->hasIncrementalInfo(); }
|
||||
|
||||
|
||||
@@ -76,10 +76,7 @@ using namespace llvm::support;
|
||||
using swift::version::Version;
|
||||
using llvm::BCBlockRAII;
|
||||
|
||||
|
||||
ASTContext &SerializerBase::getASTContext() {
|
||||
return M->getASTContext();
|
||||
}
|
||||
ASTContext &SerializerBase::getASTContext() const { return M->getASTContext(); }
|
||||
|
||||
/// Used for static_assert.
|
||||
static constexpr bool declIDFitsIn32Bits() {
|
||||
@@ -644,8 +641,9 @@ serialization::TypeID Serializer::addTypeRef(Type ty) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
PrettyStackTraceType trace(M->getASTContext(), "serializing", typeToSerialize);
|
||||
assert(M->getASTContext().LangOpts.AllowModuleWithCompilerErrors ||
|
||||
!typeToSerialize || !typeToSerialize->hasError() && "serializing type with an error");
|
||||
assert((allowCompilerErrors() || !typeToSerialize ||
|
||||
!typeToSerialize->hasError()) &&
|
||||
"serializing type with an error");
|
||||
#endif
|
||||
|
||||
return TypesToSerialize.addRef(typeToSerialize);
|
||||
@@ -1015,7 +1013,7 @@ void Serializer::writeHeader(const SerializationOptions &options) {
|
||||
Strategy.emit(ScratchRecord, unsigned(M->getResilienceStrategy()));
|
||||
}
|
||||
|
||||
if (getASTContext().LangOpts.AllowModuleWithCompilerErrors) {
|
||||
if (allowCompilerErrors()) {
|
||||
options_block::IsAllowModuleWithCompilerErrorsEnabledLayout
|
||||
AllowErrors(Out);
|
||||
AllowErrors.emit(ScratchRecord);
|
||||
@@ -1439,8 +1437,7 @@ void Serializer::writeASTBlockEntity(
|
||||
using namespace decls_block;
|
||||
|
||||
// The conformance must be complete, or we can't serialize it.
|
||||
assert(conformance->isComplete() ||
|
||||
getASTContext().LangOpts.AllowModuleWithCompilerErrors);
|
||||
assert(conformance->isComplete() || allowCompilerErrors());
|
||||
assert(NormalConformancesToSerialize.hasRef(conformance));
|
||||
|
||||
auto protocol = conformance->getProtocol();
|
||||
@@ -2861,7 +2858,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
|
||||
// Retrieve the type of the pattern.
|
||||
auto getPatternType = [&] {
|
||||
if (!pattern->hasType()) {
|
||||
if (S.getASTContext().LangOpts.AllowModuleWithCompilerErrors)
|
||||
if (S.allowCompilerErrors())
|
||||
return ErrorType::get(S.getASTContext());
|
||||
llvm_unreachable("all nodes should have types");
|
||||
}
|
||||
@@ -3625,8 +3622,7 @@ public:
|
||||
getRawStableDefaultArgumentKind(argKind),
|
||||
defaultArgumentText);
|
||||
|
||||
if (interfaceType->hasError() &&
|
||||
!S.getASTContext().LangOpts.AllowModuleWithCompilerErrors) {
|
||||
if (interfaceType->hasError() && !S.allowCompilerErrors()) {
|
||||
param->getDeclContext()->printContext(llvm::errs());
|
||||
interfaceType->dump(llvm::errs());
|
||||
llvm_unreachable("error in interface type of parameter");
|
||||
@@ -3993,8 +3989,8 @@ void Serializer::writeASTBlockEntity(const Decl *D) {
|
||||
}
|
||||
};
|
||||
|
||||
assert(getASTContext().LangOpts.AllowModuleWithCompilerErrors ||
|
||||
!D->isInvalid() && "cannot create a module with an invalid decl");
|
||||
assert((allowCompilerErrors() || !D->isInvalid()) &&
|
||||
"cannot create a module with an invalid decl");
|
||||
if (isDeclXRef(D)) {
|
||||
writeCrossReference(D);
|
||||
return;
|
||||
@@ -4156,7 +4152,7 @@ public:
|
||||
void visitType(const TypeBase *) = delete;
|
||||
|
||||
void visitErrorType(const ErrorType *ty) {
|
||||
if (S.getASTContext().LangOpts.AllowModuleWithCompilerErrors) {
|
||||
if (S.allowCompilerErrors()) {
|
||||
using namespace decls_block;
|
||||
unsigned abbrCode = S.DeclTypeAbbrCodes[ErrorTypeLayout::Code];
|
||||
ErrorTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode,
|
||||
@@ -5252,8 +5248,7 @@ static void collectInterestingNestedDeclarations(
|
||||
if (!nominalParent) {
|
||||
const DeclContext *DC = member->getDeclContext();
|
||||
nominalParent = DC->getSelfNominalTypeDecl();
|
||||
assert(nominalParent ||
|
||||
nestedType->getASTContext().LangOpts.AllowModuleWithCompilerErrors &&
|
||||
assert((nominalParent || S.allowCompilerErrors()) &&
|
||||
"parent context is not a type or extension");
|
||||
}
|
||||
nestedTypeDecls[nestedType->getName()].push_back({
|
||||
@@ -5539,6 +5534,10 @@ void Serializer::writeToStream(
|
||||
S.writeToStream(os);
|
||||
}
|
||||
|
||||
bool Serializer::allowCompilerErrors() const {
|
||||
return getASTContext().LangOpts.AllowModuleWithCompilerErrors;
|
||||
}
|
||||
|
||||
void swift::serializeToBuffers(
|
||||
ModuleOrSourceFile DC, const SerializationOptions &options,
|
||||
std::unique_ptr<llvm::MemoryBuffer> *moduleBuffer,
|
||||
|
||||
@@ -72,7 +72,7 @@ protected:
|
||||
public:
|
||||
SerializerBase(ArrayRef<unsigned char> signature, ModuleOrSourceFile DC);
|
||||
|
||||
ASTContext &getASTContext();
|
||||
ASTContext &getASTContext() const;
|
||||
};
|
||||
|
||||
class Serializer : public SerializerBase {
|
||||
@@ -538,6 +538,8 @@ public:
|
||||
/// Writes a set of generic requirements.
|
||||
void writeGenericRequirements(ArrayRef<Requirement> requirements,
|
||||
const std::array<unsigned, 256> &abbrCodes);
|
||||
|
||||
bool allowCompilerErrors() const;
|
||||
};
|
||||
|
||||
/// Serialize module documentation to the given stream.
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
// CHECK-NEXT: test{{[\\/]}}Frontend{{[\\/]}}crash.swift{{$}}
|
||||
// CHECK-NEXT: ---
|
||||
|
||||
// Check that a message when allowing errors is output
|
||||
// RUN: not --crash %target-swift-frontend -typecheck -debug-crash-after-parse -experimental-allow-module-with-compiler-errors %s 2>&1 | %FileCheck -check-prefix CHECK-ALLOW %s
|
||||
// CHECK-ALLOW-LABEL: Stack dump
|
||||
// CHECK-ALLOW: While allowing modules with compiler errors enabled
|
||||
|
||||
func anchor() {}
|
||||
anchor()
|
||||
|
||||
|
||||
16
test/Serialization/AllowErrors/crash-adds-message.swift
Normal file
16
test/Serialization/AllowErrors/crash-adds-message.swift
Normal file
@@ -0,0 +1,16 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: touch %t/empty.swift
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/errors.partial.swiftmodule -module-name errors -experimental-allow-module-with-compiler-errors %s
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/errorsempty.partial.swiftmodule -module-name errors %t/empty.swift
|
||||
|
||||
// Note - running the merge without allow errors to force a crash, we want
|
||||
// to check if there's a message about allowing compiler errors for the
|
||||
// deserialized module
|
||||
// RUN: not --crash %target-swift-frontend -module-name errors -emit-module -o %t/errors.swiftmodule %t/errors.partial.swiftmodule %t/errorsempty.partial.swiftmodule 2>&1 | %FileCheck %s
|
||||
|
||||
// REQUIRES: asserts
|
||||
|
||||
typealias AnAlias = SomeStruct
|
||||
|
||||
// CHECK: While reading from 'errors' (built while allowing compiler errors)
|
||||
19
test/Serialization/AllowErrors/invalid-alias.swift
Normal file
19
test/Serialization/AllowErrors/invalid-alias.swift
Normal file
@@ -0,0 +1,19 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
|
||||
// RUN: touch %t/empty.swift
|
||||
// RUN: %{python} %utils/split_file.py -o %t %s
|
||||
|
||||
// RUN: %target-swift-frontend -verify -emit-module -o %t/errors.partial.swiftmodule -module-name errors -experimental-allow-module-with-compiler-errors %t/errors.swift
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/errorsempty.partial.swiftmodule -module-name errors %t/empty.swift
|
||||
|
||||
// RUN: %target-swift-frontend -module-name errors -emit-module -o %t/errors.swiftmodule -experimental-allow-module-with-compiler-errors %t/errors.partial.swiftmodule %t/errorsempty.partial.swiftmodule
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/mods/uses.swiftmodule -experimental-allow-module-with-compiler-errors -I %t/mods %t/uses.swift 2>&1 | %FileCheck -check-prefix=CHECK-USES %s
|
||||
|
||||
// BEGIN errors.swift
|
||||
typealias AnAlias = undefined // expected-error {{cannot find type 'undefined'}}
|
||||
|
||||
// BEGIN uses.swift
|
||||
import errors
|
||||
func test(a: AnAlias) {}
|
||||
// CHECK-USES-NOT: cannot find type 'AnAlias' in scope
|
||||
@@ -76,7 +76,7 @@ func testInvalidTopLevelCompletion() {
|
||||
// RUN: %target-swift-frontend -merge-modules -emit-module -experimental-allow-module-with-compiler-errors %t/errors.a.swiftmodule %t/errors.b.swiftmodule %t/errors.c.swiftmodule -module-name errors -o %t/errors.swiftmodule
|
||||
|
||||
// Read the module back in to make sure it can be deserialized
|
||||
// RUN: %target-swift-ide-test -print-module -source-filename dummy -module-to-print errors -I %t | %FileCheck %s
|
||||
// RUN: %target-swift-ide-test -print-module -source-filename dummy -module-to-print errors -I %t -allow-compiler-errors | %FileCheck %s
|
||||
// CHECK: typealias InvalidAlias = <<error type>>
|
||||
// CHECK: class InvalidClass : <<error type>>, InvalidProtocol
|
||||
// CHECK: var classMemberA: <<error type>>
|
||||
@@ -123,22 +123,22 @@ func testInvalidTopLevelCompletion() {
|
||||
// CHECK: func typeUsesFunc
|
||||
|
||||
// Check completions
|
||||
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t-completions -I %t
|
||||
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t-completions -I %t -allow-compiler-errors
|
||||
|
||||
// Check cursor info for the various symbols
|
||||
// RUN: %sourcekitd-test -req=cursor -pos=4:3 %s -- -I %t -target %target-triple %s | %FileCheck %s -check-prefix=CHECK-GLOBAL
|
||||
// RUN: %sourcekitd-test -req=cursor -pos=4:3 %s -- -Xfrontend -experimental-allow-module-with-compiler-errors -I %t -target %target-triple %s | %FileCheck %s -check-prefix=CHECK-GLOBAL
|
||||
// CHECK-GLOBAL: source.lang.swift.ref.var.global
|
||||
// CHECK-GLOBAL: invalidGlobalMissingInit
|
||||
|
||||
// RUN: %sourcekitd-test -req=cursor -pos=8:3 %s -- -I %t -target %target-triple %s | %FileCheck %s -check-prefix=CHECK-FUNC
|
||||
// RUN: %sourcekitd-test -req=cursor -pos=8:3 %s -- -Xfrontend -experimental-allow-module-with-compiler-errors -I %t -target %target-triple %s | %FileCheck %s -check-prefix=CHECK-FUNC
|
||||
// CHECK-FUNC: source.lang.swift.ref.function.free
|
||||
// CHECK-FUNC: invalidPartialFunc
|
||||
|
||||
// RUN: %sourcekitd-test -req=cursor -pos=12:12 %s -- -I %t -target %target-triple %s | %FileCheck %s -check-prefix=CHECK-STRUCT
|
||||
// RUN: %sourcekitd-test -req=cursor -pos=12:12 %s -- -Xfrontend -experimental-allow-module-with-compiler-errors -I %t -target %target-triple %s | %FileCheck %s -check-prefix=CHECK-STRUCT
|
||||
// CHECK-STRUCT: source.lang.swift.ref.struct
|
||||
// CHECK-STRUCT: InvalidStruct
|
||||
|
||||
// Currently doesn't work for any members with invalid types, even within the same module: rdar://71514163
|
||||
// RUN: %sourcekitd-test -req=cursor -pos=13:7 %s -- -I %t -target %target-triple %s | not %FileCheck %s -check-prefix=CHECK-MEMBER
|
||||
// RUN: %sourcekitd-test -req=cursor -pos=13:7 %s -- -Xfrontend -experimental-allow-module-with-compiler-errors -I %t -target %target-triple %s | not %FileCheck %s -check-prefix=CHECK-MEMBER
|
||||
// CHECK-MEMBER: source.lang.swift.ref.var.instance
|
||||
// CHECK-MEMBER: memberB
|
||||
|
||||
@@ -761,6 +761,11 @@ static llvm::cl::list<std::string>
|
||||
AccessNotesPath("access-notes-path", llvm::cl::desc("Path to access notes file"),
|
||||
llvm::cl::cat(Category));
|
||||
|
||||
static llvm::cl::opt<bool>
|
||||
AllowCompilerErrors("allow-compiler-errors",
|
||||
llvm::cl::desc("Whether to attempt to continue despite compiler errors"),
|
||||
llvm::cl::init(false));
|
||||
|
||||
} // namespace options
|
||||
|
||||
static std::unique_ptr<llvm::MemoryBuffer>
|
||||
@@ -3917,6 +3922,12 @@ int main(int argc, char *argv[]) {
|
||||
options::ExplicitSwiftModuleMap;
|
||||
InitInvok.getFrontendOptions().DisableImplicitModules = true;
|
||||
}
|
||||
|
||||
if (options::AllowCompilerErrors) {
|
||||
InitInvok.getFrontendOptions().AllowModuleWithCompilerErrors = true;
|
||||
InitInvok.getLangOptions().AllowModuleWithCompilerErrors = true;
|
||||
}
|
||||
|
||||
// Process the clang arguments last and allow them to override previously
|
||||
// set options.
|
||||
if (!CCArgs.empty()) {
|
||||
|
||||
Reference in New Issue
Block a user