Skip to content

Commit 30627db

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 76e1750 commit 30627db

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
@@ -8084,5 +8084,35 @@ ERROR(availability_value_generic_type_only_version_newer, none,
80848084
ERROR(invalid_value_for_type_same_type,none,
80858085
"cannot constrain type parameter %0 to be integer %1", (Type, Type))
80868086

8087+
//===----------------------------------------------------------------------===//
8088+
// MARK: @abi Attribute
8089+
//===----------------------------------------------------------------------===//
8090+
8091+
ERROR(attr_abi_mismatched_kind,none,
8092+
"cannot give %kind0 the ABI of a %1",
8093+
(Decl *, DescriptiveDeclKind))
8094+
8095+
ERROR(attr_abi_mismatched_arity,none,
8096+
"cannot give %kind0 the ABI of a %kindonly0 with a different number of "
8097+
"low-level parameters",
8098+
(ValueDecl *))
8099+
8100+
ERROR(attr_abi_mismatched_throws,none,
8101+
"cannot give %0 the ABI of a %kindonly0 which %select{cannot|can}1 throw",
8102+
(ValueDecl *, /*abiCanThrow=*/bool))
8103+
8104+
ERROR(attr_abi_mismatched_async,none,
8105+
"cannot give %0 the ABI of %select{a non-async|an async}1 %kindonly0",
8106+
(ValueDecl *, /*abiIsAsync=*/bool))
8107+
8108+
ERROR(attr_abi_mismatched_pbd_size,none,
8109+
"cannot give pattern binding the ABI of a binding with "
8110+
"%select{more|fewer}0 patterns",
8111+
(/*abiHasExtra=*/bool))
8112+
8113+
ERROR(attr_abi_mismatched_var,none,
8114+
"no match for %select{%kind0 in the ABI|ABI %kind0}1",
8115+
(ValueDecl *, /*isABI=*/bool))
8116+
80878117
#define UNDEFINE_DIAGNOSTIC_MACROS
80888118
#include "DefineDiagnosticMacros.h"

lib/Sema/TypeCheckAttr.cpp

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

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

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

@@ -207,7 +277,52 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
207277
if (AD->isInvalid())
208278
return;
209279

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

213328
void visitAlignmentAttr(AlignmentAttr *attr) {

test/attr/attr_abi.swift

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

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

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

1919
//
@@ -23,52 +23,52 @@ func varForFunc() {}
2323
@abi(func param00_generic00() -> Int)
2424
func param00_generic00() -> Int { fatalError() }
2525

26-
@abi(func param10_generic00(_: Int) -> Int)
26+
@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}}
2727
func param10_generic00() -> Int { fatalError() }
2828

29-
@abi(func param01_generic00() -> Int)
29+
@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}}
3030
func param01_generic00(_: Int) -> Int { fatalError() }
3131

3232
@abi(func param11_generic00(_: Int) -> Int)
3333
func param11_generic00(_: Int) -> Int { fatalError() }
3434

3535

3636

37-
@abi(func param00_generic10<T>() -> T)
37+
@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}}
3838
func param00_generic10() -> Int { fatalError() }
3939

40-
@abi(func param10_generic10<T>(_: Int) -> T)
40+
@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}}
4141
func param10_generic10() -> Int { fatalError() }
4242

4343
@abi(func param01_generic10<T>() -> T)
4444
func param01_generic10(_: Int) -> Int { fatalError() }
4545

46-
@abi(func param11_generic10<T>(_: Int) -> T)
46+
@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}}
4747
func param11_generic10(_: Int) -> Int { fatalError() }
4848

4949

5050

51-
@abi(func param00_generic01() -> Int)
51+
@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}}
5252
func param00_generic01<T>() -> T { fatalError() }
5353

5454
@abi(func param10_generic01(_: Int) -> Int)
5555
func param10_generic01<T>() -> T { fatalError() }
5656

57-
@abi(func param01_generic01() -> Int)
57+
@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}}
5858
func param01_generic01<T>(_: Int) -> T { fatalError() }
5959

60-
@abi(func param11_generic01(_: Int) -> Int)
60+
@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}}
6161
func param11_generic01<T>(_: Int) -> T { fatalError() }
6262

6363

6464

6565
@abi(func param00_generic11<T>() -> T)
6666
func param00_generic11<T>() -> T { fatalError() }
6767

68-
@abi(func param10_generic11<T>(_: Int) -> T)
68+
@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}}
6969
func param10_generic11<T>() -> T { fatalError() }
7070

71-
@abi(func param01_generic11<T>() -> T)
71+
@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}}
7272
func param01_generic11<T>(_: Int) -> T { fatalError() }
7373

7474
@abi(func param11_generic11<T>(_: Int) -> T)
@@ -81,13 +81,13 @@ func param11_generic11<T>(_: Int) -> T { fatalError() }
8181
@abi(func throws00(_: () throws -> Void))
8282
func throws00(_: () throws -> Void) {}
8383

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

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

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

9393
@abi(func throws11(_: () throws -> Void) throws)
@@ -96,7 +96,7 @@ func throws11(_: () throws -> Void) throws {}
9696
@abi(func throws21(_: () throws -> Void) rethrows)
9797
func throws21(_: () throws -> Void) throws {}
9898

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

102102
@abi(func throws12(_: () throws -> Void) throws)
@@ -112,10 +112,10 @@ func throws22(_: () throws -> Void) rethrows {}
112112
@abi(func async00())
113113
func async00() {}
114114
115-
@abi(func async10() async)
115+
@abi(func async10() async) // expected-error {{cannot give 'async10()' the ABI of an async global function}}
116116
func async10() {}
117117
118-
@abi(func async01())
118+
@abi(func async01()) // expected-error {{cannot give 'async01()' the ABI of a non-async global function}}
119119
func async01() async {}
120120
121121
@abi(func async11() async)
@@ -125,17 +125,17 @@ func async11() async {}
125125
// PBD shape checking
126126
//
127127
128-
@abi(var x1, y1: Int)
128+
@abi(var x1, y1: Int) // expected-error {{cannot give pattern binding the ABI of a binding with more patterns}}
129129
var x1: Int = 0
130130

131131
@abi(var x2: Int)
132-
var x2 = 0, y2: Int = 0
132+
var x2 = 0, y2: Int = 0 // expected-error {{cannot give pattern binding the ABI of a binding with fewer patterns}}
133133
134-
@abi(var (x3, y3): (Int, Int), (a3, b3): (Int, Int))
134+
@abi(var (x3, y3): (Int, Int), (a3, b3): (Int, Int)) // expected-error {{no match for ABI var 'b3'}}
135135
var (x3, y3): (Int, Int) = (0, 0), a3: Int = 0
136136
137137
@abi(var (x4, y4): (Int, Int), a4: Int)
138-
var (x4, y4): (Int, Int) = (0, 0), (a4, b4): (Int, Int) = (0, 0)
138+
var (x4, y4): (Int, Int) = (0, 0), (a4, b4): (Int, Int) = (0, 0) // expected-error {{no match for var 'b4' in the ABI}}
139139
140140
//
141141
// Conflict diagnostics

0 commit comments

Comments
 (0)