Skip to content

Commit 1e94cbc

Browse files
committed
Type check ABI decls
Sema now type-checks the alternate ABI-providing decls inside of @abi attributes. Making this work—particularly, making redeclaration checking work—required making name lookup aware of ABI decls. Name lookup now evaluates both API-providing and ABI-providing declarations. In most cases, it will filter ABI-only decls out unless a specific flag is passed, in which case it will filter API-only decls out instead. Calls that simply retrieve a list of declarations, like `IterableDeclContext::getMembers()` and friends, typically only return API-providing decls; you have to access the ABI-providing ones through those. As part of that work, I have also added some basic compiler interfaces for working with the API-providing and ABI-providing variants. `ABIRole` encodes whether a declaration provides only API, only ABI, or both, and `ABIRoleInfo` combines that with a pointer to the counterpart providing the other role (for a declaration that provides both, that’ll just be a pointer to `this`). Decl checking of behavior specific to @abi will come in a future commit. Note that this probably doesn’t properly exercise some of the new code (ASTScope::lookupEnclosingABIAttributeScope(), for instance); I expect that to happen only once we can rename types using an @abi attribute, since that will create distinguishable behavior differences when resolving TypeReprs in other @abi attributes.
1 parent 07054af commit 1e94cbc

29 files changed

+622
-141
lines changed

include/swift/AST/ASTScope.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class ASTScopeImpl : public ASTAllocated<ASTScopeImpl> {
142142
friend class IterableTypeBodyPortion;
143143
friend class ScopeCreator;
144144
friend class ASTSourceFileScope;
145+
friend class ABIAttributeScope;
145146
friend class Lowering::SILGenFunction;
146147

147148
#pragma mark - tree state
@@ -305,6 +306,9 @@ class ASTScopeImpl : public ASTAllocated<ASTScopeImpl> {
305306
SourceFile *sourceFile, SourceLoc loc,
306307
llvm::function_ref<bool(ASTScope::PotentialMacro)> consume);
307308

309+
static ABIAttr *lookupEnclosingABIAttributeScope(
310+
SourceFile *sourceFile, SourceLoc loc);
311+
308312
static CatchNode lookupCatchNode(ModuleDecl *module, SourceLoc loc);
309313

310314
/// Scopes that cannot bind variables may set this to true to create more
@@ -948,6 +952,40 @@ class CustomAttributeScope final : public ASTScopeImpl {
948952
}
949953
};
950954

955+
/// The scope for ABI attributes and their arguments.
956+
///
957+
/// Source locations for the attribute name and its arguments are in the
958+
/// custom attribute, so lookup is invoked from within the attribute
959+
/// itself.
960+
class ABIAttributeScope final : public ASTScopeImpl {
961+
public:
962+
ABIAttr *attr;
963+
Decl *decl;
964+
965+
ABIAttributeScope(ABIAttr *attr, Decl *decl)
966+
: ASTScopeImpl(ScopeKind::ABIAttribute), attr(attr), decl(decl) {}
967+
virtual ~ABIAttributeScope() {}
968+
969+
protected:
970+
ASTScopeImpl *expandSpecifically(ScopeCreator &) override;
971+
972+
public:
973+
SourceRange
974+
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
975+
NullablePtr<const void> addressForPrinting() const override { return decl; }
976+
977+
bool ignoreInDebugInfo() const override { return true; }
978+
979+
private:
980+
AnnotatedInsertionPoint
981+
expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &);
982+
983+
public:
984+
static bool classof(const ASTScopeImpl *scope) {
985+
return scope->getKind() == ScopeKind::ABIAttribute;
986+
}
987+
};
988+
951989
/// PatternBindingDecl's (PBDs) are tricky (See the comment for \c
952990
/// PatternBindingDecl):
953991
///

include/swift/AST/ASTScopeNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ SCOPE_NODE(CaseLabelItem)
8989
SCOPE_NODE(CaseStmtBody)
9090
STMT_SCOPE_NODE(BraceStmt)
9191
EXPR_SCOPE_NODE(Try)
92+
DECL_ATTRIBUTE_SCOPE_NODE(ABIAttribute)
9293

