Skip to content

Commit 3baba0b

Browse files
committed
Type check @abi decls (sans attrs)
This commit compares the decl inside the `@abi` attribute to the decl it’s attached to, diagnosing ABI-incompatible differences. It does not yet cover attributes, which are a large undertaking.
1 parent 5bb6245 commit 3baba0b

File tree

9 files changed

+1760
-162
lines changed

9 files changed

+1760
-162
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,10 @@ namespace swift {
702702
/// Flush the active diagnostic to the diagnostic output engine.
703703
void flush();
704704

705+
/// Returns the \c SourceManager associated with \c SourceLoc s for this
706+
/// diagnostic.
707+
SourceManager &getSourceManager();
708+
705709
/// Prevent the diagnostic from behaving more severely than \p limit. For
706710
/// instance, if \c DiagnosticBehavior::Warning is passed, an error will be
707711
/// emitted as a warning, but a note will still be emitted as a note.
@@ -1561,6 +1565,10 @@ namespace swift {
15611565
}
15621566
};
15631567

1568+
inline SourceManager &InFlightDiagnostic::getSourceManager() {
1569+
return Engine->SourceMgr;
1570+
}
1571+
15641572
/// Remember details about the state of a diagnostic engine and restore them
15651573
/// when the object is destroyed.
15661574
///

include/swift/AST/DiagnosticsSema.def

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8351,16 +8351,16 @@ ERROR(attr_abi_mismatched_kind,none,
83518351

83528352
ERROR(attr_abi_mismatched_arity,none,
83538353
"cannot give %kind0 the ABI of a %kindonly0 with a different number of "
8354-
"low-level parameters",
8355-
(ValueDecl *))
8354+
"%select{|generic }1parameters",
8355+
(Decl *, /*genericParams=*/bool))
83568356

83578357
ERROR(attr_abi_mismatched_throws,none,
83588358
"cannot give %0 the ABI of a %kindonly0 which %select{cannot|can}1 throw",
8359-
(ValueDecl *, /*abiCanThrow=*/bool))
8359+
(Decl *, /*abiCanThrow=*/bool))
83608360

83618361
ERROR(attr_abi_mismatched_async,none,
83628362
"cannot give %0 the ABI of %select{a non-async|an async}1 %kindonly0",
8363-
(ValueDecl *, /*abiIsAsync=*/bool))
8363+
(Decl *, /*abiIsAsync=*/bool))
83648364

