Skip to content

Commit c91cf69

Browse files
committed
Add some basic validation of vars and funcs
Check for: • Matching decl kinds • Matching PBD shapes (does every VarDecl on both sides have a counterpart?) • Matching function effects • Matching function arity (roughly)
1 parent 08e2a4d commit c91cf69

File tree

3 files changed

+169
-24
lines changed

3 files changed

+169
-24
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8135,5 +8135,35 @@ ERROR(availability_value_generic_type_only_version_newer, none,
81358135
ERROR(invalid_value_for_type_same_type,none,
81368136
"cannot constrain type parameter %0 to be integer %1", (Type, Type))
81378137

8138+
//===----------------------------------------------------------------------===//
8139+
// MARK: @abi Attribute
8140+
//===----------------------------------------------------------------------===//
8141+
8142+
ERROR(attr_abi_mismatched_kind,none,
8143+
"cannot give %kind0 the ABI of a %1",
8144+
(Decl *, DescriptiveDeclKind))
8145+
8146+
ERROR(attr_abi_mismatched_arity,none,
8147+
"cannot give %kind0 the ABI of a %kindonly0 with a different number of "
8148+
"low-level parameters",
8149+
(ValueDecl *))
8150+
8151+
ERROR(attr_abi_mismatched_throws,none,
8152+
"cannot give %0 the ABI of a %kindonly0 which %select{cannot|can}1 throw",
8153+
(ValueDecl *, /*abiCanThrow=*/bool))
8154+
8155+
ERROR(attr_abi_mismatched_async,none,
8156+
"cannot give %0 the ABI of %select{a non-async|an async}1 %kindonly0",
8157+
(ValueDecl *, /*abiIsAsync=*/bool))
8158+
8159+
ERROR(attr_abi_mismatched_pbd_size,none,
8160+
"cannot give pattern binding the ABI of a binding with "
8161+
"%select{more|fewer}0 patterns",
8162+
(/*abiHasExtra=*/bool))
8163+
8164+
ERROR(attr_abi_mismatched_var,none,
8165+
"no match for %select{%kind0 in the ABI|ABI %kind0}1",
8166+
(ValueDecl *, /*isABI=*/bool))
8167+
81388168
#define UNDEFINE_DIAGNOSTIC_MACROS
81398169
#include "DefineDiagnosticMacros.h"

lib/Sema/TypeCheckAttr.cpp

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,81 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
190190
IGNORED_ATTR(PreInverseGenerics)
191191
#undef IGNORED_ATTR
192192

193+
private:
194+
static unsigned getABIArity(AbstractFunctionDecl *afd) {
195+
unsigned arity = afd->getParameters()->size();
196+
arity += afd->getGenericSignature().getGenericParams().size();
197+
if (afd->hasImplicitSelfDecl())
198+
arity += 1;
199+
return arity;
200+
}
201+
202+
void checkABIAttrPBD(PatternBindingDecl *APBD, VarDecl *VD) {
203+
auto PBD = VD->getParentPatternBinding();
204+
205+
// To make sure we only diagnose this stuff once, check that VD is the first
206+
// anchoring variable in the PBD.
207+
bool isFirstAnchor = false;
208+
for (auto i : range(PBD->getNumPatternEntries())) {
209+
auto anchorVD = PBD->getAnchoringVarDecl(i);
210+
if (anchorVD) {
211+
isFirstAnchor = (anchorVD == VD);
212+
break;
213+
}
214+
}
215+
216+
if (!isFirstAnchor)
217+
return;
218+
219+
// Check that the PBDs have the same number of patterns.
220+
if (PBD->getNumPatternEntries() < APBD->getNumPatternEntries()) {
221+
diagnose(APBD->getPattern(PBD->getNumPatternEntries())->getLoc(),
222+
diag::attr_abi_mismatched_pbd_size, /*abiHasExtra=*/false);
223+
return;
224+
}
225+
if (PBD->getNumPatternEntries() > APBD->getNumPatternEntries()) {
226+
diagnose(PBD->getPattern(APBD->getNumPatternEntries())->getLoc(),
227+
diag::attr_abi_mismatched_pbd_size, /*abiHasExtra=*/true);
228+
return;
229+
}
230+
231+
// Check that each pattern has the same number of variables.
232+
for (auto i : range(PBD->getNumPatternEntries())) {
233+
SmallVector<VarDecl *, 8> VDs;
234+
SmallVector<VarDecl *, 8> AVDs;
235+
236+
PBD->getPattern(i)->collectVariables(VDs);
237+
APBD->getPattern(i)->collectVariables(AVDs);
238+
239+
if (VDs.size() < AVDs.size()) {
240+
for (auto AVD : drop_begin(AVDs, VDs.size())) {
241+
AVD->diagnose(diag::attr_abi_mismatched_var,
242+
AVD, /*isABI=*/true);
243+
}
244+
}
245+
else if (VDs.size() > AVDs.size()) {
246+
for (auto VD : drop_begin(VDs, AVDs.size())) {
247+
VD->diagnose(diag::attr_abi_mismatched_var,
248+
VD, /*isABI=*/false);
249+
}
250+
}
251+
}
252+
}
253+
254+
public:
193255
void visitABIAttr(ABIAttr *attr) {
194256
Decl *AD = attr->abiDecl;
195257
if (isa<VarDecl>(D) && isa<PatternBindingDecl>(AD)) {
196-
AD = cast<PatternBindingDecl>(AD)
197-
->getVarAtSimilarStructuralPosition(cast<VarDecl>(D));
258+
auto VD = cast<VarDecl>(D);
259+
auto APBD = cast<PatternBindingDecl>(AD);
260+
261+
// Diagnose dissimilar PBD structures.
262+
checkABIAttrPBD(APBD, VD);
263+
264+
// Do the rest of this checking on the corresponding VarDecl, not the
265+
// PBD that's actually in the attribute. Note that `AD` will become null
266+
// if they're too dissimilar to match up.
267+
AD = APBD->getVarAtSimilarStructuralPosition(VD);
198268
}
199269
// TODO: EnumElementDecl?
200270

@@ -206,7 +276,52 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
206276
if (AD->isInvalid())
207277
return;
208278

279+
// Do the declarations have the same kind, broadly speaking? Many kinds have
280+
// special mangling behavior (e.g. inits vs normal funcs) that make it
281+
// unrealistic to treat one kind as though it were another.
282+
if (D->getKind() != AD->getKind()) {
283+
// FIXME: DescriptiveDeclKind is overly specific; we really just want to
284+
// say that e.g. a `func` can't have the ABI of a `var`.
285+
diagnoseAndRemoveAttr(attr, diag::attr_abi_mismatched_kind,
286+
D, AD->getDescriptiveKind());
287+
return;
288+
}
289+
290+
if (isa<AbstractFunctionDecl>(D)) {
291+
auto AFD = cast<AbstractFunctionDecl>(D);
292+
auto AAFD = cast<AbstractFunctionDecl>(AD);
293+
294+
// FIXME: How much should we diagnose in IRGen for more precise ABI info?
295+
296+
// Do the declarations have roughly the same number of parameters? We'll
297+
// allow some fuzziness for what these parameters *are*, since there isn't
298+
// always an ABI difference between e.g. a free function with N parameters
299+
// and an instance method with N-1 parameters (plus an implicit `self`).
300+
if (getABIArity(AFD) != getABIArity(AAFD)) {
301+
diagnoseAndRemoveAttr(attr, diag::attr_abi_mismatched_arity,
302+
AFD);
303+
}
304+
305+
// Do the declarations match in throwing behavior? We don't care about
306+
// `throws` vs. `rethrows` here, just whether callers will account for an
307+
// error return.
308+
// FIXME: Typed throws?
309+
if (AFD->hasThrows() != AAFD->hasThrows()) {
310+
diagnoseAndRemoveAttr(attr, diag::attr_abi_mismatched_throws,
311+
AFD, /*abiCanThrow=*/AAFD->hasThrows());
312+
}
313+
314+
// Do the declarations match in async-ness?
315+
if (AFD->hasAsync() != AAFD->hasAsync()) {
316+
diagnoseAndRemoveAttr(attr, diag::attr_abi_mismatched_async,
317+
AFD, /*abiHasAsync=*/AAFD->hasAsync());
318+
}
319+
}
320+
209321
// TODO: Validate more
322+
// FIXME: The list of properties that have to match is practically endless
323+
// and will grow as new features are added to the compiler. We might want to
324+
// write an AttributeVisitor just to help us catch omissions over time.
210325
}
211326

212327
void visitAlignmentAttr(AlignmentAttr *attr) {

test/attr/attr_abi.swift

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ func funcForFunc() {}
1313
@abi(var varForVar_abi: Int)
1414
var varForVar: Int = 0
1515

16-
@abi(func funcForVar_abi())
16+
@abi(func funcForVar_abi()) // expected-error {{cannot give var 'funcForVar' the ABI of a global function}}
1717
var funcForVar: Int = 0
1818

19-
@abi(var varForFunc_abi: Int)
19+
@abi(var varForFunc_abi: Int) // expected-error {{cannot give global function 'varForFunc()' the ABI of a pattern binding}}
2020
func varForFunc() {}
2121

2222
//
@@ -26,52 +26,52 @@ func varForFunc() {}
2626
@abi(func param00_generic00() -> Int)
2727
func param00_generic00() -> Int { fatalError() }
2828

29-
@abi(func param10_generic00(_: Int) -> Int)
29+
@abi(func param10_generic00(_: Int) -> Int) // expected-error {{cannot give global function 'param10_generic00()' the ABI of a global function with a different number of low-level parameters}}
3030
func param10_generic00() -> Int { fatalError() }
3131

32-
@abi(func param01_generic00() -> Int)
32+
@abi(func param01_generic00() -> Int) // expected-error {{cannot give global function 'param01_generic00' the ABI of a global function with a different number of low-level parameters}}
3333
func param01_generic00(_: Int) -> Int { fatalError() }
3434

3535
@abi(func param11_generic00(_: Int) -> Int)
3636
func param11_generic00(_: Int) -> Int { fatalError() }
3737

3838

3939

40-
@abi(func param00_generic10<T>() -> T)
40+
@abi(func param00_generic10<T>() -> T) // expected-error {{cannot give global function 'param00_generic10()' the ABI of a global function with a different number of low-level parameters}}
4141
func param00_generic10() -> Int { fatalError() }
4242

43-
@abi(func param10_generic10<T>(_: Int) -> T)
43+
@abi(func param10_generic10<T>(_: Int) -> T) // expected-error {{cannot give global function 'param10_generic10()' the ABI of a global function with a different number of low-level parameters}}
4444
func param10_generic10() -> Int { fatalError() }
4545

4646
@abi(func param01_generic10<T>() -> T)
4747
func param01_generic10(_: Int) -> Int { fatalError() }
4848

49-
@abi(func param11_generic10<T>(_: Int) -> T)
49+
@abi(func param11_generic10<T>(_: Int) -> T) // expected-error {{cannot give global function 'param11_generic10' the ABI of a global function with a different number of low-level parameters}}
5050
func param11_generic10(_: Int) -> Int { fatalError() }
5151

5252

5353

54-
@abi(func param00_generic01() -> Int)
54+
@abi(func param00_generic01() -> Int) // expected-error {{cannot give global function 'param00_generic01()' the ABI of a global function with a different number of low-level parameters}}
5555
func param00_generic01<T>() -> T { fatalError() }
5656

5757
@abi(func param10_generic01(_: Int) -> Int)
5858
func param10_generic01<T>() -> T { fatalError() }
5959

60-
@abi(func param01_generic01() -> Int)
60+
@abi(func param01_generic01() -> Int) // expected-error {{cannot give global function 'param01_generic01' the ABI of a global function with a different number of low-level parameters}}
6161
func param01_generic01<T>(_: Int) -> T { fatalError() }
6262

63-
@abi(func param11_generic01(_: Int) -> Int)
63+
@abi(func param11_generic01(_: Int) -> Int) // expected-error {{cannot give global function 'param11_generic01' the ABI of a global function with a different number of low-level parameters}}
6464
func param11_generic01<T>(_: Int) -> T { fatalError() }
6565

6666

6767

6868
@abi(func param00_generic11<T>() -> T)
6969
func param00_generic11<T>() -> T { fatalError() }
7070

71-
@abi(func param10_generic11<T>(_: Int) -> T)
71+
@abi(func param10_generic11<T>(_: Int) -> T) // expected-error {{cannot give global function 'param10_generic11()' the ABI of a global function with a different number of low-level parameters}}
7272
func param10_generic11<T>() -> T { fatalError() }
7373

74-
@abi(func param01_generic11<T>() -> T)
74+
@abi(func param01_generic11<T>() -> T) // expected-error {{cannot give global function 'param01_generic11' the ABI of a global function with a different number of low-level parameters}}
7575
func param01_generic11<T>(_: Int) -> T { fatalError() }
7676

7777
@abi(func param11_generic11<T>(_: Int) -> T)
@@ -84,13 +84,13 @@ func param11_generic11<T>(_: Int) -> T { fatalError() }
8484
@abi(func throws00(_: () throws -> Void))
8585
func throws00(_: () throws -> Void) {}
8686

87-
@abi(func throws10(_: () throws -> Void) throws)
87+
@abi(func throws10(_: () throws -> Void) throws) // expected-error {{cannot give 'throws10' the ABI of a global function which can throw}}
8888
func throws10(_: () throws -> Void) {}
8989

90-
@abi(func throws20(_: () throws -> Void) rethrows)
90+
@abi(func throws20(_: () throws -> Void) rethrows) // expected-error {{cannot give 'throws20' the ABI of a global function which can throw}}
9191
func throws20(_: () throws -> Void) {}
9292

93-
@abi(func throws01(_: () throws -> Void))
93+
@abi(func throws01(_: () throws -> Void)) // expected-error {{cannot give 'throws01' the ABI of a global function which cannot throw}}
9494
func throws01(_: () throws -> Void) throws {}
9595

9696
@abi(func throws11(_: () throws -> Void) throws)
@@ -99,7 +99,7 @@ func throws11(_: () throws -> Void) throws {}
9999
@abi(func throws21(_: () throws -> Void) rethrows)
100100
func throws21(_: () throws -> Void) throws {}
101101

102-
@abi(func throws02(_: () throws -> Void))
102+
@abi(func throws02(_: () throws -> Void)) // expected-error {{cannot give 'throws02' the ABI of a global function which cannot throw}}
103103
func throws02(_: () throws -> Void) rethrows {}
104104

105105
@abi(func throws12(_: () throws -> Void) throws)
@@ -115,10 +115,10 @@ func throws22(_: () throws -> Void) rethrows {}
115115
@abi(func async00())
116116
func async00() {}
117117
118-
@abi(func async10() async)
118+
@abi(func async10() async) // expected-error {{cannot give 'async10()' the ABI of an async global function}}
119119
func async10() {}
120120
121-
@abi(func async01())
121+
@abi(func async01()) // expected-error {{cannot give 'async01()' the ABI of a non-async global function}}
122122
func async01() async {}
123123
124124
@abi(func async11() async)
@@ -128,17 +128,17 @@ func async11() async {}
128128
// PBD shape checking
129129
//
130130
131-
@abi(var x1, y1: Int)
131+
@abi(var x1, y1: Int) // expected-error {{cannot give pattern binding the ABI of a binding with more patterns}}
132132
var x1: Int = 0
133133

134134
@abi(var x2: Int)
135-
var x2 = 0, y2: Int = 0
135+
var x2 = 0, y2: Int = 0 // expected-error {{cannot give pattern binding the ABI of a binding with fewer patterns}}
136136
137-
@abi(var (x3, y3): (Int, Int), (a3, b3): (Int, Int))
137+
@abi(var (x3, y3): (Int, Int), (a3, b3): (Int, Int)) // expected-error {{no match for ABI var 'b3'}}
138138
var (x3, y3): (Int, Int) = (0, 0), a3: Int = 0
139139
140140
@abi(var (x4, y4): (Int, Int), a4: Int)
141-
var (x4, y4): (Int, Int) = (0, 0), (a4, b4): (Int, Int) = (0, 0)
141+
var (x4, y4): (Int, Int) = (0, 0), (a4, b4): (Int, Int) = (0, 0) // expected-error {{no match for var 'b4' in the ABI}}
142142
143143
//
144144
// Conflict diagnostics

0 commit comments

Comments
 (0)