9394
#undef DECL_ATTRIBUTE_SCOPE_NODE
9495
#undef EXPR_SCOPE_NODE

include/swift/AST/Attr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2934,7 +2934,7 @@ class ABIAttr : public DeclAttribute {
29342934

29352935
/// Is this attribute attached to the ABI declaration and pointing back to
29362936
/// the original? Inverse \c ABIAttr s are always implicit and result in an
2937-
/// \c ABIRole with \c providesAPI() but not \c providesABI() .
2937+
/// \c ABIRoleInfo with \c providesAPI() but not \c providesABI() .
29382938
bool isInverse() const { return Bits.ABIAttr.isInverse; }
29392939

29402940
void connectToInverse(Decl *owner) const;

include/swift/AST/Decl.h

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ namespace swift {
9494
class MacroDefinition;
9595
class ModuleDecl;
9696
class NamedPattern;
97+
enum NLOptions : unsigned;
9798
class EnumCaseDecl;
9899
class EnumElementDecl;
99100
class ParameterList;
@@ -4338,6 +4339,9 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
43384339
IncludeAttrImplements = 1 << 0,
43394340
/// Whether to exclude members of macro expansions.
43404341
ExcludeMacroExpansions = 1 << 1,
4342+
/// If @abi attributes are present, return the decls representing the ABI,
4343+
/// not the API.
4344+
ABIProviding = 1 << 2,
43414345
};
43424346

43434347
/// Find all of the declarations with the given name within this nominal type
@@ -9772,6 +9776,126 @@ const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index);
97729776
/// nullptr if the source does not have a parameter list.
97739777
const ParamDecl *getParameterAt(const DeclContext *source, unsigned index);
97749778

