Skip to content

Commit 76e1750

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 7fcce43 commit 76e1750

29 files changed

+619
-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
@@ -946,6 +950,40 @@ class CustomAttributeScope final : public ASTScopeImpl {
946950
}
947951
};
948952

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

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
@@ -3333,7 +3333,7 @@ class ABIAttr : public DeclAttribute {
33333333

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

33393339
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;
@@ -4281,6 +4282,9 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
42814282
IncludeAttrImplements = 1 << 0,
42824283
/// Whether to exclude members of macro expansions.
42834284
ExcludeMacroExpansions = 1 << 1,
4285+
/// If @abi attributes are present, return the decls representing the ABI,
4286+
/// not the API.
4287+
ABIProviding = 1 << 2,
42844288
};
42854289

42864290
/// Find all of the declarations with the given name within this nominal type
@@ -9669,6 +9673,126 @@ const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index);
96699673
/// nullptr if the source does not have a parameter list.
96709674
const ParamDecl *getParameterAt(const DeclContext *source, unsigned index);
96719675

9676+
class ABIRole {
9677+
public:
9678+
enum Value : uint8_t {
9679+
Neither = 0,
9680+
ProvidesABI = 1 << 0,
9681+
ProvidesAPI = 1 << 1,
9682+
Either = ProvidesABI | ProvidesAPI,
9683+
};
9684+
9685+
Value value;
9686+
9687+
ABIRole(Value value)
9688+
: value(value)
9689+
{ }
9690+
9691+
ABIRole()
9692+
: ABIRole(Neither)
9693+
{ }
9694+
9695+
explicit ABIRole(NLOptions opts);
9696+
9697+
template<typename FlagType>
9698+
explicit ABIRole(OptionSet<FlagType> flags)
9699+
: value(flags.contains(FlagType::ABIProviding) ? ProvidesABI : ProvidesAPI)
9700+
{ }
9701+
9702+
inline ABIRole operator|(ABIRole rhs) const {
9703+
return ABIRole(ABIRole::Value(value | rhs.value));
9704+
}
9705+
inline ABIRole &operator|=(ABIRole rhs) {
9706+
value = ABIRole::Value(value | rhs.value);
9707+
return *this;
9708+
}
9709+
inline ABIRole operator&(ABIRole rhs) const {
9710+
return ABIRole(ABIRole::Value(value & rhs.value));
9711+
}
9712+
inline ABIRole &operator&=(ABIRole rhs) {
9713+
value = ABIRole::Value(value & rhs.value);
9714+
return *this;
9715+
}
9716+
inline ABIRole operator~() const {
9717+
return ABIRole(ABIRole::Value(~value));
9718+
}
9719+
9720+
operator bool() const {
9721+
return value != Neither;
9722+
}
9723+
};
9724+
9725+
namespace abi_role_detail {
9726+
9727+
using Storage = llvm::PointerIntPair<Decl *, 2, ABIRole::Value>;
9728+
Storage computeStorage(Decl *decl);
9729+
9730+
}
9731+
9732+
/// Specifies the \c ABIAttr -related behavior of this declaration
9733+
/// and provides access to its counterpart.
9734+
///
9735+
/// A given declaration may provide the API, the ABI, or both. If it provides
9736+
/// API, the counterpart is the matching ABI-providing decl; if it provides
9737+
/// ABI, the countepart is the matching API-providing decl. A declaration
9738+
/// which provides both API and ABI is its own counterpart.
9739+
///
9740+
/// If the counterpart is \c nullptr , this indicates a fundamental mismatch
9741+
/// between decl and counterpart. Sometimes this mismatch is a difference in
9742+
/// decl kind; in these cases, \c getCounterpartUnchecked() will return the
9743+
/// incorrect counterpart.
9744+
template<typename SpecificDecl>
9745+
class ABIRoleInfo {
9746+
friend abi_role_detail::Storage abi_role_detail::computeStorage(Decl *);
9747+
9748+
abi_role_detail::Storage counterpartAndFlags;
9749+
9750+
ABIRoleInfo(abi_role_detail::Storage storage)
9751+
: counterpartAndFlags(storage)
9752+
{ }
9753+
9754+
public:
9755+
explicit ABIRoleInfo(const SpecificDecl *decl)
9756+
: ABIRoleInfo(abi_role_detail::computeStorage(const_cast<SpecificDecl *>(decl)))
9757+
{ }
9758+
9759+
Decl *getCounterpartUnchecked() const {
9760+
return counterpartAndFlags.getPointer();
9761+
}
9762+
9763+
SpecificDecl *getCounterpart() const {
9764+
return dyn_cast_or_null<SpecificDecl>(getCounterpartUnchecked());
9765+
}
9766+
9767+
ABIRole getRole() const {
9768+
return ABIRole(ABIRole::Value(counterpartAndFlags.getInt()));
9769+
}
9770+
9771+
bool matches(ABIRole desiredRole) const {
9772+
return getRole() & desiredRole;
9773+
}
9774+
9775+
template<typename Options>
9776+
bool matchesOptions(Options opts) const {
9777+
return matches(ABIRole(opts));
9778+
}
9779+
9780+
bool providesABI() const {
9781+
return matches(ABIRole::ProvidesABI);
9782+
}
9783+
9784+
bool providesAPI() const {
9785+
return matches(ABIRole::ProvidesAPI);
9786+
}
9787+
9788+
bool hasABIAttr() const {
9789+
return !providesABI();
9790+
}
9791+
};
9792+
9793+
template<typename SpecificDecl>
9794+
ABIRoleInfo(const SpecificDecl *decl) -> ABIRoleInfo<SpecificDecl>;
9795+
96729796
StringRef getAccessorNameForDiagnostic(AccessorDecl *accessor, bool article);
96739797
StringRef getAccessorNameForDiagnostic(AccessorKind accessorKind, bool article);
96749798

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
};
@@ -555,6 +558,9 @@ template <typename Result>
555558
void filterForDiscriminator(SmallVectorImpl<Result> &results,
556559
DebuggerClient *debugClient);
557560

