mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
SILModule::isVisibleExternally utility for VarDecls. (#16834)
* SILModule::isVisibleExternally utility for VarDecls. * Fix the SIL parser so it doesn't drop global variable decls. This information was getting lost in SIL printing/parsing. Some passes rely on it. Regardless of whether passes should rely on it, it is totally unacceptable for the SIL passes to have subtle differences in behavior depending on the frontend mode. So, if we don't want passes to rely on global variable decls, that needs to be enforced by the API independent of how the frontend is invoked or how SIL is serialized. * Use custom DemangleOptions to lookup global variable identifiers.
This commit is contained in:
@@ -43,11 +43,7 @@ namespace swift {
|
||||
Parser &P;
|
||||
public:
|
||||
explicit PrettyStackTraceParser(Parser &P) : P(P) {}
|
||||
void print(llvm::raw_ostream &out) const override {
|
||||
out << "With parser at source location: ";
|
||||
P.Tok.getLoc().print(out, P.Context.SourceMgr);
|
||||
out << '\n';
|
||||
}
|
||||
void print(llvm::raw_ostream &out) const override;
|
||||
};
|
||||
} // end namespace swift
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
namespace swift {
|
||||
|
||||
class ValueDecl;
|
||||
|
||||
/// Linkage for a SIL object. This concept combines the notions
|
||||
/// of symbol linkage and visibility.
|
||||
///
|
||||
@@ -176,6 +178,8 @@ inline bool isPossiblyUsedExternally(SILLinkage linkage, bool wholeModule) {
|
||||
return linkage <= SILLinkage::Hidden;
|
||||
}
|
||||
|
||||
SILLinkage getDeclSILLinkage(const ValueDecl *decl);
|
||||
|
||||
inline bool hasPublicVisibility(SILLinkage linkage) {
|
||||
switch (linkage) {
|
||||
case SILLinkage::Public:
|
||||
|
||||
@@ -474,6 +474,14 @@ public:
|
||||
void setOptRecordStream(std::unique_ptr<llvm::yaml::Output> &&Stream,
|
||||
std::unique_ptr<llvm::raw_ostream> &&RawStream);
|
||||
|
||||
// This is currently limited to VarDecl because the visibility of global
|
||||
// variables and class properties is straightforward, while the visibility of
|
||||
// class methods (ValueDecls) depends on the subclass scope. "Visiblity" has
|
||||
// a different meaning when vtable layout is at stake.
|
||||
bool isVisibleExternally(const VarDecl *decl) {
|
||||
return isPossiblyUsedExternally(getDeclSILLinkage(decl), isWholeModule());
|
||||
}
|
||||
|
||||
PropertyListType &getPropertyList() { return properties; }
|
||||
const PropertyListType &getPropertyList() const { return properties; }
|
||||
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
#include "swift/AST/ProtocolConformance.h"
|
||||
#include "swift/Basic/Defer.h"
|
||||
#include "swift/Basic/Timer.h"
|
||||
#include "swift/Demangling/Demangle.h"
|
||||
#include "swift/Parse/Lexer.h"
|
||||
#include "swift/Parse/Parser.h"
|
||||
#include "swift/Parse/ParseSILSupport.h"
|
||||
#include "swift/Parse/Parser.h"
|
||||
#include "swift/SIL/AbstractionPattern.h"
|
||||
#include "swift/SIL/InstructionUtils.h"
|
||||
#include "swift/SIL/SILArgument.h"
|
||||
@@ -28,8 +29,8 @@
|
||||
#include "swift/SIL/SILModule.h"
|
||||
#include "swift/SIL/SILUndef.h"
|
||||
#include "swift/SIL/TypeLowering.h"
|
||||
#include "swift/Syntax/SyntaxKind.h"
|
||||
#include "swift/Subsystems.h"
|
||||
#include "swift/Syntax/SyntaxKind.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/SaveAndRestore.h"
|
||||
|
||||
@@ -99,6 +100,12 @@ SILParserState::SILParserState(SILModule *M)
|
||||
|
||||
SILParserState::~SILParserState() = default;
|
||||
|
||||
void PrettyStackTraceParser::print(llvm::raw_ostream &out) const {
|
||||
out << "With parser at source location: ";
|
||||
P.Tok.getLoc().print(out, P.Context.SourceMgr);
|
||||
out << '\n';
|
||||
}
|
||||
|
||||
bool swift::parseIntoSourceFile(SourceFile &SF,
|
||||
unsigned BufferID,
|
||||
bool *Done,
|
||||
@@ -5374,6 +5381,53 @@ bool SILParserTUState::parseDeclSILStage(Parser &P) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Lookup a global variable declaration from its demangled name.
|
||||
///
|
||||
/// A variable declaration exists for all sil_global variables defined in
|
||||
/// Swift. A Swift global defined outside this module will be exposed
|
||||
/// via an addressor rather than as a sil_global. Globals imported
|
||||
/// from clang will produce a sil_global but will not have any corresponding
|
||||
/// VarDecl.
|
||||
///
|
||||
/// FIXME: lookupGlobalDecl() can handle collisions between private or
|
||||
/// fileprivate global variables in the same SIL Module, but the typechecker
|
||||
/// will still incorrectly diagnose this as an "invalid redeclaration" and give
|
||||
/// all but the first declaration an error type.
|
||||
static Optional<VarDecl *> lookupGlobalDecl(Identifier GlobalName,
|
||||
SILLinkage GlobalLinkage,
|
||||
SILType GlobalType, Parser &P) {
|
||||
// Create a set of DemangleOptions to produce the global variable's
|
||||
// identifier, which is used as a search key in the declaration context.
|
||||
Demangle::DemangleOptions demangleOpts;
|
||||
demangleOpts.QualifyEntities = false;
|
||||
demangleOpts.ShowPrivateDiscriminators = false;
|
||||
demangleOpts.DisplayEntityTypes = false;
|
||||
std::string GlobalDeclName = Demangle::demangleSymbolAsString(
|
||||
GlobalName.str(), demangleOpts);
|
||||
|
||||
SmallVector<ValueDecl *, 4> CurModuleResults;
|
||||
P.SF.getParentModule()->lookupValue(
|
||||
{}, P.Context.getIdentifier(GlobalDeclName), NLKind::UnqualifiedLookup,
|
||||
CurModuleResults);
|
||||
// Bail-out on clang-imported globals.
|
||||
if (CurModuleResults.empty())
|
||||
return nullptr;
|
||||
|
||||
// private and fileprivate globals of the same name may be merged into a
|
||||
// single SIL module. Find the declaration with the correct type and
|
||||
// linkage. (If multiple globals have the same type and linkage then it
|
||||
// doesn't matter which declaration we use).
|
||||
for (ValueDecl *ValDecl : CurModuleResults) {
|
||||
auto *VD = cast<VarDecl>(ValDecl);
|
||||
CanType DeclTy = VD->getType()->getCanonicalType();
|
||||
if (DeclTy == GlobalType.getASTType()
|
||||
&& getDeclSILLinkage(VD) == GlobalLinkage) {
|
||||
return VD;
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
/// decl-sil-global: [[only in SIL mode]]
|
||||
/// 'sil_global' sil-linkage @name : sil-type [external]
|
||||
bool SILParserTUState::parseSILGlobal(Parser &P) {
|
||||
@@ -5406,11 +5460,16 @@ bool SILParserTUState::parseSILGlobal(Parser &P) {
|
||||
if (!GlobalLinkage.hasValue())
|
||||
GlobalLinkage = SILLinkage::DefaultForDefinition;
|
||||
|
||||
// FIXME: check for existing global variable?
|
||||
auto *GV = SILGlobalVariable::create(M, GlobalLinkage.getValue(),
|
||||
isSerialized,
|
||||
GlobalName.str(),GlobalType,
|
||||
RegularLocation(NameLoc));
|
||||
// Lookup the global variable declaration for this sil_global.
|
||||
auto VD =
|
||||
lookupGlobalDecl(GlobalName, GlobalLinkage.getValue(), GlobalType, P);
|
||||
if (!VD) {
|
||||
P.diagnose(NameLoc, diag::sil_global_variable_not_found, GlobalName);
|
||||
return true;
|
||||
}
|
||||
auto *GV = SILGlobalVariable::create(
|
||||
M, GlobalLinkage.getValue(), isSerialized, GlobalName.str(), GlobalType,
|
||||
RegularLocation(NameLoc), VD.getValue());
|
||||
|
||||
GV->setLet(isLet);
|
||||
// Parse static initializer if exists.
|
||||
|
||||
@@ -855,3 +855,22 @@ SILProperty *SILProperty::create(SILModule &M,
|
||||
return prop;
|
||||
}
|
||||
|
||||
// Definition from SILLinkage.h.
|
||||
SILLinkage swift::getDeclSILLinkage(const ValueDecl *decl) {
|
||||
AccessLevel access = decl->getEffectiveAccess();
|
||||
SILLinkage linkage;
|
||||
switch (access) {
|
||||
case AccessLevel::Private:
|
||||
case AccessLevel::FilePrivate:
|
||||
linkage = SILLinkage::Private;
|
||||
break;
|
||||
case AccessLevel::Internal:
|
||||
linkage = SILLinkage::Hidden;
|
||||
break;
|
||||
case AccessLevel::Public:
|
||||
case AccessLevel::Open:
|
||||
linkage = SILLinkage::Public;
|
||||
break;
|
||||
}
|
||||
return linkage;
|
||||
}
|
||||
|
||||
@@ -371,6 +371,13 @@ protected:
|
||||
}
|
||||
|
||||
/// Retrieve the visibility information from the AST.
|
||||
///
|
||||
/// This differs from SILModule::isVisibleExternally(VarDecl *) because of
|
||||
/// it's handling of class methods. It returns true for methods whose
|
||||
/// declarations are not directly visible externally, but have been imported
|
||||
/// from another module. This ensures that entries aren't deleted from vtables
|
||||
/// imported from the stdlib.
|
||||
/// FIXME: Passes should not embed special logic for handling linkage.
|
||||
bool isVisibleExternally(const ValueDecl *decl) {
|
||||
AccessLevel access = decl->getEffectiveAccess();
|
||||
SILLinkage linkage;
|
||||
@@ -390,9 +397,7 @@ protected:
|
||||
if (isPossiblyUsedExternally(linkage, Module->isWholeModule()))
|
||||
return true;
|
||||
|
||||
// If a vtable or witness table (method) is only visible in another module
|
||||
// it can be accessed inside that module and we don't see this access.
|
||||
// We hit this case e.g. if a table is imported from the stdlib.
|
||||
// Special case for vtable visibility.
|
||||
if (decl->getDeclContext()->getParentModule() != Module->getSwiftModule())
|
||||
return true;
|
||||
|
||||
|
||||
@@ -128,25 +128,6 @@ class GlobalPropertyOpt {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isVisibleExternally(VarDecl *decl) {
|
||||
AccessLevel access = decl->getEffectiveAccess();
|
||||
SILLinkage linkage;
|
||||
switch (access) {
|
||||
case AccessLevel::Private:
|
||||
case AccessLevel::FilePrivate:
|
||||
linkage = SILLinkage::Private;
|
||||
break;
|
||||
case AccessLevel::Internal:
|
||||
linkage = SILLinkage::Hidden;
|
||||
break;
|
||||
case AccessLevel::Public:
|
||||
case AccessLevel::Open:
|
||||
linkage = SILLinkage::Public;
|
||||
break;
|
||||
}
|
||||
return isPossiblyUsedExternally(linkage, M.isWholeModule());
|
||||
}
|
||||
|
||||
static bool canAddressEscape(SILValue V, bool acceptStore);
|
||||
|
||||
/// Gets the entry for a struct or class field.
|
||||
@@ -154,7 +135,7 @@ class GlobalPropertyOpt {
|
||||
Entry * &entry = FieldEntries[Field];
|
||||
if (!entry) {
|
||||
entry = new (EntryAllocator.Allocate()) Entry(SILValue(), Field);
|
||||
if (isVisibleExternally(Field))
|
||||
if (M.isVisibleExternally(Field))
|
||||
setAddressEscapes(entry);
|
||||
}
|
||||
return entry;
|
||||
|
||||
@@ -284,28 +284,7 @@ static bool isSameInitSequence(const InitSequence &LHS,
|
||||
|
||||
/// Check if a given let property can be assigned externally.
|
||||
static bool isAssignableExternally(VarDecl *Property, SILModule *Module) {
|
||||
AccessLevel access = Property->getEffectiveAccess();
|
||||
SILLinkage linkage;
|
||||
switch (access) {
|
||||
case AccessLevel::Private:
|
||||
case AccessLevel::FilePrivate:
|
||||
linkage = SILLinkage::Private;
|
||||
DEBUG(llvm::dbgs() << "Property " << *Property << " has private access\n");
|
||||
break;
|
||||
case AccessLevel::Internal:
|
||||
linkage = SILLinkage::Hidden;
|
||||
DEBUG(llvm::dbgs() << "Property " << *Property << " has internal access\n");
|
||||
break;
|
||||
case AccessLevel::Public:
|
||||
case AccessLevel::Open:
|
||||
linkage = SILLinkage::Public;
|
||||
DEBUG(llvm::dbgs() << "Property " << *Property << " has public access\n");
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG(llvm::dbgs() << "Module of " << *Property << " WMO mode is: " << Module->isWholeModule() << "\n");
|
||||
|
||||
if (isPossiblyUsedExternally(linkage, Module->isWholeModule())) {
|
||||
if (Module->isVisibleExternally(Property)) {
|
||||
// If at least one of the properties of the enclosing type cannot be
|
||||
// used externally, then no initializer can be implemented externally as
|
||||
// it wouldn't be able to initialize such a property.
|
||||
|
||||
54
test/SIL/Parser/global_decl.sil
Normal file
54
test/SIL/Parser/global_decl.sil
Normal file
@@ -0,0 +1,54 @@
|
||||
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s
|
||||
|
||||
// Check that sil_globals and their corresponding decls are
|
||||
// parsed. There is no direct way to verify that the declarations are
|
||||
// properly associated with the sil_globals, so just make sure it succeeds.
|
||||
//
|
||||
// FIXME: Add support for name collisions across private/fileprivate globals.
|
||||
|
||||
sil_stage canonical
|
||||
|
||||
import Builtin
|
||||
import Swift
|
||||
import SwiftShims
|
||||
|
||||
struct S {
|
||||
init()
|
||||
}
|
||||
|
||||
class C {
|
||||
init()
|
||||
deinit
|
||||
}
|
||||
|
||||
enum E {
|
||||
case a
|
||||
@_implements(Equatable, ==(_:_:)) static func __derived_enum_equals(_ a: E, _ b: E) -> Bool
|
||||
var hashValue: Int { get }
|
||||
func hash(into hasher: inout Hasher)
|
||||
}
|
||||
|
||||
private var global1: S
|
||||
|
||||
fileprivate var global2: C
|
||||
|
||||
var global3: E
|
||||
|
||||
public var global4: Int
|
||||
|
||||
weak var global5: @sil_weak C?
|
||||
|
||||
// CHECK: sil_global private @$S11global_decl7global133_EB6670D548223EDC99AF0D8F02575BC4LLAA1SVvp : $S
|
||||
sil_global private @$S11global_decl7global133_EB6670D548223EDC99AF0D8F02575BC4LLAA1SVvp : $S
|
||||
|
||||
// CHECK: sil_global private @$S11global_decl7global233_EB6670D548223EDC99AF0D8F02575BC4LLAA1CCvp : $C
|
||||
sil_global private @$S11global_decl7global233_EB6670D548223EDC99AF0D8F02575BC4LLAA1CCvp : $C
|
||||
|
||||
// CHECK: sil_global hidden @$S11global_decl7global3AA1EOvp : $E
|
||||
sil_global hidden @$S11global_decl7global3AA1EOvp : $E
|
||||
|
||||
// CHECK: sil_global @$S11global_decl7global4Sivp : $Int
|
||||
sil_global @$S11global_decl7global4Sivp : $Int
|
||||
|
||||
// CHECK: sil_global hidden @$S11global_decl7global5AA1CCSgXwvp : $@sil_weak Optional<C>
|
||||
sil_global hidden @$S11global_decl7global5AA1CCSgXwvp : $@sil_weak Optional<C>
|
||||
Reference in New Issue
Block a user