9779+
class ABIRole {
9780+
public:
9781+
enum Value : uint8_t {
9782+
Neither = 0,
9783+
ProvidesABI = 1 << 0,
9784+
ProvidesAPI = 1 << 1,
9785+
Either = ProvidesABI | ProvidesAPI,
9786+
};
9787+
9788+
Value value;
9789+
9790+
ABIRole(Value value)
9791+
: value(value)
9792+
{ }
9793+
9794+
ABIRole()
9795+
: ABIRole(Neither)
9796+
{ }
9797+
9798+
explicit ABIRole(NLOptions opts);
9799+
9800+
template<typename FlagType>
9801+
explicit ABIRole(OptionSet<FlagType> flags)
9802+
: value(flags.contains(FlagType::ABIProviding) ? ProvidesABI : ProvidesAPI)
9803+
{ }
9804+
9805+
inline ABIRole operator|(ABIRole rhs) const {
9806+
return ABIRole(ABIRole::Value(value | rhs.value));
9807+
}
9808+
inline ABIRole &operator|=(ABIRole rhs) {
9809+
value = ABIRole::Value(value | rhs.value);
9810+
return *this;
9811+
}
9812+
inline ABIRole operator&(ABIRole rhs) const {
9813+
return ABIRole(ABIRole::Value(value & rhs.value));
9814+
}
9815+
inline ABIRole &operator&=(ABIRole rhs) {
9816+
value = ABIRole::Value(value & rhs.value);
9817+
return *this;
9818+
}
9819+
inline ABIRole operator~() const {
9820+
return ABIRole(ABIRole::Value(~value));
9821+
}
9822+
9823+
operator bool() const {
9824+
return value != Neither;
9825+
}
9826+
};
9827+
9828+
namespace abi_role_detail {
9829+
9830+
using Storage = llvm::PointerIntPair<Decl *, 2, ABIRole::Value>;
9831+
Storage computeStorage(Decl *decl);
9832+
9833+
}
9834+
9835+
/// Specifies the \c ABIAttr -related behavior of this declaration
9836+
/// and provides access to its counterpart.
9837+
///
9838+
/// A given declaration may provide the API, the ABI, or both. If it provides
9839+
/// API, the counterpart is the matching ABI-providing decl; if it provides
9840+
/// ABI, the countepart is the matching API-providing decl. A declaration
9841+
/// which provides both API and ABI is its own counterpart.
9842+
///
9843+
/// If the counterpart is \c nullptr , this indicates a fundamental mismatch
9844+
/// between decl and counterpart. Sometimes this mismatch is a difference in
9845+
/// decl kind; in these cases, \c getCounterpartUnchecked() will return the
9846+
/// incorrect counterpart.
9847+
template<typename SpecificDecl>
9848+
class ABIRoleInfo {
9849+
friend abi_role_detail::Storage abi_role_detail::computeStorage(Decl *);
9850+
9851+
abi_role_detail::Storage counterpartAndFlags;
9852+
9853+
ABIRoleInfo(abi_role_detail::Storage storage)
9854+
: counterpartAndFlags(storage)
9855+
{ }
9856+
9857+
public:
9858+
explicit ABIRoleInfo(const SpecificDecl *decl)
9859+
: ABIRoleInfo(abi_role_detail::computeStorage(const_cast<SpecificDecl *>(decl)))
9860+
{ }
9861+
9862+
Decl *getCounterpartUnchecked() const {
9863+
return counterpartAndFlags.getPointer();
9864+
}
9865+
9866+
SpecificDecl *getCounterpart() const {
9867+
return dyn_cast_or_null<SpecificDecl>(getCounterpartUnchecked());
9868+
}
9869+
9870+
ABIRole getRole() const {
9871+
return ABIRole(ABIRole::Value(counterpartAndFlags.getInt()));
9872+
}
9873+
9874+
bool matches(ABIRole desiredRole) const {
9875+
return getRole() & desiredRole;
9876+
}
9877+
9878+
template<typename Options>
9879+
bool matchesOptions(Options opts) const {
9880+
return matches(ABIRole(opts));
9881+
}
9882+
9883+
bool providesABI() const {
9884+
return matches(ABIRole::ProvidesABI);
9885+
}
9886+
9887+
bool providesAPI() const {
9888+
return matches(ABIRole::ProvidesAPI);
9889+
}
9890+
9891+
bool hasABIAttr() const {
9892+
return !providesABI();
9893+
}
9894+
};
9895+
9896+
template<typename SpecificDecl>
9897+
ABIRoleInfo(const SpecificDecl *decl) -> ABIRoleInfo<SpecificDecl>;
9898+
97759899
StringRef
97769900
getAccessorNameForDiagnostic(AccessorDecl *accessor, bool article,
97779901
std::optional<bool> underscored = std::nullopt);

include/swift/AST/LookupKinds.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ enum NLOptions : unsigned {
6464
/// from a module that has not been imported.
6565
NL_IgnoreMissingImports = 1 << 9,
6666

67+
/// If @abi attributes are present, return the decls representing the ABI,
68+
/// not the API.
69+
NL_ABIProviding = 1 << 10,
70+
6771
/// The default set of options used for qualified name lookup.
6872
///
6973
/// FIXME: Eventually, add NL_ProtocolMembers to this, once all of the
@@ -97,6 +101,9 @@ void simple_display(llvm::raw_ostream &out, NLOptions options);
97101
enum class ModuleLookupFlags : unsigned {
98102
/// Exclude names introduced by macro expansions in the top-level module.
99103
ExcludeMacroExpansions = 1 << 0,
104+
/// If @abi attributes are present, return the decls representing the ABI,
105+
/// not the API.
106+
ABIProviding = 1 << 1,
100107
};
101108

102109
} // end namespace swift

include/swift/AST/NameLookup.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ enum class UnqualifiedLookupFlags {
253253
/// This lookup should include members that would otherwise be filtered out
254254
/// because they come from a module that has not been imported.
255255
IgnoreMissingImports = 1 << 10,
256+
/// If @abi attributes are present, return the decls representing the ABI,
257+
/// not the API.
258+
ABIProviding = 1 << 11,
256259

257260
// Reminder: If you add a flag, make sure you update simple_display() below
258261
};
@@ -564,6 +567,9 @@ template <typename Result>
564567
void filterForDiscriminator(SmallVectorImpl<Result> &results,
565568
DebuggerClient *debugClient);
566569