561+
/// \returns Whether the given source location is inside an \@abi attribute.
562+
bool isInABIAttr(SourceFile *sourceFile, SourceLoc loc);
563+
558564
/// \returns The set of macro declarations with the given name that
559565
/// fulfill any of the given macro roles.
560566
SmallVector<MacroDecl *, 1> lookupMacros(DeclContext *dc,
@@ -749,8 +755,16 @@ class ASTScope : public ASTAllocated<ASTScope> {
749755
/// local declarations inside the innermost syntactic scope only.
750756
static void lookupLocalDecls(SourceFile *, DeclName, SourceLoc,
751757
bool stopAfterInnermostBraceStmt,
758+
ABIRole roleFilter,
752759
SmallVectorImpl<ValueDecl *> &);
753760

761+
static void lookupLocalDecls(SourceFile *sf, DeclName name, SourceLoc loc,
762+
bool stopAfterInnermostBraceStmt,
763+
SmallVectorImpl<ValueDecl *> &results) {
764+
lookupLocalDecls(sf, name, loc, stopAfterInnermostBraceStmt,
765+
ABIRole::ProvidesAPI, results);
766+
}
767+
754768
/// Returns the result if there is exactly one, nullptr otherwise.
755769
static ValueDecl *lookupSingleLocalDecl(SourceFile *, DeclName, SourceLoc);
756770

@@ -795,6 +809,18 @@ class ASTScope : public ASTAllocated<ASTScope> {
795809
SourceFile *sourceFile, SourceLoc loc,
796810
llvm::function_ref<bool(PotentialMacro macro)> consume);
797811

812+
/// Look up the scope tree for the nearest enclosing ABI attribute at
813+
/// the given source location.
814+
///
815+
/// \param sourceFile The source file containing the given location.
816+
/// \param loc The source location to start lookup from.
817+
/// \param consume A function that is called when an ABI attribute
818+
/// scope is found. If \c consume returns \c true, lookup
819+
/// will stop. If \c consume returns \c false, lookup will
820+
/// continue up the scope tree.
821+
static ABIAttr *lookupEnclosingABIAttributeScope(
822+
SourceFile *sourceFile, SourceLoc loc);
823+
798824
/// Look up the scope tree for the nearest point at which an error thrown from
799825
/// this location can be caught or rethrown.
800826
///

lib/AST/ASTDumper.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,7 @@ namespace {
907907
TerminalColor Color = DeclColor) {
908908
printFieldQuotedRaw([&](raw_ostream &OS) { declRef.dump(OS); }, label,
909909
Color);
910+
printFlag(!ABIRoleInfo(declRef.getDecl()).providesAPI(), "abi_only_decl");
910911
}
911912

912913
void printThrowDest(ThrownErrorDestination throws, bool wantNothrow) {
@@ -1102,6 +1103,8 @@ namespace {
11021103
printFieldQuoted(implAttr->CategoryName.str(), label);
11031104
}
11041105

1106+
printFlag(!ABIRoleInfo(D).providesAPI(), "abi_only");
1107+
11051108
printSourceRange(D->getSourceRange(), &D->getASTContext());
11061109
printFlag(D->TrailingSemiLoc.isValid(), "trailing_semi",
11071110
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)