From 5b68f75330884f4fef3ea437901401ad38663c5d Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Mon, 15 Jun 2020 21:30:11 +0100 Subject: [PATCH] [Typechecker] Diagnose use of magic literals as raw value for enum case --- include/swift/AST/DiagnosticsSema.def | 3 +++ lib/Sema/TypeCheckDecl.cpp | 18 +++++++++++++++--- ...um_raw_representable_object_literals.swift | 19 +++++++++++++++++++ .../compiler_crashers_2_fixed/sr12998.swift | 19 +++++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 test/Sema/enum_raw_representable_object_literals.swift create mode 100644 validation-test/compiler_crashers_2_fixed/sr12998.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index e8581d3cbc515..bda3ee15bf1b0 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2665,6 +2665,9 @@ ERROR(enum_non_integer_convertible_raw_type_no_value,none, "expressible by integer or string literal", ()) ERROR(enum_raw_value_not_unique,none, "raw value for enum case is not unique", ()) +ERROR(enum_raw_value_magic_literal,none, + "use of '%0' literal as raw value for enum case is not supported", + (StringRef)) NOTE(enum_raw_value_used_here,none, "raw value previously used here", ()) NOTE(enum_raw_value_incrementing_from_here,none, diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 6529f0ca38818..f7dc8ede450d3 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1082,6 +1082,21 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, if (ED->LazySemanticInfo.hasFixedRawValues()) continue; + // Using magic literals like #file as raw value is not supported right now. + // TODO: We could potentially support #file, #function, #line and #column. + auto &Diags = ED->getASTContext().Diags; + SourceLoc diagLoc = uncheckedRawValueOf(elt)->isImplicit() + ? elt->getLoc() + : uncheckedRawValueOf(elt)->getLoc(); + if (auto magicLiteralExpr = + dyn_cast(prevValue)) { + auto kindString = + magicLiteralExpr->getKindString(magicLiteralExpr->getKind()); + Diags.diagnose(diagLoc, diag::enum_raw_value_magic_literal, kindString); + elt->setInvalid(); + continue; + } + // Check that the raw value is unique. RawValueKey key{prevValue}; RawValueSource source{elt, lastExplicitValueElt}; @@ -1091,9 +1106,6 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, continue; // Diagnose the duplicate value. - auto &Diags = ED->getASTContext().Diags; - SourceLoc diagLoc = uncheckedRawValueOf(elt)->isImplicit() - ? elt->getLoc() : uncheckedRawValueOf(elt)->getLoc(); Diags.diagnose(diagLoc, diag::enum_raw_value_not_unique); assert(lastExplicitValueElt && "should not be able to have non-unique raw values when " diff --git a/test/Sema/enum_raw_representable_object_literals.swift b/test/Sema/enum_raw_representable_object_literals.swift new file mode 100644 index 0000000000000..f70bbcea068ce --- /dev/null +++ b/test/Sema/enum_raw_representable_object_literals.swift @@ -0,0 +1,19 @@ +// RUN: %target-typecheck-verify-swift +// REQUIRES: OS=ios + +import UIKit + +struct FooLiteral: _ExpressibleByColorLiteral, _ExpressibleByImageLiteral, _ExpressibleByFileReferenceLiteral { + init(_colorLiteralRed: Float, green: Float, blue: Float, alpha: Float) {} + init(imageLiteralResourceName: String) {} + init(fileReferenceLiteralResourceName: String) {} +} + +enum Foo: FooLiteral { // expected-error {{raw type 'FooLiteral' is not expressible by a string, integer, or floating-point literal}} + typealias RawValue = Never + var rawValue: Never { fatalError() } + init(rawValue: Never) { fatalError() } + case bar1 = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1) + case bar2 = #imageLiteral(resourceName: "hello.png") + case bar3 = #fileLiteral(resourceName: "what.txt") +} diff --git a/validation-test/compiler_crashers_2_fixed/sr12998.swift b/validation-test/compiler_crashers_2_fixed/sr12998.swift new file mode 100644 index 0000000000000..d9c32eeb9bd22 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr12998.swift @@ -0,0 +1,19 @@ +// RUN: %target-swift-frontend -typecheck %s -verify + +enum FooString: String { // expected-error {{'FooString' declares raw type 'String', but does not conform to RawRepresentable and conformance could not be synthesized}} + case bar1 = #file // expected-error {{use of '#file' literal as raw value for enum case is not supported}} + case bar2 = #function // expected-error {{use of '#function' literal as raw value for enum case is not supported}} + case bar3 = #filePath // expected-error {{use of '#filePath' literal as raw value for enum case is not supported}} + case bar4 = #line // expected-error {{cannot convert value of type 'Int' to raw type 'String'}} + case bar5 = #column // expected-error {{cannot convert value of type 'Int' to raw type 'String'}} + case bar6 = #dsohandle // expected-error {{cannot convert value of type 'UnsafeRawPointer' to raw type 'String'}} +} + +enum FooInt: Int { // expected-error {{'FooInt' declares raw type 'Int', but does not conform to RawRepresentable and conformance could not be synthesized}} + case bar1 = #file // expected-error {{cannot convert value of type 'String' to raw type 'Int'}} + case bar2 = #function // expected-error {{cannot convert value of type 'String' to raw type 'Int'}} + case bar3 = #filePath // expected-error {{cannot convert value of type 'String' to raw type 'Int'}} + case bar4 = #line // expected-error {{use of '#line' literal as raw value for enum case is not supported}} + case bar5 = #column // expected-error {{use of '#column' literal as raw value for enum case is not supported}} + case bar6 = #dsohandle // expected-error {{cannot convert value of type 'UnsafeRawPointer' to raw type 'Int'}} +}