Skip to content

Commit bf18697

Browse files
author
Marc Rasi
committed
parsing, typechecking, and SILGen for #assert
`#assert` is a new static assertion statement that will let us write tests for the new constant evaluation infrastructure that we are working on. `#assert` works by lowering to a `Builtin.poundAssert` SIL instruction. The constant evaluation infrastructure will look for these SIL instructions, const-evaluate their conditions, and emit errors if the conditions are non-constant or false. This commit implements parsing, typechecking and SILGen for `#assert`.
1 parent cb37fea commit bf18697

32 files changed

+309
-40
lines changed

include/swift/AST/Builtins.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,9 @@ BUILTIN_MISC_OPERATION(Swift3ImplicitObjCEntrypoint, "swift3ImplicitObjCEntrypoi
536536
/// willThrow: Error -> ()
537537
BUILTIN_MISC_OPERATION(WillThrow, "willThrow", "", Special)
538538

539+
/// poundAssert has type (Builtin.Int1, Builtin.RawPointer) -> ().
540+
BUILTIN_MISC_OPERATION(PoundAssert, "poundAssert", "", Special)
541+
539542
#undef BUILTIN_MISC_OPERATION
540543

541544
/// Builtins for instrumentation added by sanitizers during SILGen.

include/swift/AST/DiagnosticsParse.def

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ WARNING(escaped_parameter_name,none,
9999
"keyword '%0' does not need to be escaped in argument list",
100100
(StringRef))
101101

102+
ERROR(forbidden_interpolated_string,none,
103+
"%0 cannot be an interpolated string literal", (StringRef))
104+
ERROR(forbidden_extended_escaping_string,none,
105+
"%0 cannot be an extended escaping string literal", (StringRef))
106+
102107
//------------------------------------------------------------------------------
103108
// MARK: Lexer diagnostics
104109
//------------------------------------------------------------------------------
@@ -1263,6 +1268,17 @@ ERROR(expr_typeof_expected_rparen,PointsToFirstBadToken,
12631268
ERROR(expr_dynamictype_deprecated,PointsToFirstBadToken,
12641269
"'.dynamicType' is deprecated. Use 'type(of: ...)' instead", ())
12651270

1271+
ERROR(pound_assert_disabled,PointsToFirstBadToken,
1272+
"#assert is an experimental feature that is currently disabled", ())
1273+
ERROR(pound_assert_expected_lparen,PointsToFirstBadToken,
1274+
"expected '(' in #assert directive", ())
1275+
ERROR(pound_assert_expected_rparen,PointsToFirstBadToken,
1276+
"expected ')' in #assert directive", ())
1277+
ERROR(pound_assert_expected_expression,PointsToFirstBadToken,
1278+
"expected a condition expression", ())
1279+
ERROR(pound_assert_expected_string_literal,PointsToFirstBadToken,
1280+
"expected a string literal", ())
1281+
12661282
//------------------------------------------------------------------------------
12671283
// MARK: Attribute-parsing diagnostics
12681284
//------------------------------------------------------------------------------
@@ -1311,11 +1327,6 @@ ERROR(alignment_must_be_positive_integer,none,
13111327
ERROR(swift_native_objc_runtime_base_must_be_identifier,none,
13121328
"@_swift_native_objc_runtime_base class name must be an identifier", ())
13131329

1314-
ERROR(attr_interpolated_string,none,
1315-
"'%0' cannot be an interpolated string literal", (StringRef))
1316-
ERROR(attr_extended_escaping_string,none,
1317-
"'%0' cannot be an extended escaping string literal", (StringRef))
1318-
13191330
ERROR(attr_only_at_non_local_scope, none,
13201331
"attribute '%0' can only be used in a non-local scope", (StringRef))
13211332

include/swift/AST/Stmt.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,31 @@ class ThrowStmt : public Stmt {
12251225
}
12261226
};
12271227

1228+
/// PoundAssertStmt - Asserts that a condition is true, at compile time.
1229+
class PoundAssertStmt : public Stmt {
1230+
SourceRange Range;
1231+
Expr *Condition;
1232+
StringRef Message;
1233+
1234+
public:
1235+
PoundAssertStmt(SourceRange Range, Expr *condition, StringRef message)
1236+
: Stmt(StmtKind::PoundAssert, /*Implicit=*/false),
1237+
Range(Range),
1238+
Condition(condition),
1239+
Message(message) {}
1240+
1241+
SourceRange getSourceRange() const { return Range; }
1242+
1243+
Expr *getCondition() const { return Condition; }
1244+
StringRef getMessage() const { return Message; }
1245+
1246+
void setCondition(Expr *condition) { Condition = condition; }
1247+
1248+
static bool classof(const Stmt *S) {
1249+
return S->getKind() == StmtKind::PoundAssert;
1250+
}
1251+
};
1252+
12281253
} // end namespace swift
12291254

12301255
#endif // SWIFT_AST_STMT_H

include/swift/AST/StmtNodes.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ STMT(Continue, Stmt)
6767
STMT(Fallthrough, Stmt)
6868
STMT(Fail, Stmt)
6969
STMT(Throw, Stmt)
70-
LAST_STMT(Throw)
70+
STMT(PoundAssert, Stmt)
71+
LAST_STMT(PoundAssert)
7172

7273
#undef STMT_RANGE
7374
#undef LABELED_STMT

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ namespace swift {
211211
/// optimized custom allocator, so that memory debugging tools can be used.
212212
bool UseMalloc = false;
213213

214+
/// \brief Enable experimental #assert feature.
215+
bool EnableExperimentalStaticAssert = false;
216+
214217
/// \brief Enable experimental property behavior feature.
215218
bool EnableExperimentalPropertyBehaviors = false;
216219

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,10 @@ def enable_sil_opaque_values : Flag<["-"], "enable-sil-opaque-values">,
319319
def enable_large_loadable_types : Flag<["-"], "enable-large-loadable-types">,
320320
HelpText<"Enable Large Loadable types IRGen pass">;
321321

322+
def enable_experimental_static_assert :
323+
Flag<["-"], "enable-experimental-static-assert">,
324+
HelpText<"Enable experimental #assert">;
325+
322326
def enable_experimental_property_behaviors :
323327
Flag<["-"], "enable-experimental-property-behaviors">,
324328
HelpText<"Enable experimental property behaviors">;

include/swift/Parse/Parser.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,16 @@ class Parser {
555555

556556
/// Parse an #endif.
557557
bool parseEndIfDirective(SourceLoc &Loc);
558-
558+
559+
/// Given that the current token is a string literal,
560+
/// - if it is not interpolated, returns the contents;
561+
/// - otherwise, diagnoses and returns None.
562+
///
563+
/// \param Loc where to diagnose.
564+
/// \param DiagText name for the string literal in the diagnostic.
565+
Optional<StringRef>
566+
getStringLiteralIfNotInterpolated(SourceLoc Loc, StringRef DiagText);
567+
559568
public:
560569
InFlightDiagnostic diagnose(SourceLoc Loc, Diagnostic Diag) {
561570
if (Diags.isDiagnosticPointsToFirstBadToken(Diag.getID()) &&
@@ -1326,6 +1335,7 @@ class Parser {
13261335
ParserResult<Expr> parseExprCollection();
13271336
ParserResult<Expr> parseExprArray(SourceLoc LSquareLoc);
13281337
ParserResult<Expr> parseExprDictionary(SourceLoc LSquareLoc);
1338+
ParserResult<Expr> parseExprPoundAssert();
13291339
ParserResult<Expr> parseExprPoundUnknown(SourceLoc LSquareLoc);
13301340
ParserResult<Expr>
13311341
parseExprPoundCodeCompletion(Optional<StmtKind> ParentKind);
@@ -1364,6 +1374,7 @@ class Parser {
13641374
ParserResult<Stmt> parseStmtSwitch(LabeledStmtInfo LabelInfo);
13651375
ParserStatus parseStmtCases(SmallVectorImpl<ASTNode> &cases, bool IsActive);
13661376
ParserResult<CaseStmt> parseStmtCase(bool IsActive);
1377+
ParserResult<Stmt> parseStmtPoundAssert();
13671378

13681379
//===--------------------------------------------------------------------===//
13691380
// Generics Parsing

lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,13 @@ class PrintStmt : public StmtVisitor<PrintStmt> {
16551655
PrintWithColorRAII(OS, ParenthesisColor) << ')';
16561656
}
16571657

1658+
void visitPoundAssertStmt(PoundAssertStmt *S) {
1659+
printCommon(S, "pound_assert");
1660+
OS << " message=" << QuotedString(S->getMessage()) << "\n";
1661+
printRec(S->getCondition());
1662+
OS << ")";
1663+
}
1664+
16581665
void visitDoCatchStmt(DoCatchStmt *S) {
16591666
printCommon(S, "do_catch_stmt") << '\n';
16601667
printRec(S->getBody());

lib/AST/ASTPrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3057,6 +3057,11 @@ void PrintAST::visitThrowStmt(ThrowStmt *stmt) {
30573057
// FIXME: print expression.
30583058
}
30593059

3060+
void PrintAST::visitPoundAssertStmt(PoundAssertStmt *stmt) {
3061+
Printer << tok::pound_assert << " ";
3062+
// FIXME: print expression.
3063+
}
3064+
30603065
void PrintAST::visitDeferStmt(DeferStmt *stmt) {
30613066
Printer << tok::kw_defer << " ";
30623067
visit(stmt->getBodyAsWritten());

lib/AST/ASTScope.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,7 @@ ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, Stmt *stmt) {
10891089
case StmtKind::Fallthrough:
10901090
case StmtKind::Fail:
10911091
case StmtKind::Throw:
1092+
case StmtKind::PoundAssert:
10921093
// Nothing to do for these statements.
10931094
return nullptr;
10941095
}

0 commit comments

Comments
 (0)