570+
/// \returns Whether the given source location is inside an \@abi attribute.
571+
bool isInABIAttr(SourceFile *sourceFile, SourceLoc loc);
572+
567573
/// \returns The set of macro declarations with the given name that
568574
/// fulfill any of the given macro roles.
569575
SmallVector<MacroDecl *, 1> lookupMacros(DeclContext *dc,
@@ -758,8 +764,16 @@ class ASTScope : public ASTAllocated<ASTScope> {
758764
/// local declarations inside the innermost syntactic scope only.
759765
static void lookupLocalDecls(SourceFile *, DeclName, SourceLoc,
760766
bool stopAfterInnermostBraceStmt,
767+
ABIRole roleFilter,
761768
SmallVectorImpl<ValueDecl *> &);
762769

770+
static void lookupLocalDecls(SourceFile *sf, DeclName name, SourceLoc loc,
771+
bool stopAfterInnermostBraceStmt,
772+
SmallVectorImpl<ValueDecl *> &results) {
773+
lookupLocalDecls(sf, name, loc, stopAfterInnermostBraceStmt,
774+
ABIRole::ProvidesAPI, results);
775+
}
776+
763777
/// Returns the result if there is exactly one, nullptr otherwise.
764778
static ValueDecl *lookupSingleLocalDecl(SourceFile *, DeclName, SourceLoc);
765779

@@ -804,6 +818,18 @@ class ASTScope : public ASTAllocated<ASTScope> {
804818
SourceFile *sourceFile, SourceLoc loc,
805819
llvm::function_ref<bool(PotentialMacro macro)> consume);
806820

821+
/// Look up the scope tree for the nearest enclosing ABI attribute at
822+
/// the given source location.
823+
///
824+
/// \param sourceFile The source file containing the given location.
825+
/// \param loc The source location to start lookup from.
826+
/// \param consume A function that is called when an ABI attribute
827+
/// scope is found. If \c consume returns \c true, lookup
828+
/// will stop. If \c consume returns \c false, lookup will
829+
/// continue up the scope tree.
830+
static ABIAttr *lookupEnclosingABIAttributeScope(
831+
SourceFile *sourceFile, SourceLoc loc);
832+
807833
/// Look up the scope tree for the nearest point at which an error thrown from
808834
/// this location can be caught or rethrown.
809835
///

lib/AST/ASTDumper.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,7 @@ namespace {
990990
TerminalColor Color = DeclColor) {
991991
printFieldQuotedRaw([&](raw_ostream &OS) { declRef.dump(OS); }, label,
992992
Color);
993+
printFlag(!ABIRoleInfo(declRef.getDecl()).providesAPI(), "abi_only_decl");
993994
}
994995

995996
void printThrowDest(ThrownErrorDestination throws, bool wantNothrow) {
@@ -1185,6 +1186,8 @@ namespace {
11851186
printFieldQuoted(implAttr->CategoryName.str(), label);
11861187
}
11871188

1189+
printFlag(!ABIRoleInfo(D).providesAPI(), "abi_only");
1190+
11881191
printSourceRange(D->getSourceRange(), &D->getASTContext());
11891192
printFlag(D->TrailingSemiLoc.isValid(), "trailing_semi",
11901193
DeclModifierColor);

lib/AST/ASTScope.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ void ASTScope::lookupEnclosingMacroScope(
6767
return ASTScopeImpl::lookupEnclosingMacroScope(sourceFile, loc, body);
6868
}
6969

70+
ABIAttr *ASTScope::lookupEnclosingABIAttributeScope(
71+
SourceFile *sourceFile, SourceLoc loc) {
72+
return ASTScopeImpl::lookupEnclosingABIAttributeScope(sourceFile, loc);
73+
}
74+
7075
CatchNode ASTScope::lookupCatchNode(ModuleDecl *module, SourceLoc loc) {
7176
return ASTScopeImpl::lookupCatchNode(module, loc);
7277
}

0 commit comments

Comments
 (0)