83658365
ERROR(attr_abi_mismatched_pbd_size,none,
83668366
"cannot give pattern binding the ABI of a binding with "
@@ -8369,13 +8369,65 @@ ERROR(attr_abi_mismatched_pbd_size,none,
83698369

83708370
ERROR(attr_abi_mismatched_var,none,
83718371
"no match for %select{%kind0 in the ABI|ABI %kind0}1",
8372-
(ValueDecl *, /*isABI=*/bool))
8372+
(Decl *, /*isABI=*/bool))
83738373

83748374
ERROR(attr_abi_incompatible_with_silgen_name,none,
83758375
"cannot use '@_silgen_name' and '@abi' on the same %0 because they serve "
83768376
"the same purpose",
83778377
(DescriptiveDeclKind))
83788378

8379+
ERROR(attr_abi_mismatched_type,none,
8380+
"type %0 in '@abi' should match %1",
8381+
(Type, Type))
8382+
NOTE(attr_abi_should_match_type_here,none,
8383+
"should match type here", ())
8384+
8385+
ERROR(attr_abi_mismatched_generic_signature,none,
8386+
"generic signature '%0' in '@abi' is not compatible with '%1'",
8387+
(StringRef, StringRef))
8388+
ERROR(attr_abi_missing_generic_signature,none,
8389+
"declaration in '@abi' should have generic signature compatible with "
8390+
"'%0'",
8391+
(StringRef))
8392+
ERROR(attr_abi_extra_generic_signature,none,
8393+
"declaration in '@abi' should not have generic signature because %0 "
8394+
"is not generic",
8395+
(Decl *))
8396+
8397+
ERROR(attr_abi_mismatched_param_modifier,none,
8398+
"%select{default |}0%3 %select{attribute|modifier}2 "
8399+
"%select{|'%0' }0in '@abi' is not compatible with %select{default|'%1'}1",
8400+
(StringRef, StringRef, /*isModifier=*/bool, DescriptiveDeclKind))
8401+
ERROR(attr_abi_no_default_arguments,none,
8402+
"%kind0 in '@abi' should not have a default argument; it does not "
8403+
"affect the parameter's ABI",
8404+
(Decl *))
8405+
8406+
// These macros insert 'final', 'non-final', or nothing depending on both the
8407+
// current decl and its counterpart, such that 'non-final' is used if the
8408+
// counterpart would be described as 'final' or 'static'. They must be kept in
8409+
// sync with `StaticnessAndFinality`.
8410+
#define NONFINAL_OR_NOTHING(COUNTERPART) \
8411+
"%select{||non-final |non-final |non-final |%error}" #COUNTERPART
8412+
#define FINAL_OR_NONFINAL_OR_NOTHING(CURRENT, COUNTERPART, FINAL_OK) \
8413+
"%select{|%select{" NONFINAL_OR_NOTHING(COUNTERPART) \
8414+
"|" NONFINAL_OR_NOTHING(COUNTERPART) \
8415+
"|final |final ||%error}" #CURRENT "}" #FINAL_OK
8416+
8417+
ERROR(attr_abi_static_final_mismatch,none,
8418+
FINAL_OR_NONFINAL_OR_NOTHING(0, 2, 4) "%kind1 in '@abi' should be "
8419+
FINAL_OR_NONFINAL_OR_NOTHING(2, 0, 4) "%kindonly3 to ensure ABI "
8420+
"compatibility",
8421+
(uint8_t, Decl *, uint8_t, Decl *, /*isClass=*/bool))
8422+
8423+
#undef NONFINAL_OR_NOTHING
8424+
#undef FINAL_OR_NONFINAL_OR_NOTHING
8425+
8426+
ERROR(attr_abi_failable_mismatch,none,
8427+
"cannot give %select{non-failable|failable}1 %kind0 the ABI of a "
8428+
"%select{non-failable|failable}2 %kindonly0",
8429+
(Decl *, bool, bool))
8430+
83798431
//===----------------------------------------------------------------------===//
83808432
// MARK: Isolated conformances
83818433
//===----------------------------------------------------------------------===//

lib/Sema/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ add_swift_host_library(swiftSema STATIC
5050
TypeOfReference.cpp
5151
TypeCheckAccess.cpp
5252
TypeCheckAttr.cpp
53+
TypeCheckAttrABI.cpp
5354
TypeCheckAvailability.cpp
5455
TypeCheckBitwise.cpp
5556
TypeCheckCaptures.cpp

lib/Sema/TypeCheckAttr.cpp

Lines changed: 2 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -195,68 +195,10 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
195195
IGNORED_ATTR(Unsafe)
196196
#undef IGNORED_ATTR
197197

198-
private:
199-
static unsigned getABIArity(AbstractFunctionDecl *afd) {
200-
unsigned arity = afd->getParameters()->size();
201-
arity += afd->getGenericSignature().getGenericParams().size();
202-
if (afd->hasImplicitSelfDecl())
203-
arity += 1;
204-
return arity;
205-
}
206-
207-
void checkABIAttrPBD(PatternBindingDecl *APBD, VarDecl *VD) {
208-
auto PBD = VD->getParentPatternBinding();
209-
210-
// To make sure we only diagnose this stuff once, check that VD is the first
211-
// anchoring variable in the PBD.
212-
bool isFirstAnchor = false;
213-
for (auto i : range(PBD->getNumPatternEntries())) {
214-
auto anchorVD = PBD->getAnchoringVarDecl(i);
215-
if (anchorVD) {
216-
isFirstAnchor = (anchorVD == VD);
217-
break;
218-
}
219-
}
220-
221-
if (!isFirstAnchor)
222-
return;
223-
224-
// Check that the PBDs have the same number of patterns.
225-
if (PBD->getNumPatternEntries() < APBD->getNumPatternEntries()) {
226-
diagnose(APBD->getPattern(PBD->getNumPatternEntries())->getLoc(),
227-
diag::attr_abi_mismatched_pbd_size, /*abiHasExtra=*/false);
228-
return;
229-
}
230-
if (PBD->getNumPatternEntries() > APBD->getNumPatternEntries()) {
231-
diagnose(PBD->getPattern(APBD->getNumPatternEntries())->getLoc(),
232-
diag::attr_abi_mismatched_pbd_size, /*abiHasExtra=*/true);
233-
return;
234-
}
235-
236-
// Check that each pattern has the same number of variables.
237-
for (auto i : range(PBD->getNumPatternEntries())) {
238-
SmallVector<VarDecl *, 8> VDs;
239-
SmallVector<VarDecl *, 8> AVDs;
240-
241-
PBD->getPattern(i)->collectVariables(VDs);
242-
APBD->getPattern(i)->collectVariables(AVDs);
243-
244-
if (VDs.size() < AVDs.size()) {
245-
for (auto AVD : drop_begin(AVDs, VDs.size())) {
246-
AVD->diagnose(diag::attr_abi_mismatched_var,
247-
AVD, /*isABI=*/true);
248-
}
249-
}
250-
else if (VDs.size() > AVDs.size()) {
251-
for (auto VD : drop_begin(VDs, AVDs.size())) {
252-
VD->diagnose(diag::attr_abi_mismatched_var,
253-
VD, /*isABI=*/false);
254-
}
255-
}
256-
}
198+
void visitABIAttr(ABIAttr *attr) {
199+
TypeChecker::checkDeclABIAttribute(D, attr);
257200
}
258201

259-
public:
260202
void visitExecutionAttr(ExecutionAttr *attr) {
261203
auto *const decl = cast<ValueDecl>(D);
262204

@@ -300,81 +242,6 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
300242
}
301243
}
302244

303-
void visitABIAttr(ABIAttr *attr) {
304-
Decl *AD = attr->abiDecl;
305-
if (isa<VarDecl>(D) && isa<PatternBindingDecl>(AD)) {
306-
auto VD = cast<VarDecl>(D);
307-
auto APBD = cast<PatternBindingDecl>(AD);
308-
309-
// Diagnose dissimilar PBD structures.
310-
checkABIAttrPBD(APBD, VD);
311-
312-
// Do the rest of this checking on the corresponding VarDecl, not the
313-
// PBD that's actually in the attribute. Note that `AD` will become null
314-
// if they're too dissimilar to match up.
315-
AD = APBD->getVarAtSimilarStructuralPosition(VD);
316-
}
317-
// TODO: EnumElementDecl?
318-
319-
if (!AD)
320-
return;
321-
322-
// Check the ABI decl and bail if there was a problem with it.
323-
TypeChecker::typeCheckDecl(AD);
324-
if (AD->isInvalid())
325-
return;
326-
327-
// Do the declarations have the same kind, broadly speaking? Many kinds have
328-
// special mangling behavior (e.g. inits vs normal funcs) that make it
329-
// unrealistic to treat one kind as though it were another.
330-
if (D->getKind() != AD->getKind()) {
331-
// FIXME: DescriptiveDeclKind is overly specific; we really just want to
332-
// say that e.g. a `func` can't have the ABI of a `var`.
333-
diagnoseAndRemoveAttr(attr, diag::attr_abi_mismatched_kind,
334-
D, AD->getDescriptiveKind());
335-
return;
336-
}
337-
338-
if (isa<AbstractFunctionDecl>(D)) {
339-
auto AFD = cast<AbstractFunctionDecl>(D);
340-
auto AAFD = cast<AbstractFunctionDecl>(AD);
341-
342-
// FIXME: How much should we diagnose in IRGen for more precise ABI info?
343-
344-
// Do the declarations have roughly the same number of parameters? We'll
345-
// allow some fuzziness for what these parameters *are*, since there isn't
346-
// always an ABI difference between e.g. a free function with N parameters
347-
// and an instance method with N-1 parameters (plus an implicit `self`).
348-
if (getABIArity(AFD) != getABIArity(AAFD)) {
349-
diagnoseAndRemoveAttr(attr, diag::attr_abi_mismatched_arity,
350-
AFD);
351-
}
352-
353-
// Do the declarations match in throwing behavior? We don't care about
354-
// `throws` vs. `rethrows` here, just whether callers will account for an
355-
// error return.
356-
// FIXME: Typed throws?
357-
if (AFD->hasThrows() != AAFD->hasThrows()) {
358-
diagnoseAndRemoveAttr(attr, diag::attr_abi_mismatched_throws,
359-
AFD, /*abiCanThrow=*/AAFD->hasThrows());
360-
}
361-
362-
// Do the declarations match in async-ness?
363-
if (AFD->hasAsync() != AAFD->hasAsync()) {
364-
diagnoseAndRemoveAttr(attr, diag::attr_abi_mismatched_async,
365-
AFD, /*abiHasAsync=*/AAFD->hasAsync());
366-
}
367-
}
368-
369-
// TODO: Diagnose if Protocol::isMarkerProtocol() - contradiction in terms
370-
// (and mangler can't handle invertible protocols with @abi)
371-
372-
// TODO: Validate more
373-
// FIXME: The list of properties that have to match is practically endless
374-
// and will grow as new features are added to the compiler. We might want to
375-
// write an AttributeVisitor just to help us catch omissions over time.
376-
}
377-
378245
void visitAlignmentAttr(AlignmentAttr *attr) {
379246
// Alignment must be a power of two.
380247
auto value = attr->getValue();

0 commit comments

Comments
 (0)