Skip to content

Commit 59f83be

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 1e94cbc commit 59f83be

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
@@ -8111,5 +8111,35 @@ ERROR(availability_value_generic_type_only_version_newer, none,
81118111
ERROR(invalid_value_for_type_same_type,none,
81128112
"cannot constrain type parameter %0 to be integer %1", (Type, Type))
81138113

8114+
//===----------------------------------------------------------------------===//
8115+
// MARK: @abi Attribute
8116+
//===----------------------------------------------------------------------===//
8117+
8118+
ERROR(attr_abi_mismatched_kind,none,
8119+
"cannot give %kind0 the ABI of a %1",
8120+
(Decl *, DescriptiveDeclKind))
8121+
8122+
ERROR(attr_abi_mismatched_arity,none,
8123+
"cannot give %kind0 the ABI of a %kindonly0 with a different number of "
8124+
"low-level parameters",
8125+
(ValueDecl *))
8126+
8127+
ERROR(attr_abi_mismatched_throws,none,
8128+
"cannot give %0 the ABI of a %kindonly0 which %select{cannot|can}1 throw",
8129+
(ValueDecl *, /*abiCanThrow=*/bool))
8130+
8131+
ERROR(attr_abi_mismatched_async,none,
8132+
"cannot give %0 the ABI of %select{a non-async|an async}1 %kindonly0",
8133+
(ValueDecl *, /*abiIsAsync=*/bool))
8134+
8135+
ERROR(attr_abi_mismatched_pbd_size,none,
8136+
"cannot give pattern binding the ABI of a binding with "
8137+
"%select{more|fewer}0 patterns",
8138+
(/*abiHasExtra=*/bool))
8139+
8140+
ERROR(attr_abi_mismatched_var,none,
8141+
"no match for %select{%kind0 in the ABI|ABI %kind0}1",
8142+
(ValueDecl *, /*isABI=*/bool))
8143+
81148144
#define UNDEFINE_DIAGNOSTIC_MACROS
81158145
#include "DefineDiagnosticMacros.h"

lib/Sema/TypeCheckAttr.cpp

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,85 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
188188
IGNORED_ATTR(PreInverseGenerics)
189189
#undef IGNORED_ATTR
190190

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

196258
Decl *AD = attr->abiDecl;
197259
if (isa<VarDecl>(D) && isa<PatternBindingDecl>(AD)) {
198-
AD = cast<PatternBindingDecl>(AD)
199-
->getVarAtSimilarStructuralPosition(cast<VarDecl>(D));
260+
auto VD = cast<VarDecl>(D);
261+
auto APBD = cast<PatternBindingDecl>(AD);
262+
263+
// Diagnose dissimilar PBD structures.
264+
checkABIAttrPBD(APBD, VD);
265+
266+
// Do the rest of this checking on the corresponding VarDecl, not the
267+
// PBD that's actually in the attribute. Note that `AD` will become null
268+
// if they're too dissimilar to match up.
269+
AD = APBD->getVarAtSimilarStructuralPosition(VD);
200270
}
201271
// TODO: EnumElementDecl?
202272

@@ -208,7 +278,52 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
208278
if (AD->isInvalid())
209279
return;
210280

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

214329
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)