Merge pull request #37472 from bnbarham/cleanup-allow-errors

[Serialization] Add whether allowing errors to the pretty stack output
This commit is contained in:
Ben Barham
2021-05-26 11:07:47 +10:00
committed by GitHub
13 changed files with 112 additions and 36 deletions

View File

@@ -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)",

View File

@@ -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,

View File

@@ -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)";
}

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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(); }

View File

@@ -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,

View File

@@ -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.

View File

@@ -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()

View 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)

View 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

View File

@@ -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

View File

@@ -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()) {