Files
swift-mirror/include/swift/Serialization/Validation.h
Doug Gregor ed93b46fa6 [Embedded] Introduce DeferredCodeGen feature.
Introduce an experimental feature DeferredCodeGen, that defers the
generation of LLVM IR (and therefore object code) for all entities
within an Embedded Swift module unless they have explicitly requested
to not be emitted into the client (e.g., with
`@_neverEmitIntoClient`).

This feature is meant to generalize and subsume
-emit-empty-object-file, relying on lazy emission of entities rather
than abruptly ending the compilation pipeline before emitting any IR.

Part of rdar://158363967.
2025-09-03 15:55:47 -07:00

363 lines
13 KiB
C++

//===--- Validation.h - Validation / errors for serialization ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SERIALIZATION_VALIDATION_H
#define SWIFT_SERIALIZATION_VALIDATION_H
#include "swift/AST/Identifier.h"
#include "swift/Basic/CXXStdlibKind.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/SourceLoc.h"
#include "swift/Basic/Version.h"
#include "swift/Parse/ParseVersion.h"
#include "swift/Serialization/SerializationOptions.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/TargetParser/Triple.h"
namespace swift {
class ModuleFile;
enum class ResilienceStrategy : unsigned;
namespace serialization {
/// Describes whether a serialized module can be used by this compiler.
enum class Status {
/// The module is valid.
Valid,
/// The module file format is too old to be used by this version of the
/// compiler.
FormatTooOld,
/// The module file format is too new to be used by this version of the
/// compiler.
FormatTooNew,
/// The precise revision version doesn't match.
RevisionIncompatible,
/// The distribution channel doesn't match.
ChannelIncompatible,
/// The module is required to be in OSSA, but is not.
NotInOSSA,
/// The module file depends on another module that can't be loaded.
MissingDependency,
/// The module file is an overlay for a Clang module, which can't be found.
MissingUnderlyingModule,
/// The module file depends on a module that is still being loaded, i.e.
/// there is a circular dependency.
CircularDependency,
/// The module file depends on a bridging header that can't be loaded.
FailedToLoadBridgingHeader,
/// The module file is malformed in some way.
Malformed,
/// The module documentation file is malformed in some way.
MalformedDocumentation,
/// The module file's name does not match the module it is being loaded
/// into.
NameMismatch,
/// The module file was built for a different target platform.
TargetIncompatible,
/// The module file was built for a target newer than the current target.
TargetTooNew,
/// The module file was built with a different SDK than the one in use
/// to build the client.
SDKMismatch,
};
/// Returns the string for the Status enum.
std::string StatusToString(Status S);
/// Returns true if the data looks like it contains a serialized AST.
bool isSerializedAST(StringRef data);
/// \see validateSerializedAST()
struct ValidationInfo {
StringRef name = {};
StringRef targetTriple = {};
StringRef shortVersion = {};
StringRef miscVersion = {};
version::Version compatibilityVersion = {};
llvm::VersionTuple userModuleVersion;
StringRef sdkName = {};
StringRef sdkVersion = {};
StringRef problematicRevision = {};
StringRef problematicChannel = {};
size_t bytes = 0;
Status status = Status::Malformed;
std::vector<StringRef> allowableClients;
};
/// A collection of options that can be used to set up a new AST context
/// before it has been created.
///
/// Note that this is intended to be a transient data structure; as such,
/// <strong>none of the string values added to it are copied</strong>.
///
/// \sa validateSerializedAST()
class ExtendedValidationInfo {
SmallVector<StringRef, 4> ExtraClangImporterOpts;
SmallVector<std::pair<PluginSearchOption::Kind, StringRef>, 2>
PluginSearchOptions;
std::string SDKPath;
StringRef ModuleABIName;
StringRef ModulePackageName;
StringRef ExportAsName;
StringRef PublicModuleName;
CXXStdlibKind CXXStdlib;
version::Version SwiftInterfaceCompilerVersion;
struct {
unsigned ArePrivateImportsEnabled : 1;
unsigned IsSIB : 1;
unsigned IsStaticLibrary : 1;
unsigned HasHermeticSealAtLink : 1;
unsigned IsEmbeddedSwiftModule : 1;
unsigned IsTestable : 1;
unsigned ResilienceStrategy : 2;
unsigned IsImplicitDynamicEnabled : 1;
unsigned IsBuiltFromInterface : 1;
unsigned IsAllowModuleWithCompilerErrorsEnabled : 1;
unsigned IsConcurrencyChecked : 1;
unsigned HasCxxInteroperability : 1;
unsigned AllowNonResilientAccess: 1;
unsigned SerializePackageEnabled: 1;
unsigned StrictMemorySafety: 1;
unsigned DeferredCodeGen: 1;
} Bits;
public:
ExtendedValidationInfo() : Bits() {}
StringRef getSDKPath() const { return SDKPath; }
void setSDKPath(std::string path) {
assert(SDKPath.empty());
SDKPath = path;
}
ArrayRef<StringRef> getExtraClangImporterOptions() const {
return ExtraClangImporterOpts;
}
void addExtraClangImporterOption(StringRef option) {
ExtraClangImporterOpts.push_back(option);
}
ArrayRef<std::pair<PluginSearchOption::Kind, StringRef>>
getPluginSearchOptions() const {
return PluginSearchOptions;
}
void addPluginSearchOption(
const std::pair<PluginSearchOption::Kind, StringRef> &opt) {
PluginSearchOptions.push_back(opt);
}
bool isSIB() const { return Bits.IsSIB; }
void setIsSIB(bool val) {
Bits.IsSIB = val;
}
bool arePrivateImportsEnabled() { return Bits.ArePrivateImportsEnabled; }
void setPrivateImportsEnabled(bool enabled) {
Bits.ArePrivateImportsEnabled = enabled;
}
bool isImplicitDynamicEnabled() { return Bits.IsImplicitDynamicEnabled; }
void setImplicitDynamicEnabled(bool val) {
Bits.IsImplicitDynamicEnabled = val;
}
bool isStaticLibrary() const { return Bits.IsStaticLibrary; }
void setIsStaticLibrary(bool val) {
Bits.IsStaticLibrary = val;
}
bool hasHermeticSealAtLink() const { return Bits.HasHermeticSealAtLink; }
void setHasHermeticSealAtLink(bool val) {
Bits.HasHermeticSealAtLink = val;
}
bool isEmbeddedSwiftModule() const { return Bits.IsEmbeddedSwiftModule; }
void setIsEmbeddedSwiftModule(bool val) {
Bits.IsEmbeddedSwiftModule = val;
}
bool isTestable() const { return Bits.IsTestable; }
void setIsTestable(bool val) {
Bits.IsTestable = val;
}
ResilienceStrategy getResilienceStrategy() const {
return ResilienceStrategy(Bits.ResilienceStrategy);
}
void setResilienceStrategy(ResilienceStrategy resilience) {
Bits.ResilienceStrategy = unsigned(resilience);
}
bool isBuiltFromInterface() const { return Bits.IsBuiltFromInterface; }
void setIsBuiltFromInterface(bool val) {
Bits.IsBuiltFromInterface = val;
}
bool allowNonResilientAccess() const { return Bits.AllowNonResilientAccess; }
void setAllowNonResilientAccess(bool val) {
Bits.AllowNonResilientAccess = val;
}
bool serializePackageEnabled() const { return Bits.SerializePackageEnabled; }
void setSerializePackageEnabled(bool val) {
Bits.SerializePackageEnabled = val;
}
bool isAllowModuleWithCompilerErrorsEnabled() {
return Bits.IsAllowModuleWithCompilerErrorsEnabled;
}
void setAllowModuleWithCompilerErrorsEnabled(bool val) {
Bits.IsAllowModuleWithCompilerErrorsEnabled = val;
}
StringRef getModuleABIName() const { return ModuleABIName; }
void setModuleABIName(StringRef name) { ModuleABIName = name; }
StringRef getModulePackageName() const { return ModulePackageName; }
void setModulePackageName(StringRef name) { ModulePackageName = name; }
StringRef getPublicModuleName() const { return PublicModuleName; }
void setPublicModuleName(StringRef name) { PublicModuleName = name; }
StringRef getExportAsName() const { return ExportAsName; }
void setExportAsName(StringRef name) { ExportAsName = name; }
bool isConcurrencyChecked() const {
return Bits.IsConcurrencyChecked;
}
void setIsConcurrencyChecked(bool val = true) {
Bits.IsConcurrencyChecked = val;
}
bool strictMemorySafety() const {
return Bits.StrictMemorySafety;
}
void setStrictMemorySafety(bool val = true) {
Bits.StrictMemorySafety = val;
}
bool deferredCodeGen() const {
return Bits.DeferredCodeGen;
}
void setDeferredCodeGen(bool val = true) {
Bits.DeferredCodeGen = val;
}
bool hasCxxInteroperability() const { return Bits.HasCxxInteroperability; }
void setHasCxxInteroperability(bool val) {
Bits.HasCxxInteroperability = val;
}
CXXStdlibKind getCXXStdlibKind() const { return CXXStdlib; }
void setCXXStdlibKind(CXXStdlibKind kind) { CXXStdlib = kind; }
version::Version getSwiftInterfaceCompilerVersion() const {
return SwiftInterfaceCompilerVersion;
}
void setSwiftInterfaceCompilerVersion(StringRef version) {
if (auto genericVersion = VersionParser::parseVersionString(
version, SourceLoc(), /*Diags=*/nullptr))
SwiftInterfaceCompilerVersion = genericVersion.value();
}
};
struct SearchPath {
std::string Path;
bool IsFramework;
bool IsSystem;
};
/// Returns info about the serialized AST in the given data.
///
/// If the returned status is anything but Status::Valid, the serialized data
/// cannot be loaded by this version of the compiler. If the returned size is
/// non-zero, it's possible to skip over this module's data, in case there is
/// more data in the buffer. The returned name, which may be empty, directly
/// points into the given data buffer.
///
/// Note that this does not actually try to load the module or validate any
/// of its dependencies; it only checks that it /can/ be loaded.
///
/// \param data A buffer containing the serialized AST. Result information
/// refers directly into this buffer.
/// \param requiresOSSAModules If true, necessitates the module to be
/// compiled with -enable-ossa-modules.
/// \param requiredSDK If not empty, only accept modules built with
/// a compatible SDK. The StringRef represents the canonical SDK name.
/// \param target The target triple of the current compilation for
/// validating that the module we are attempting to load is compatible.
/// \param[out] extendedInfo If present, will be populated with additional
/// compilation options serialized into the AST at build time that may be
/// necessary to load it properly.
/// \param[out] dependencies If present, will be populated with list of
/// input files the module depends on, if present in INPUT_BLOCK.
ValidationInfo validateSerializedAST(
StringRef data, bool requiresOSSAModules,
StringRef requiredSDK,
ExtendedValidationInfo *extendedInfo = nullptr,
SmallVectorImpl<SerializationOptions::FileDependency> *dependencies =
nullptr,
SmallVectorImpl<SearchPath> *searchPaths = nullptr,
std::optional<llvm::Triple> target = std::nullopt);
/// Emit diagnostics explaining a failure to load a serialized AST.
///
/// - \p Ctx is an AST context through which any diagnostics are surfaced.
/// - \p diagLoc is the (possibly invalid) location used in the diagnostics.
/// - \p loadInfo and \p extendedInfo describe the attempt to load an AST
/// (\ref validateSerializedAST). Note that loadInfo.Status must not be
/// Status::Valid.
/// - \p moduleBufferID and \p moduleDocBufferID are the buffer identifiers
/// of the module input and doc input buffers respectively (\ref
/// SerializedModuleLoaderBase::loadAST, \ref ModuleFile::load).
/// - \p loadedModuleFile is an invalid loaded module.
/// - \p ModuleName is the name used to refer to the module in diagnostics.
void diagnoseSerializedASTLoadFailure(
ASTContext &Ctx, SourceLoc diagLoc, const ValidationInfo &loadInfo,
StringRef moduleBufferID, StringRef moduleDocBufferID,
ModuleFile *loadedModuleFile, Identifier ModuleName);
/// Emit diagnostics explaining a failure to load a serialized AST,
/// this version only supports diagnostics relevant to transitive dependencies:
/// missing dependency, missing underlying module, or circular dependency.
///
/// \see diagnoseSerializedASTLoadFailure that supports all diagnostics.
///
/// - \p Ctx is an AST context through which any diagnostics are surfaced.
/// - \p diagLoc is the (possibly invalid) location used in the diagnostics.
/// - \p status describes the issue with loading the AST. It must not be
/// Status::Valid.
/// - \p loadedModuleFile is an invalid loaded module.
/// - \p ModuleName is the name used to refer to the module in diagnostics.
/// - \p forTestable indicates if we loaded the AST for a @testable import.
void diagnoseSerializedASTLoadFailureTransitive(
ASTContext &Ctx, SourceLoc diagLoc, const serialization::Status status,
ModuleFile *loadedModuleFile, Identifier ModuleName, bool forTestable);
/// Determine whether two triples are considered to be compatible for module
/// serialization purposes.
bool areCompatible(const llvm::Triple &moduleTarget,
const llvm::Triple &ctxTarget);
} // end namespace serialization
} // end namespace swift
#endif