Skip to content

Commit a86b30d

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 cb9b2bb commit a86b30d

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

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

33343334
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;
@@ -4286,6 +4287,9 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
42864287
IncludeAttrImplements = 1 << 0,
42874288
/// Whether to exclude members of macro expansions.
42884289
ExcludeMacroExpansions = 1 << 1,
4290+
/// If @abi attributes are present, return the decls representing the ABI,
4291+
/// not the API.
4292+
ABIProviding = 1 << 2,
42894293
};
42904294

42914295
/// Find all of the declarations with the given name within this nominal type
@@ -9688,6 +9692,126 @@ const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index);
96889692
/// nullptr if the source does not have a parameter list.
96899693
const ParamDecl *getParameterAt(const DeclContext *source, unsigned index);
96909694

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

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)