From 1f32e2d957ee0acba3f57ac6240f6ce4cc4f08d6 Mon Sep 17 00:00:00 2001 From: YOCKOW Date: Mon, 2 Sep 2019 13:31:23 +0900 Subject: [PATCH 001/123] [Foundation] DataProtocol: Reimplement firstRange(of:in:)/lastRange(of:in:) to fix SR-10689. Cherry-pick from https://github.com/apple/swift-corelibs-foundation/pull/2499 --- .../Darwin/Foundation/DataProtocol.swift | 78 +++++++++---------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/stdlib/public/Darwin/Foundation/DataProtocol.swift b/stdlib/public/Darwin/Foundation/DataProtocol.swift index 00f3a032cf43a..4a920511435bf 100644 --- a/stdlib/public/Darwin/Foundation/DataProtocol.swift +++ b/stdlib/public/Darwin/Foundation/DataProtocol.swift @@ -142,60 +142,56 @@ extension DataProtocol { return self.copyBytes(to: UnsafeMutableRawBufferPointer(start: ptr.baseAddress, count: ptr.count * MemoryLayout.stride), from: range) } + private func matches(_ data: D, from index: Index) -> Bool { + var haystackIndex = index + var needleIndex = data.startIndex + + while true { + guard self[haystackIndex] == data[needleIndex] else { return false } + + haystackIndex = self.index(after: haystackIndex) + needleIndex = data.index(after: needleIndex) + if needleIndex == data.endIndex { + // i.e. needle is found. + return true + } else if haystackIndex == endIndex { + return false + } + } + } + public func firstRange(of data: D, in range: R) -> Range? where R.Bound == Index { let r = range.relative(to: self) - let rangeCount = distance(from: r.lowerBound, to: r.upperBound) - if rangeCount < data.count { + let length = data.count + + if length == 0 || length > distance(from: r.lowerBound, to: r.upperBound) { return nil } - var haystackIndex = r.lowerBound - let haystackEnd = index(r.upperBound, offsetBy: -data.count) - while haystackIndex < haystackEnd { - var compareIndex = haystackIndex - var needleIndex = data.startIndex - let needleEnd = data.endIndex - var matched = true - while compareIndex < haystackEnd && needleIndex < needleEnd { - if self[compareIndex] != data[needleIndex] { - matched = false - break - } - needleIndex = data.index(after: needleIndex) - compareIndex = index(after: compareIndex) + + var position = r.lowerBound + while position < r.upperBound && distance(from: position, to: r.upperBound) >= length { + if matches(data, from: position) { + return position..(of data: D, in range: R) -> Range? where R.Bound == Index { let r = range.relative(to: self) - let rangeCount = distance(from: r.lowerBound, to: r.upperBound) - if rangeCount < data.count { + let length = data.count + + if length == 0 || length > distance(from: r.lowerBound, to: r.upperBound) { return nil } - var haystackIndex = r.upperBound - let haystackStart = index(r.lowerBound, offsetBy: data.count) - while haystackIndex > haystackStart { - var compareIndex = haystackIndex - var needleIndex = data.endIndex - let needleStart = data.startIndex - var matched = true - while compareIndex > haystackStart && needleIndex > needleStart { - if self[compareIndex] != data[needleIndex] { - matched = false - break - } - needleIndex = data.index(before: needleIndex) - compareIndex = index(before: compareIndex) - } - if matched { - return compareIndex..= r.lowerBound { + if matches(data, from: position) { + return position.. Date: Sun, 8 Dec 2019 22:47:45 +0900 Subject: [PATCH 002/123] [Foundation] Add tests for [SR-10689](https://bugs.swift.org/browse/SR-10689). Cherry-pick from https://github.com/apple/swift-corelibs-foundation/pull/2499/commits/19017a7af69c9937da7b8dc013f14a0a85843ad4 --- test/stdlib/TestData.swift | 94 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/test/stdlib/TestData.swift b/test/stdlib/TestData.swift index cb7d36b8fccb1..e5833316f041c 100644 --- a/test/stdlib/TestData.swift +++ b/test/stdlib/TestData.swift @@ -1077,6 +1077,99 @@ class TestData : TestDataSuper { expectEqual(slice4[0], 8) } + func test_rangeOfDataProtocol() { + // https://bugs.swift.org/browse/SR-10689 + + let base = Data([0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03]) + let subdata = base[10..<13] // [0x02, 0x03, 0x00] + let oneByte = base[14..<15] // [0x02] + + do { // firstRange(of:in:) + func assertFirstRange(_ data: Data, _ fragment: Data, range: ClosedRange? = nil, + expectedStartIndex: Int?, + _ message: @autoclosure () -> String = "", + file: String = #file, line: UInt = #line) { + if let index = expectedStartIndex { + let expectedRange: Range = index..<(index + fragment.count) + if let someRange = range { + expectEqual(data.firstRange(of: fragment, in: someRange), expectedRange, message(), file: file, line: line) + } else { + expectEqual(data.firstRange(of: fragment), expectedRange, message(), file: file, line: line) + } + } else { + if let someRange = range { + expectNil(data.firstRange(of: fragment, in: someRange), message(), file: file, line: line) + } else { + expectNil(data.firstRange(of: fragment), message(), file: file, line: line) + } + } + } + + assertFirstRange(base, base, expectedStartIndex: base.startIndex) + assertFirstRange(base, subdata, expectedStartIndex: 2) + assertFirstRange(base, oneByte, expectedStartIndex: 2) + + assertFirstRange(subdata, base, expectedStartIndex: nil) + assertFirstRange(subdata, subdata, expectedStartIndex: subdata.startIndex) + assertFirstRange(subdata, oneByte, expectedStartIndex: subdata.startIndex) + + assertFirstRange(oneByte, base, expectedStartIndex: nil) + assertFirstRange(oneByte, subdata, expectedStartIndex: nil) + assertFirstRange(oneByte, oneByte, expectedStartIndex: oneByte.startIndex) + + assertFirstRange(base, subdata, range: 1...14, expectedStartIndex: 2) + assertFirstRange(base, subdata, range: 6...8, expectedStartIndex: 6) + assertFirstRange(base, subdata, range: 8...10, expectedStartIndex: nil) + + assertFirstRange(base, oneByte, range: 1...14, expectedStartIndex: 2) + assertFirstRange(base, oneByte, range: 6...6, expectedStartIndex: 6) + assertFirstRange(base, oneByte, range: 8...9, expectedStartIndex: nil) + } + + do { // lastRange(of:in:) + func assertLastRange(_ data: Data, _ fragment: Data, range: ClosedRange? = nil, + expectedStartIndex: Int?, + _ message: @autoclosure () -> String = "", + file: String = #file, line: UInt = #line) { + if let index = expectedStartIndex { + let expectedRange: Range = index..<(index + fragment.count) + if let someRange = range { + expectEqual(data.lastRange(of: fragment, in: someRange), expectedRange, message(), file: file, line: line) + } else { + expectEqual(data.lastRange(of: fragment), expectedRange, message(), file: file, line: line) + } + } else { + if let someRange = range { + expectNil(data.lastRange(of: fragment, in: someRange), message(), file: file, line: line) + } else { + expectNil(data.lastRange(of: fragment), message(), file: file, line: line) + } + } + } + + assertLastRange(base, base, expectedStartIndex: base.startIndex) + assertLastRange(base, subdata, expectedStartIndex: 10) + assertLastRange(base, oneByte, expectedStartIndex: 14) + + assertLastRange(subdata, base, expectedStartIndex: nil) + assertLastRange(subdata, subdata, expectedStartIndex: subdata.startIndex) + assertLastRange(subdata, oneByte, expectedStartIndex: subdata.startIndex) + + assertLastRange(oneByte, base, expectedStartIndex: nil) + assertLastRange(oneByte, subdata, expectedStartIndex: nil) + assertLastRange(oneByte, oneByte, expectedStartIndex: oneByte.startIndex) + + assertLastRange(base, subdata, range: 1...14, expectedStartIndex: 10) + assertLastRange(base, subdata, range: 6...8, expectedStartIndex: 6) + assertLastRange(base, subdata, range: 8...10, expectedStartIndex: nil) + + assertLastRange(base, oneByte, range: 1...14, expectedStartIndex: 14) + assertLastRange(base, oneByte, range: 6...6, expectedStartIndex: 6) + assertLastRange(base, oneByte, range: 8...9, expectedStartIndex: nil) + } + } + func test_sliceAppending() { // https://bugs.swift.org/browse/SR-4473 var fooData = Data() @@ -3882,6 +3975,7 @@ DataTests.test("test_noCopyBehavior") { TestData().test_noCopyBehavior() } DataTests.test("test_doubleDeallocation") { TestData().test_doubleDeallocation() } DataTests.test("test_repeatingValueInitialization") { TestData().test_repeatingValueInitialization() } DataTests.test("test_rangeZoo") { TestData().test_rangeZoo() } +DataTests.test("test_rangeOfDataProtocol") { TestData().test_rangeOfDataProtocol() } DataTests.test("test_sliceAppending") { TestData().test_sliceAppending() } DataTests.test("test_replaceSubrange") { TestData().test_replaceSubrange() } DataTests.test("test_sliceWithUnsafeBytes") { TestData().test_sliceWithUnsafeBytes() } From 28531141d2dccd2b2d0df5c9a459536341585306 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 10 Jul 2020 02:16:38 +0300 Subject: [PATCH 003/123] AssociatedTypeInference: Self is a valid fixed type witness --- include/swift/AST/GenericSignatureBuilder.h | 2 +- lib/AST/GenericSignatureBuilder.cpp | 2 +- lib/Sema/TypeCheckProtocolInference.cpp | 19 ++-- .../req/associated_type_inference.swift | 21 +--- ...associated_type_inference_fixed_type.swift | 105 ++++++++++++++++++ 5 files changed, 125 insertions(+), 24 deletions(-) create mode 100644 test/decl/protocol/req/associated_type_inference_fixed_type.swift diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h index abb790e466a14..5481e97b01f84 100644 --- a/include/swift/AST/GenericSignatureBuilder.h +++ b/include/swift/AST/GenericSignatureBuilder.h @@ -757,7 +757,7 @@ class GenericSignatureBuilder { /// \param resolutionKind How to perform the resolution. /// /// \param wantExactPotentialArchetype Whether to return the precise - /// potential archetype described by the type (vs. just the equivalance + /// potential archetype described by the type (vs. just the equivalence /// class and resolved type). ResolvedType maybeResolveEquivalenceClass( Type type, diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index 7d05c54be064f..a1126184199d6 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -6265,7 +6265,7 @@ static bool removalDisconnectsEquivalenceClass( // derived edges). if (fromComponentIndex == toComponentIndex) return false; - /// Describes the parents in the equivalance classes we're forming. + /// Describes the parents in the equivalence classes we're forming. SmallVector parents; for (unsigned i : range(equivClass->derivedSameTypeComponents.size())) { parents.push_back(i); diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 823befcbacd9c..13a2cfc39f34e 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -805,25 +805,30 @@ Type AssociatedTypeInference::computeFixedTypeWitness( AssociatedTypeDecl *assocType) { // Look at all of the inherited protocols to determine whether they // require a fixed type for this associated type. - Type dependentType = assocType->getDeclaredInterfaceType(); Type resultType; for (auto conformedProto : adoptee->getAnyNominal()->getAllProtocols()) { if (!conformedProto->inheritsFrom(assocType->getProtocol())) continue; - auto genericSig = conformedProto->getGenericSignature(); + const auto genericSig = conformedProto->getGenericSignature(); if (!genericSig) return Type(); - Type concreteType = genericSig->getConcreteType(dependentType); - if (!concreteType) continue; + const auto nestedType = genericSig->getCanonicalTypeInContext( + DependentMemberType::get(conformedProto->getSelfInterfaceType(), + assocType->getName())); + if (nestedType->isEqual(conformedProto->getSelfInterfaceType())) { + // Self is a valid fixed type witness. + } else if (nestedType->isTypeParameter()) { + continue; + } if (!resultType) { - resultType = concreteType; + resultType = nestedType; continue; } // FIXME: Bailing out on ambiguity. - if (!resultType->isEqual(concreteType)) + if (!resultType->isEqual(nestedType)) return Type(); } @@ -887,7 +892,7 @@ AssociatedTypeInference::computeAbstractTypeWitness( return AbstractTypeWitness::forFixed(assocType, concreteType); // If we can form a default type, do so. - if (auto typeWitness = computeDefaultTypeWitness(assocType)) + if (const auto &typeWitness = computeDefaultTypeWitness(assocType)) return typeWitness; // If there is a generic parameter of the named type, use that. diff --git a/test/decl/protocol/req/associated_type_inference.swift b/test/decl/protocol/req/associated_type_inference.swift index 0de5e8ec1b6bc..817f08de5e85d 100644 --- a/test/decl/protocol/req/associated_type_inference.swift +++ b/test/decl/protocol/req/associated_type_inference.swift @@ -676,21 +676,12 @@ struct S40: P40c { typealias B = Self } -// Self is not treated as a fixed type witness. +// Fails to find the fixed type witness B == FIXME_S1. protocol FIXME_P1a { - associatedtype A // expected-note {{protocol requires nested type 'A'}} -} -protocol FIXME_P1b: FIXME_P1a where A == Self {} -// expected-error@+2 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1a'}} -// expected-error@+1 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1b'}} -struct FIXME_S1: FIXME_P1b {} - -// Fails to find the fixed type witness B == FIXME_S2. -protocol FIXME_P2a { associatedtype A: Equatable = Never // expected-note {{protocol requires nested type 'A'}} - associatedtype B: FIXME_P2a // expected-note {{protocol requires nested type 'B'}} + associatedtype B: FIXME_P1a // expected-note {{protocol requires nested type 'B'}} } -protocol FIXME_P2b: FIXME_P2a where B == FIXME_S2 {} -// expected-error@+2 {{type 'FIXME_S2' does not conform to protocol 'FIXME_P2a'}} -// expected-error@+1 {{type 'FIXME_S2' does not conform to protocol 'FIXME_P2b'}} -struct FIXME_S2: FIXME_P2b {} +protocol FIXME_P1b: FIXME_P1a where B == FIXME_S1 {} +// expected-error@+2 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1a'}} +// expected-error@+1 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1b'}} +struct FIXME_S1: FIXME_P1b {} diff --git a/test/decl/protocol/req/associated_type_inference_fixed_type.swift b/test/decl/protocol/req/associated_type_inference_fixed_type.swift new file mode 100644 index 0000000000000..4b8f6c99b3289 --- /dev/null +++ b/test/decl/protocol/req/associated_type_inference_fixed_type.swift @@ -0,0 +1,105 @@ +// RUN: %target-typecheck-verify-swift + +protocol P1 where A == Never { + associatedtype A // expected-note {{protocol requires nested type 'A'}} +} +// FIXME: Should this infer A := Never? +struct S1: P1 {} // expected-error {{type 'S1' does not conform to protocol 'P1'}} + +protocol P2a { + associatedtype A +} +protocol P2b: P2a where A == Never {} +protocol P2c: P2b {} +struct S2a: P2b {} // OK, A := Never +struct S2b: P2c {} // OK, A := Never + +// Fixed type witnesses can reference dependent members. +protocol P3a { + associatedtype A + associatedtype B +} +protocol P3b: P3a where A == [B] {} +struct S3: P3b { // OK, A := [Never], B := Never + typealias B = Never +} + +protocol P4 {} +extension P4 { + typealias B = Self +} +struct S4: P4, P3b {} // OK, A := [S4], B := S4 + +// Self is a valid fixed type witness. +protocol P5a { + associatedtype A +} +protocol P5b: P5a where A == Self {} +struct S5: P5b {} // OK, A := S5 + + +protocol P6 where A == Never { // expected-error {{same-type constraint type 'Never' does not conform to required protocol 'P6'}} + // expected-error@+2 {{same-type constraint type 'Never' does not conform to required protocol 'P6'}} + // expected-note@+1 {{protocol requires nested type 'A}} + associatedtype A: P6 +} +struct S6: P6 {} // expected-error {{type 'S6' does not conform to protocol 'P6'}} + +protocol P7a where A == Never { + associatedtype A +} +// expected-error@+2 {{'Self.A' cannot be equal to both 'Bool' and 'Never'}} +// expected-note@+1 {{same-type constraint 'Self.A' == 'Never' implied here}} +protocol P7b: P7a where A == Bool {} +struct S7: P7b {} + +protocol P8 where A == Bool { + associatedtype A // expected-note {{protocol requires nested type 'A'}} +} +// expected-error@+2 {{type 'S8' does not conform to protocol 'P7a'}} +// expected-error@+1 {{type 'S8' does not conform to protocol 'P8'}} +struct S8: P8, P7a {} + +protocol P9a where A == Never { + associatedtype A +} +protocol P9b: P9a { + associatedtype A // expected-note {{protocol requires nested type 'A'}} +} +// FIXME: Associated type restatement sabotages the conformance. +// expected-error@+2 {{type 'S9a' does not conform to protocol 'P9a'}} +// expected-error@+1 {{type 'S9a' does not conform to protocol 'P9b'}} +struct S9a: P9b {} +// expected-error@+2 {{'P9a' requires the types 'S9b.A' (aka 'Bool') and 'Never' be equivalent}} +// expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S9b]}} +struct S9b: P9b { + typealias A = Bool +} +struct S9c: P9b { // OK, S9c.A does not contradict Self.A == Never. + typealias Sugar = Never + typealias A = Sugar +} + +protocol P10 {} +extension P10 { + typealias A = Bool +} +// FIXME: 'P10 extension.A' should not be considered a viable type witness; +// instead, the compiler should infer A := Never and synthesize S10.A. +// expected-error@+2 {{'P9a' requires the types 'S10.A' (aka 'Bool') and 'Never' be equivalent}} +// expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S10]}} +struct S10: P10, P9a {} + +protocol P11a { + associatedtype A +} +protocol P11b: P11a where A == Never {} +protocol Q11 { + associatedtype A // expected-note {{protocol requires nested type 'A'}} +} +// FIXME: Unrelated protocols with a matching associated type should +// also be considered when computing a fixed type witness. +// expected-error@+3 {{type 'S11' does not conform to protocol 'Q11'}} +// expected-error@+2 {{type 'S11' does not conform to protocol 'P11a'}} +// expected-error@+1 {{type 'S11' does not conform to protocol 'P11b'}} +struct S11: Q11, P11b {} From 1724debda4272051cf507a74d96a65ae90339677 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Mon, 3 Aug 2020 19:39:23 -0700 Subject: [PATCH 004/123] [ConstraintSystem] Add a type variable merging heuristic to addJoinConstraint. This heuristic merges type variables for literal expressions of the same kind. This is valid because such type variables will have the same set of constraints on them, and must be bound to the same type. --- lib/Sema/CSSimplify.cpp | 62 ++++++++++++++++++++++++++++++++++--- lib/Sema/ConstraintSystem.h | 10 +++--- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index fbc473622529d..4957153e7b349 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -32,6 +32,8 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Support/Compiler.h" +#include + using namespace swift; using namespace constraints; @@ -10418,14 +10420,44 @@ void ConstraintSystem::addContextualConversionConstraint( convertTypeLocator, /*isFavored*/ true); } +/// Returns the \c ExprKind of the given type variable if it's the type of an +/// atomic literal expression, meaning the literal can't be composed of subexpressions. +/// Otherwise, returns \c None. +static Optional getAtomicLiteralKind(TypeVariableType *typeVar) { + const std::unordered_set atomicLiteralKinds = { + ExprKind::IntegerLiteral, + ExprKind::FloatLiteral, + ExprKind::StringLiteral, + ExprKind::BooleanLiteral, + ExprKind::NilLiteral, + }; + + if (!typeVar) + return None; + + auto *locator = typeVar->getImpl().getLocator(); + if (!locator->directlyAt()) + return None; + + auto literalKind = getAsExpr(locator->getAnchor())->getKind(); + if (!atomicLiteralKinds.count(literalKind)) + return None; + + return literalKind; +} + Type ConstraintSystem::addJoinConstraint( ConstraintLocator *locator, - ArrayRef> inputs) { + ArrayRef> inputs, + Optional supertype) { switch (inputs.size()) { case 0: return Type(); case 1: + if (supertype.hasValue()) + break; + return inputs.front().first; default: @@ -10434,12 +10466,32 @@ Type ConstraintSystem::addJoinConstraint( } // Create a type variable to capture the result of the join. - Type resultTy = createTypeVariable(locator, - (TVO_PrefersSubtypeBinding | - TVO_CanBindToNoEscape)); + Type resultTy = supertype.hasValue() ? supertype.getValue() : + createTypeVariable(locator, (TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape)); + + using RawExprKind = uint8_t; + llvm::SmallDenseMap representativeForKind; - // Introduce conversions from each input type to the type variable. + // Join the input types. for (const auto &input : inputs) { + // We can merge the type variables of same-kind atomic literal expressions because they + // will all have the same set of constraints and therefore can never resolve to anything + // different. + auto *typeVar = input.first->getAs(); + if (auto literalKind = getAtomicLiteralKind(typeVar)) { + auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; + auto *currentRep = getRepresentative(typeVar); + + if (originalRep) { + if (originalRep != currentRep) + mergeEquivalenceClasses(currentRep, originalRep); + continue; + } + + originalRep = currentRep; + } + + // Introduce conversions from each input type to the supertype. addConstraint( ConstraintKind::Conversion, input.first, resultTy, input.second); } diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 2abf2a3bc3913..391dc445b3a0d 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3080,12 +3080,14 @@ class ConstraintSystem { /// supertype. /// /// Currently, a "join" is modeled by a set of conversion constraints to - /// a new type variable. At some point, we may want a new constraint kind - /// to cover the join. + /// a new type variable or a specified supertype. At some point, we may want + /// a new constraint kind to cover the join. /// - /// \returns the joined type, which is generally a new type variable. + /// \returns the joined type, which is generally a new type variable, unless there are + /// fewer than 2 input types or the \c supertype parameter is specified. Type addJoinConstraint(ConstraintLocator *locator, - ArrayRef> inputs); + ArrayRef> inputs, + Optional supertype = None); /// Add a constraint to the constraint system with an associated fix. void addFixConstraint(ConstraintFix *fix, ConstraintKind kind, From 50265140aaca5f1af82a6e7a2dc4833488e6ccb3 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 3 Aug 2020 18:49:13 -0700 Subject: [PATCH 005/123] [sil] Define ValueOwnershipKind::isCompatibleWith(SILValue v). This just returns isCompatibleWith(v.getOwnershipKind()). Just makes some code easier to write. --- include/swift/SIL/SILValue.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h index 37064391dd50a..751484a90e175 100644 --- a/include/swift/SIL/SILValue.h +++ b/include/swift/SIL/SILValue.h @@ -41,6 +41,7 @@ class SILLocation; class DeadEndBlocks; class ValueBaseUseIterator; class ValueUseIterator; +class SILValue; /// An enumeration which contains values for all the concrete ValueBase /// subclasses. @@ -188,6 +189,12 @@ struct ValueOwnershipKind { return merge(other).hasValue(); } + /// Returns isCompatibleWith(other.getOwnershipKind()). + /// + /// Definition is inline after SILValue is defined to work around circular + /// dependencies. + bool isCompatibleWith(SILValue other) const; + template static Optional merge(RangeTy &&r) { auto initial = Optional(ValueOwnershipKind::None); @@ -440,6 +447,10 @@ class SILValue { void verifyOwnership(DeadEndBlocks *DEBlocks = nullptr) const; }; +inline bool ValueOwnershipKind::isCompatibleWith(SILValue other) const { + return isCompatibleWith(other.getOwnershipKind()); +} + /// A map from a ValueOwnershipKind that an operand can accept to a /// UseLifetimeConstraint that describes the effect that the operand's use has /// on the underlying value. If a ValueOwnershipKind is not in this map then From bfbc3a7570cbe4a1112498d2a105bdb12e314fd7 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 4 Aug 2020 15:42:54 -0700 Subject: [PATCH 006/123] [Test] Run __swift5_entry test on all Apple platforms. Previously, the test was limited to only x86_64 macos. Remove that limitation by introducing the appropriate cross-platform typedef for mach_header and signing the pointer before casting it to a function pointer. --- test/IRGen/entrypoint-section-run.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/test/IRGen/entrypoint-section-run.cpp b/test/IRGen/entrypoint-section-run.cpp index 2158b77e7ea85..efb009823a7b2 100644 --- a/test/IRGen/entrypoint-section-run.cpp +++ b/test/IRGen/entrypoint-section-run.cpp @@ -1,10 +1,11 @@ // RUN: %empty-directory(%t) -// RUN: %clang %s -isysroot %sdk -o %t/main +// RUN: %target-clang %s -std=c++11 -isysroot %sdk -o %t/main // RUN: %target-codesign %t/main // RUN: %target-build-swift %S/Inputs/at-main-struct-simple.swift -O -parse-as-library -emit-library -o %t/libHowdy.dylib -module-name Howdy +// RUN: %target-codesign %t/libHowdy.dylib // RUN: %target-run %t/main %t/libHowdy.dylib | %FileCheck %s -// REQUIRES: OS=macosx,CPU=x86_64 +// REQUIRES: VENDOR=apple // REQUIRES: executable_test // UNSUPPORTED: remote_run @@ -13,6 +14,13 @@ #include #include #include +#include + +#if __POINTER_WIDTH__ == 64 +using mach_header_platform = mach_header_64; +#else +using mach_header_platform = mach_header; +#endif int main(int argc, char *argv[]) { if (argc != 2) { @@ -35,12 +43,19 @@ int main(int argc, char *argv[]) { continue; } auto *header = - reinterpret_cast(_dyld_get_image_header(index)); + reinterpret_cast(_dyld_get_image_header(index)); size_t size; auto *data = getsectiondata(header, "__TEXT", "__swift5_entry", &size); int32_t offset = *reinterpret_cast(data); mainFunction = reinterpret_cast( - reinterpret_cast(data) + offset); + ptrauth_sign_unauthenticated( + reinterpret_cast( + reinterpret_cast(data) + offset + ), + ptrauth_key_function_pointer, + ptrauth_function_pointer_type_discriminator(MainFunction) + ) + ); break; } From 8c0ee61ca4e4a48324b4269a4376cf318e8a42ed Mon Sep 17 00:00:00 2001 From: Shoaib Meenai Date: Tue, 4 Aug 2020 19:09:37 -0700 Subject: [PATCH 007/123] [utils] Add Uxtheme.h to VFS overlay This is needed for building the stdlib for Windows now. --- utils/WindowsSDKVFSOverlay.yaml.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/WindowsSDKVFSOverlay.yaml.in b/utils/WindowsSDKVFSOverlay.yaml.in index ed491aa90a2ef..e8fb615273b8f 100644 --- a/utils/WindowsSDKVFSOverlay.yaml.in +++ b/utils/WindowsSDKVFSOverlay.yaml.in @@ -149,6 +149,9 @@ roots: - name: unknwn.h type: file external-contents: "@UniversalCRTSdkDir@/Include/@UCRTVersion@/um/Unknwn.h" + - name: uxtheme.h + type: file + external-contents: "@UniversalCRTSdkDir@/Include/@UCRTVersion@/um/Uxtheme.h" - name: unknwnbase.h type: file external-contents: "@UniversalCRTSdkDir@/Include/@UCRTVersion@/um/Unknwnbase.h" From 8d21750ef3de437e21c14959c9f7838cae416518 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 4 Aug 2020 15:11:27 -0700 Subject: [PATCH 008/123] Frontend: support dumping the JIT state Add a debugging mechanism that enables the JIT to dump the LLVM IR and object files to enable debugging the JIT. This makes it easier to debug the JIT mode failures. The idea was from Lang Hames! --- include/swift/AST/IRGenOptions.h | 8 ++++++++ include/swift/Option/FrontendOptions.td | 3 +++ lib/Frontend/CompilerInvocation.cpp | 18 ++++++++++++++++-- lib/Immediate/Immediate.cpp | 25 +++++++++++++++++++++++++ test/IRGen/jit-debugging.swift | 15 +++++++++++++++ 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 test/IRGen/jit-debugging.swift diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index e60873f074638..f805562d7ef52 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -139,6 +139,12 @@ struct PointerAuthOptions : clang::PointerAuthOptions { PointerAuthSchema ResilientClassStubInitCallbacks; }; +enum class JITDebugArtifact : unsigned { + None, ///< None + LLVMIR, ///< LLVM IR + Object, ///< Object File +}; + /// The set of options supported by IR generation. class IRGenOptions { public: @@ -326,6 +332,8 @@ class IRGenOptions { Optional AutolinkRuntimeCompatibilityLibraryVersion; Optional AutolinkRuntimeCompatibilityDynamicReplacementLibraryVersion; + JITDebugArtifact DumpJIT = JITDebugArtifact::None; + IRGenOptions() : DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssembly), Verify(true), OptMode(OptimizationMode::NotSet), diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 76cd3658ee615..5bd693d2ffe7d 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -329,6 +329,9 @@ def disable_llvm_verify : Flag<["-"], "disable-llvm-verify">, def disable_llvm_value_names : Flag<["-"], "disable-llvm-value-names">, HelpText<"Don't add names to local values in LLVM IR">; +def dump_jit : JoinedOrSeparate<["-"], "dump-jit">, + HelpText<"Dump JIT contents">; + def enable_llvm_value_names : Flag<["-"], "enable-llvm-value-names">, HelpText<"Add names to local values in LLVM IR">; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index bdb3437ee50e2..f9c3828c19c67 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1448,9 +1448,23 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_disable_concrete_type_metadata_mangled_name_accessors)) Opts.DisableConcreteTypeMetadataMangledNameAccessors = true; - if (Args.hasArg(OPT_use_jit)) + if (Args.hasArg(OPT_use_jit)) { Opts.UseJIT = true; - + if (const Arg *A = Args.getLastArg(OPT_dump_jit)) { + llvm::Optional artifact = + llvm::StringSwitch>(A->getValue()) + .Case("llvm-ir", JITDebugArtifact::LLVMIR) + .Case("object", JITDebugArtifact::Object) + .Default(None); + if (!artifact) { + Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, + A->getOption().getName(), A->getValue()); + return true; + } + Opts.DumpJIT = *artifact; + } + } + for (const Arg *A : Args.filtered(OPT_verify_type_layout)) { Opts.VerifyTypeLayoutNames.push_back(A->getValue()); } diff --git a/lib/Immediate/Immediate.cpp b/lib/Immediate/Immediate.cpp index 5ac87f6f42397..b49156177b8f1 100644 --- a/lib/Immediate/Immediate.cpp +++ b/lib/Immediate/Immediate.cpp @@ -30,6 +30,7 @@ #include "swift/SILOptimizer/PassManager/Passes.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" +#include "llvm/ExecutionEngine/Orc/DebugUtils.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/IR/LLVMContext.h" @@ -75,6 +76,18 @@ static void *loadRuntimeLib(StringRef sharedLibName, return nullptr; } +static void DumpLLVMIR(const llvm::Module &M) { + std::string path = (M.getName() + ".ll").str(); + for (size_t count = 0; llvm::sys::fs::exists(path); ) + path = (M.getName() + llvm::utostr(count++) + ".ll").str(); + + std::error_code error; + llvm::raw_fd_ostream stream(path, error); + if (error) + return; + M.print(stream, /*AssemblyAnnotationWriter=*/nullptr); +} + void *swift::immediate::loadSwiftRuntime(ArrayRef runtimeLibPaths) { #if defined(_WIN32) @@ -290,6 +303,18 @@ int swift::RunImmediately(CompilerInstance &CI, } auto Module = GenModule.getModule(); + + switch (IRGenOpts.DumpJIT) { + case JITDebugArtifact::None: + break; + case JITDebugArtifact::LLVMIR: + DumpLLVMIR(*Module); + break; + case JITDebugArtifact::Object: + JIT->getObjTransformLayer().setTransform(llvm::orc::DumpObjects()); + break; + } + { // Get a generator for the process symbols and attach it to the main // JITDylib. diff --git a/test/IRGen/jit-debugging.swift b/test/IRGen/jit-debugging.swift new file mode 100644 index 0000000000000..78d59fa93fbf9 --- /dev/null +++ b/test/IRGen/jit-debugging.swift @@ -0,0 +1,15 @@ +// %empty-directory(%t) +// RUN: not %target-swift-frontend -use-jit -dump-jit invalid -interpret %s 2>&1 | %FileCheck -check-prefix CHECK-INVALID %s +// CHECK-INVALID: error: invalid value 'invalid' in 'dump-jit' + +// RUN: %empty-directory(%t) +// RUN: cd %t && %target-swift-frontend -use-jit -dump-jit llvm-ir -interpret %s +// RUN: %FileCheck -check-prefix CHECK-LLIR %s < %t/main.ll +// CHECK-LLIR: ; ModuleID = 'main' + +// RUN: %empty-directory(%t) +// RUN: cd %t && %target-swift-frontend -use-jit -dump-jit object -interpret %s +// RUN: %llvm-nm --defined-only --extern-only %t/main-jitted-objectbuffer.o | %FileCheck -check-prefix CHECK-OBJ %s +// CHECK-OBJ: T {{_?}}main + +let zero = 0 From 849c63634ca69655c2fc182c72873c5f8776b048 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Wed, 5 Aug 2020 09:34:06 -0700 Subject: [PATCH 009/123] [AutoDiff] Fix differentiation for non-wrt `inout` parameters. (#33304) Fix SIL differential function type calculation to handle non-wrt `inout` parameters. Patch `SILFunctionType::getDifferentiabilityResultIndices` to prevent returning empty result indices for `@differentiable` function types with no formal results where all `inout` parameters are `@noDerivative`. TF-1305 tracks a robust fix. Resolves SR-13305. Exposes TF-1305: parameter/result differentiability hole for `inout` parameters. --- lib/SIL/IR/SILFunctionType.cpp | 47 ++++++++++++-- ...sr13305-noderivative-inout-parameter.swift | 39 +++++++++++ .../validation-test/inout_parameters.swift | 64 +++++++++++++++++++ 3 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 test/AutoDiff/compiler_crashers_fixed/sr13305-noderivative-inout-parameter.swift create mode 100644 test/AutoDiff/validation-test/inout_parameters.swift diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 79bf388988373..60f7584418787 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -235,8 +235,25 @@ IndexSubset *SILFunctionType::getDifferentiabilityResultIndices() { resultIndices.push_back(resultAndIndex.index()); // Check `inout` parameters. for (auto inoutParamAndIndex : enumerate(getIndirectMutatingParameters())) - if (inoutParamAndIndex.value().getDifferentiability() != - SILParameterDifferentiability::NotDifferentiable) + // FIXME(TF-1305): The `getResults().empty()` condition is a hack. + // + // Currently, an `inout` parameter can either be: + // 1. Both a differentiability parameter and a differentiability result. + // 2. `@noDerivative`: neither a differentiability parameter nor a + // differentiability result. + // However, there is no way to represent an `inout` parameter that: + // 3. Is a differentiability result but not a differentiability parameter. + // 4. Is a differentiability parameter but not a differentiability result. + // This case is not currently expressible and does not yet have clear use + // cases, so supporting it is a non-goal. + // + // See TF-1305 for solution ideas. For now, `@noDerivative` `inout` + // parameters are not treated as differentiability results, unless the + // original function has no formal results, in which case all `inout` + // parameters are treated as differentiability results. + if (getResults().empty() || + inoutParamAndIndex.value().getDifferentiability() != + SILParameterDifferentiability::NotDifferentiable) resultIndices.push_back(getNumResults() + inoutParamAndIndex.index()); auto numSemanticResults = getNumResults() + getNumIndirectMutatingParameters(); @@ -432,8 +449,9 @@ static CanSILFunctionType getAutoDiffDifferentialType( } } SmallVector differentialResults; - if (inoutParamIndices->isEmpty()) { - for (auto resultIndex : resultIndices->getIndices()) { + for (auto resultIndex : resultIndices->getIndices()) { + // Handle formal original result. + if (resultIndex < originalFnTy->getNumResults()) { auto &result = originalResults[resultIndex]; auto resultTan = result.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); @@ -452,8 +470,27 @@ static CanSILFunctionType getAutoDiffDifferentialType( substReplacements.push_back(resultTanType); differentialResults.push_back({gpType, resultConv}); } + continue; } + // Handle original `inout` parameter. + auto inoutParamIndex = resultIndex - originalFnTy->getNumResults(); + auto inoutParamIt = std::next( + originalFnTy->getIndirectMutatingParameters().begin(), inoutParamIndex); + auto paramIndex = + std::distance(originalFnTy->getParameters().begin(), &*inoutParamIt); + // If the original `inout` parameter is a differentiability parameter, then + // it already has a corresponding differential parameter. Skip adding a + // corresponding differential result. + if (parameterIndices->contains(paramIndex)) + continue; + auto inoutParam = originalFnTy->getParameters()[paramIndex]; + auto paramTan = inoutParam.getInterfaceType()->getAutoDiffTangentSpace( + lookupConformance); + assert(paramTan && "Parameter type does not have a tangent space?"); + differentialResults.push_back( + {paramTan->getCanonicalType(), ResultConvention::Indirect}); } + SubstitutionMap substitutions; if (!substGenericParams.empty()) { auto genericSig = @@ -714,7 +751,9 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( CanGenericSignature derivativeFnInvocationGenSig, bool isReabstractionThunk) { assert(parameterIndices); + assert(!parameterIndices->isEmpty() && "Parameter indices must not be empty"); assert(resultIndices); + assert(!resultIndices->isEmpty() && "Result indices must not be empty"); auto &ctx = getASTContext(); // Look up result in cache. diff --git a/test/AutoDiff/compiler_crashers_fixed/sr13305-noderivative-inout-parameter.swift b/test/AutoDiff/compiler_crashers_fixed/sr13305-noderivative-inout-parameter.swift new file mode 100644 index 0000000000000..af8485e3cf224 --- /dev/null +++ b/test/AutoDiff/compiler_crashers_fixed/sr13305-noderivative-inout-parameter.swift @@ -0,0 +1,39 @@ +// RUN: %target-swift-frontend -emit-sil -verify %s +// REQUIRES: asserts + +import _Differentiation + +// SR-13305: Test protocol witness thunk for `@differentiable` protocol +// requirement, where the required method has a non-wrt `inout` parameter +// that should be treated as a differentiability result. + +protocol SR_13305_Protocol { + @differentiable(wrt: x) + func method(x: Float, y: inout Float) +} + +struct SR_13305_Struct: SR_13305_Protocol { + @differentiable(wrt: x) + func method(x: Float, y: inout Float) { + y = y * x + } +} + +// Original crash: +// Assertion failed: (!array.empty() && "claiming next from empty array!"), function claimNext, file /Users/danielzheng/swift-build/swift/lib/SILGen/SILGenPoly.cpp, line 112. +// Stack dump: +// ... +// 1. Swift version 5.3-dev (LLVM f8bd914aadc2e7b, Swift ba9c433c81d51ea) +// 2. While evaluating request ASTLoweringRequest(Lowering AST to SIL for module main) +// 3. While generating SIL witness table protocol conformance to 'SR_13305_Protocol' (at sr-13305.swift:7:1) for type 'SR_13305_Struct' (declared at [sr-13305.swift:12:1 - line:17:1] RangeText="struct SR_13305_Struct: SR_13305_Protocol { +// @differentiable(wrt: x) +// func method(x: Float, y: inout Float) { +// y = y * x +// } +// ") +// 4. While generating protocol witness thunk SIL function "@AD__$s4main15SR_13305_StructVAA0B15_13305_ProtocolA2aDP6method1x1yySf_SfztFTW_jvp_SUU". +// for 'method(x:y:)' (at sr-13305.swift:14:3) +// 5. While emitting reabstraction thunk in SIL function "@$sSfIegy_S2fIegyd_TR". +// ... +// 7 swift-frontend 0x0000000100fe80ad swift::SILResultInfo const& claimNext(llvm::ArrayRef&) + 93 +// 8 swift-frontend 0x0000000100fe6cc0 (anonymous namespace)::ResultPlanner::claimNextInnerResult((anonymous namespace)::ResultPlanner::PlanData&) + 32 diff --git a/test/AutoDiff/validation-test/inout_parameters.swift b/test/AutoDiff/validation-test/inout_parameters.swift new file mode 100644 index 0000000000000..4cbd25590b943 --- /dev/null +++ b/test/AutoDiff/validation-test/inout_parameters.swift @@ -0,0 +1,64 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import DifferentiationUnittest +import StdlibUnittest + +var InoutParameterAutoDiffTests = TestSuite("InoutParameterDifferentiation") + +// SR-13305: Test function with non-wrt `inout` parameter, which should be +// treated as a differentiability result. + +protocol SR_13305_Protocol { + @differentiable(wrt: x) + func method(_ x: Float, _ y: inout Float) + + @differentiable(wrt: x) + func genericMethod(_ x: T, _ y: inout T) +} + +InoutParameterAutoDiffTests.test("non-wrt inout parameter") { + struct SR_13305_Struct: SR_13305_Protocol { + @differentiable(wrt: x) + func method(_ x: Float, _ y: inout Float) { + y = y * x + } + + @differentiable(wrt: x) + func genericMethod(_ x: T, _ y: inout T) { + y = x + } + } + + @differentiable(wrt: x) + func foo(_ s: SR_13305_Struct, _ x: Float, _ y: Float) -> Float { + var y = y + s.method(x, &y) + return y + } + + @differentiable(wrt: x) + func fooGeneric(_ s: T, _ x: Float, _ y: Float) -> Float { + var y = y + s.method(x, &y) + return x + } + + let s = SR_13305_Struct() + + do { + let (value, (dx, dy)) = valueWithGradient(at: 2, 3, in: { foo(s, $0, $1) }) + expectEqual(6, value) + expectEqual((3, 2), (dx, dy)) + } + expectEqual((value: 6, gradient: 3), valueWithGradient(at: 2, in: { foo(s, $0, 3) })) + + do { + let (value, (dx, dy)) = valueWithGradient(at: 2, 3, in: { fooGeneric(s, $0, $1) }) + expectEqual(2, value) + expectEqual((1, 0), (dx, dy)) + } + expectEqual((value: 2, gradient: 1), valueWithGradient(at: 2, in: { fooGeneric(s, $0, 3) })) +} + +runAllTests() From 493d1025e6abd13964de8a2492c0bed4d42cb94f Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Wed, 5 Aug 2020 21:02:33 +0200 Subject: [PATCH 010/123] [Localization] Ignore diagnostic IDs that are available in YAML and not in `.def` --- lib/AST/LocalizationFormat.cpp | 19 +++++++++++++------ test/diagnostics/Localization/Inputs/en.yaml | 3 +++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/AST/LocalizationFormat.cpp b/lib/AST/LocalizationFormat.cpp index f0af4a133288a..f35029fd27fcc 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/AST/LocalizationFormat.cpp @@ -46,6 +46,10 @@ template <> struct ScalarEnumerationTraits { #define DIAG(KIND, ID, Options, Text, Signature) \ io.enumCase(value, #ID, LocalDiagID::ID); #include "swift/AST/DiagnosticsAll.def" + // Ignore diagnostic IDs that are available in the YAML file and not + // available in the `.def` file. + if (!io.outputting() && io.matchEnumFallback()) + value = LocalDiagID::NumDiags; } }; @@ -101,12 +105,15 @@ readYAML(llvm::yaml::IO &io, T &Seq, bool, Context &Ctx) { DiagnosticNode current; yamlize(io, current, true, Ctx); io.postflightElement(SaveInfo); - // YAML file isn't guaranteed to have diagnostics in order of their - // declaration in `.def` files, to accommodate that we need to leave - // holes in diagnostic array for diagnostics which haven't yet been - // localized and for the ones that have `DiagnosticNode::id` - // indicates their position. - Seq[static_cast(current.id)] = std::move(current.msg); + + if (current.id != LocalDiagID::NumDiags) { + // YAML file isn't guaranteed to have diagnostics in order of their + // declaration in `.def` files, to accommodate that we need to leave + // holes in diagnostic array for diagnostics which haven't yet been + // localized and for the ones that have `DiagnosticNode::id` + // indicates their position. + Seq[static_cast(current.id)] = std::move(current.msg); + } } } io.endSequence(); diff --git a/test/diagnostics/Localization/Inputs/en.yaml b/test/diagnostics/Localization/Inputs/en.yaml index c14e03e543519..f84a604333226 100644 --- a/test/diagnostics/Localization/Inputs/en.yaml +++ b/test/diagnostics/Localization/Inputs/en.yaml @@ -17,6 +17,9 @@ # #===----------------------------------------------------------------------===# +- id: "not_available_in_def" + msg: "Shouldn't be produced" + - id: "lex_unterminated_string" msg: "unterminated string literal" From d2cb1cac4f14b2113d279b0414a85d4c0efab5cf Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 5 Aug 2020 12:13:11 -0700 Subject: [PATCH 011/123] [Diagnostics] NFC: Adjust `en.yaml` to mirror diagnostics in `.def` files --- localization/diagnostics/en.yaml | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index 466a970fd2f1d..37fb5b6e24d9d 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -147,10 +147,10 @@ msg: >- unrecognized accessor kind '%0' in SDK node -- id: pound_source_location_creates_pound_file_conflicts +- id: source_location_creates_file_id_conflicts msg: >- - '#sourceLocation' directive produces '#file' string of '%0', which - conflicts with '#file' strings produced by other paths in the module + '#sourceLocation' directive produces '#fileID' string of '%0', which + conflicts with '#fileID' strings produced by other paths in the module - id: fixit_correct_source_location_file msg: >- @@ -1343,13 +1343,9 @@ only function declarations may be marked 'rethrows'; did you mean 'throws'? -- id: throws_in_wrong_position +- id: async_or_throws_in_wrong_position msg: >- - 'throws' may only occur before '->' - -- id: rethrows_in_wrong_position - msg: >- - 'rethrows' may only occur before '->' + %select{'throws'|'rethrows'|'async'}0 may only occur before '->' - id: throw_in_function_type msg: >- @@ -7132,14 +7128,6 @@ %0 is not a 'func', 'init', 'subscript', or 'var' computed property declaration -- id: autodiff_attr_accessor_not_found - msg: >- - %0 does not have a '%1' accessor - -- id: autodiff_attr_original_decl_none_valid_found - msg: >- - could not find function %0 with expected type %1 - - id: autodiff_attr_original_decl_not_same_type_context msg: >- %0 is not defined in the current type context From 55c2e01838fc265716d5da8859c4640c1f00102e Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Wed, 5 Aug 2020 21:59:21 +0200 Subject: [PATCH 012/123] [Localization] Add comments --- lib/AST/LocalizationFormat.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/AST/LocalizationFormat.cpp b/lib/AST/LocalizationFormat.cpp index f35029fd27fcc..bf08c5110ebb3 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/AST/LocalizationFormat.cpp @@ -48,7 +48,7 @@ template <> struct ScalarEnumerationTraits { #include "swift/AST/DiagnosticsAll.def" // Ignore diagnostic IDs that are available in the YAML file and not // available in the `.def` file. - if (!io.outputting() && io.matchEnumFallback()) + if (io.matchEnumFallback()) value = LocalDiagID::NumDiags; } }; @@ -106,6 +106,10 @@ readYAML(llvm::yaml::IO &io, T &Seq, bool, Context &Ctx) { yamlize(io, current, true, Ctx); io.postflightElement(SaveInfo); + // A diagnostic ID might be present in YAML and not in `.def` file, + // if that's the case ScalarEnumerationTraits will assign the diagnostic ID + // to `LocalDiagID::NumDiags`. Since the diagnostic ID isn't available + // in `.def` it shouldn't be stored in the diagnostics array. if (current.id != LocalDiagID::NumDiags) { // YAML file isn't guaranteed to have diagnostics in order of their // declaration in `.def` files, to accommodate that we need to leave From ef6c37451606514ed4a64052c0785372e5ddcbee Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Fri, 31 Jul 2020 17:11:23 -0700 Subject: [PATCH 013/123] [Sema/Index] Resolve #keyPath components so they can be indexed Unlike \keypath expressions, only the property components of #keypath expressions were being resolved, so index wouldn't pick up references for their qualifying types. Also fixes a code completion bug where it was reporting members from the Swift rather than ObjC side of bridged types. Resolves rdar://problem/61573935 --- include/swift/AST/Expr.h | 18 ++++++++ lib/AST/ASTDumper.cpp | 5 +++ lib/AST/ASTWalker.cpp | 1 + lib/AST/Expr.cpp | 1 + lib/IDE/SourceEntityWalker.cpp | 1 + lib/SILGen/SILGenExpr.cpp | 5 +++ lib/Sema/CSApply.cpp | 10 ++++- lib/Sema/CSGen.cpp | 3 ++ lib/Sema/CSSimplify.cpp | 3 ++ lib/Sema/ConstraintSystem.cpp | 1 + lib/Sema/TypeCheckAvailability.cpp | 1 + lib/Sema/TypeCheckCodeCompletion.cpp | 18 ++++++-- lib/Sema/TypeCheckExprObjC.cpp | 22 ++++++++-- test/IDE/complete_pound_keypath.swift | 44 +++++++++++++++++++- test/Index/index_keypaths.swift | 38 +++++++++++++---- test/expr/primary/keypath/keypath-objc.swift | 14 +++---- 16 files changed, 160 insertions(+), 25 deletions(-) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index a62c045674a18..0b022d4a26790 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -5259,6 +5259,7 @@ class KeyPathExpr : public Expr { OptionalWrap, Identity, TupleElement, + DictionaryKey, }; private: @@ -5367,6 +5368,16 @@ class KeyPathExpr : public Expr { propertyType, loc); } + + /// Create a component for a dictionary key (#keyPath only). + static Component forDictionaryKey(DeclNameRef UnresolvedName, + Type valueType, + SourceLoc loc) { + return Component(nullptr, UnresolvedName, nullptr, {}, {}, + Kind::DictionaryKey, + valueType, + loc); + } /// Create a component for a subscript. static Component forSubscript(ASTContext &ctx, @@ -5457,6 +5468,7 @@ class KeyPathExpr : public Expr { case Kind::Property: case Kind::Identity: case Kind::TupleElement: + case Kind::DictionaryKey: return true; case Kind::UnresolvedSubscript: @@ -5481,6 +5493,7 @@ class KeyPathExpr : public Expr { case Kind::Property: case Kind::Identity: case Kind::TupleElement: + case Kind::DictionaryKey: return nullptr; } llvm_unreachable("unhandled kind"); @@ -5500,6 +5513,7 @@ class KeyPathExpr : public Expr { case Kind::Property: case Kind::Identity: case Kind::TupleElement: + case Kind::DictionaryKey: llvm_unreachable("no subscript labels for this kind"); } llvm_unreachable("unhandled kind"); @@ -5522,6 +5536,7 @@ class KeyPathExpr : public Expr { case Kind::Property: case Kind::Identity: case Kind::TupleElement: + case Kind::DictionaryKey: return {}; } llvm_unreachable("unhandled kind"); @@ -5533,6 +5548,7 @@ class KeyPathExpr : public Expr { DeclNameRef getUnresolvedDeclName() const { switch (getKind()) { case Kind::UnresolvedProperty: + case Kind::DictionaryKey: return Decl.UnresolvedName; case Kind::Invalid: @@ -5563,6 +5579,7 @@ class KeyPathExpr : public Expr { case Kind::OptionalForce: case Kind::Identity: case Kind::TupleElement: + case Kind::DictionaryKey: llvm_unreachable("no decl ref for this kind"); } llvm_unreachable("unhandled kind"); @@ -5582,6 +5599,7 @@ class KeyPathExpr : public Expr { case Kind::Identity: case Kind::Property: case Kind::Subscript: + case Kind::DictionaryKey: llvm_unreachable("no field number for this kind"); } llvm_unreachable("unhandled kind"); diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 94e6654c5562b..fdaa58eca8207 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2829,6 +2829,11 @@ class PrintExpr : public ExprVisitor { PrintWithColorRAII(OS, DiscriminatorColor) << "#" << component.getTupleIndex(); break; + case KeyPathExpr::Component::Kind::DictionaryKey: + PrintWithColorRAII(OS, ASTNodeColor) << "dict_key"; + PrintWithColorRAII(OS, IdentifierColor) + << " key='" << component.getUnresolvedDeclName() << "'"; + break; } PrintWithColorRAII(OS, TypeColor) << " type='" << GetTypeOfKeyPathComponent(E, i) << "'"; diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 6c6726c2c0225..3641f7c807627 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -1133,6 +1133,7 @@ class Traversal : public ASTVisitor SemaAnnotator::walkToExprPre(Expr *E) { case KeyPathExpr::Component::Kind::OptionalWrap: case KeyPathExpr::Component::Kind::OptionalForce: case KeyPathExpr::Component::Kind::Identity: + case KeyPathExpr::Component::Kind::DictionaryKey: break; } } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 6b524fe06a9d2..cb8273d129e1e 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -3734,6 +3734,11 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) { case KeyPathExpr::Component::Kind::UnresolvedProperty: case KeyPathExpr::Component::Kind::UnresolvedSubscript: llvm_unreachable("not resolved"); + break; + + case KeyPathExpr::Component::Kind::DictionaryKey: + llvm_unreachable("DictionaryKey only valid in #keyPath"); + break; } } diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index dbdd3217b3e72..c24f5b0eeac43 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -237,6 +237,9 @@ static bool buildObjCKeyPathString(KeyPathExpr *E, // Don't bother building the key path string if the key path didn't even // resolve. return false; + case KeyPathExpr::Component::Kind::DictionaryKey: + llvm_unreachable("DictionaryKey only valid in #keyPath expressions."); + return false; } } @@ -4690,6 +4693,10 @@ namespace { case KeyPathExpr::Component::Kind::OptionalWrap: case KeyPathExpr::Component::Kind::TupleElement: llvm_unreachable("already resolved"); + break; + case KeyPathExpr::Component::Kind::DictionaryKey: + llvm_unreachable("DictionaryKey only valid in #keyPath"); + break; } // Update "componentTy" with the result type of the last component. @@ -7745,9 +7752,8 @@ namespace { componentType = solution.simplifyType(cs.getType(kp, i)); assert(!componentType->hasTypeVariable() && "Should not write type variable into key-path component"); + kp->getMutableComponents()[i].setComponentType(componentType); } - - kp->getMutableComponents()[i].setComponentType(componentType); } } diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index e7ff79903d2f5..d4784d0633703 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3487,6 +3487,9 @@ namespace { } case KeyPathExpr::Component::Kind::Identity: continue; + case KeyPathExpr::Component::Kind::DictionaryKey: + llvm_unreachable("DictionaryKey only valid in #keyPath"); + break; } // By now, `base` is the result type of this component. Set it in the diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index b85e02d509480..03d95d6bbcba6 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -8242,6 +8242,9 @@ ConstraintSystem::simplifyKeyPathConstraint( case KeyPathExpr::Component::Kind::TupleElement: llvm_unreachable("not implemented"); break; + case KeyPathExpr::Component::Kind::DictionaryKey: + llvm_unreachable("DictionaryKey only valid in #keyPath"); + break; } } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index e302206c9dd0e..1214740c8d1d5 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -493,6 +493,7 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator( case ComponentKind::OptionalChain: case ComponentKind::OptionalWrap: case ComponentKind::Identity: + case ComponentKind::DictionaryKey: // These components don't have any callee associated, so just continue. break; } diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 88661330d3ffb..b2f41c94c6a37 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -2522,6 +2522,7 @@ class AvailabilityWalker : public ASTWalker { case KeyPathExpr::Component::Kind::OptionalWrap: case KeyPathExpr::Component::Kind::OptionalForce: case KeyPathExpr::Component::Kind::Identity: + case KeyPathExpr::Component::Kind::DictionaryKey: break; } } diff --git a/lib/Sema/TypeCheckCodeCompletion.cpp b/lib/Sema/TypeCheckCodeCompletion.cpp index bb4470cca9c86..b40af172a2cd5 100644 --- a/lib/Sema/TypeCheckCodeCompletion.cpp +++ b/lib/Sema/TypeCheckCodeCompletion.cpp @@ -621,9 +621,21 @@ static Optional getTypeOfCompletionContextExpr( case CompletionTypeCheckKind::KeyPath: referencedDecl = nullptr; - if (auto keyPath = dyn_cast(parsedExpr)) - return TypeChecker::checkObjCKeyPathExpr(DC, keyPath, - /*requireResultType=*/true); + if (auto keyPath = dyn_cast(parsedExpr)) { + auto components = keyPath->getComponents(); + if (!components.empty()) { + auto &last = components.back(); + if (last.isResolved()) { + if (last.getKind() == KeyPathExpr::Component::Kind::Property) + referencedDecl = last.getDeclRef(); + Type lookupTy = last.getComponentType(); + ASTContext &Ctx = DC->getASTContext(); + if (auto bridgedClass = Ctx.getBridgedToObjC(DC, lookupTy)) + return bridgedClass; + return lookupTy; + } + } + } return None; } diff --git a/lib/Sema/TypeCheckExprObjC.cpp b/lib/Sema/TypeCheckExprObjC.cpp index 8fcd77a4de05c..324e044ce1a75 100644 --- a/lib/Sema/TypeCheckExprObjC.cpp +++ b/lib/Sema/TypeCheckExprObjC.cpp @@ -221,6 +221,7 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, case KeyPathExpr::Component::Kind::OptionalWrap: case KeyPathExpr::Component::Kind::Property: case KeyPathExpr::Component::Kind::Subscript: + case KeyPathExpr::Component::Kind::DictionaryKey: llvm_unreachable("already resolved!"); } @@ -241,6 +242,9 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, // From here, we're resolving a property. Use the current type. updateState(/*isProperty=*/true, currentType); + auto resolved = KeyPathExpr::Component:: + forDictionaryKey(componentName, currentType, componentNameLoc); + resolvedComponents.push_back(resolved); continue; } @@ -321,10 +325,14 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, if (auto var = dyn_cast(found)) { // Resolve this component to the variable we found. auto varRef = ConcreteDeclRef(var); - auto resolved = - KeyPathExpr::Component::forProperty(varRef, Type(), componentNameLoc); + Type varTy = var->getInterfaceType(); + + // Updates currentType + updateState(/*isProperty=*/true, varTy); + + auto resolved = KeyPathExpr::Component::forProperty(varRef, currentType, + componentNameLoc); resolvedComponents.push_back(resolved); - updateState(/*isProperty=*/true, var->getInterfaceType()); // Check that the property is @objc. if (!var->isObjC()) { @@ -390,7 +398,15 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, break; } + // Updates currentType based on newType. updateState(/*isProperty=*/false, newType); + + // Resolve this component to the type we found. + auto typeRef = ConcreteDeclRef(type); + auto resolved = KeyPathExpr::Component::forProperty(typeRef, currentType, + componentNameLoc); + resolvedComponents.push_back(resolved); + continue; } diff --git a/test/IDE/complete_pound_keypath.swift b/test/IDE/complete_pound_keypath.swift index 8a7b84ced7f67..6dc428a36344a 100644 --- a/test/IDE/complete_pound_keypath.swift +++ b/test/IDE/complete_pound_keypath.swift @@ -6,6 +6,16 @@ // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_2 | %FileCheck -check-prefix=CHECK-IN_KEYPATH %s +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_3 | %FileCheck -check-prefix=CHECK-IN_KEYPATH_BRIDGED_STRING %s + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_4 | %FileCheck -check-prefix=CHECK-IN_KEYPATH_BRIDGED_STRING %s + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_5 | %FileCheck -check-prefixes=CHECK-IN_KEYPATH,CHECK-IN_KEYPATH_OPT %s + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_6 | %FileCheck -check-prefixes=CHECK-IN_KEYPATH,CHECK-IN_KEYPATH_OPT %s + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_7 | %FileCheck -check-prefixes=CHECK-IN_KEYPATH_BRIDGED_STRING %s + // REQUIRES: objc_interop @@ -21,9 +31,11 @@ func selectorArg1(obj: NSObject) { acceptKeyPath(#^KEYPATH_ARG^# } -class ObjCClass : NSObject { +@objcMembers class ObjCClass : NSObject { var prop1: String = "" var prop2: ObjCClass? + var prop3: [ObjCClass]? = [] + var prop4: [String: String] = [:] func completeInKeyPath1() { _ = #keyPath(#^IN_KEYPATH_1^# @@ -34,12 +46,42 @@ func completeInKeyPath2() { _ = #keyPath(ObjCClass.#^IN_KEYPATH_2^# } +func completeInKeyPath3() { + _ = #keyPath(ObjCClass.prop1.#^IN_KEYPATH_3^# +} +func completeInKeyPath3() { + _ = #keyPath(String.#^IN_KEYPATH_4^# +} + +func completeInKeyPath4() { + _ = #keyPath(ObjCClass.prop2.#^IN_KEYPATH_5^# +} + +func completeInKeyPath5() { + _ = #keyPath(ObjCClass.prop3.#^IN_KEYPATH_6^# +} + +func completeInKeyPath6() { + _ = #keyPath(ObjCClass.prop4.anythingHere.#^IN_KEYPATH_7^# +} + // CHECK-AFTER_POUND-NOT: keyPath // CHECK-KEYPATH_ARG: Keyword/None/TypeRelation[Identical]: #keyPath({#@objc property sequence#})[#String#]; name=#keyPath(@objc property sequence) // CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop1[#String#]; name=prop1 // CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop2[#ObjCClass?#]; name=prop2 +// CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop3[#[ObjCClass]?#]; name=prop3 // CHECK-IN_KEYPATH: Decl[InstanceVar]/Super: hashValue[#Int#]; name=hashValue +// Make sure we unwrap optionals (members of Optional itself are invalid in this context) +// +// CHECK-IN_KEYPATH_OPT-NOT: name=map + +// Make sure we handle bridged types (i.e. show NSString members rather than String members) +// +// CHECK-IN_KEYPATH_BRIDGED_STRING: Decl[InstanceVar]/CurrNominal/IsSystem: urlsInText[#[URL]#]; name=urlsInText +// CHECK-IN_KEYPATH_BRIDGED_STRING: Decl[InstanceVar]/CurrNominal/IsSystem: uppercased[#String!#]; name=uppercased +// CHECK-IN_KEYPATH_BRIDGED_STRING-NOT: name=count + diff --git a/test/Index/index_keypaths.swift b/test/Index/index_keypaths.swift index 2405032541afa..96b8d367934bb 100644 --- a/test/Index/index_keypaths.swift +++ b/test/Index/index_keypaths.swift @@ -1,27 +1,47 @@ -// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %s | %FileCheck %s +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -print-indexed-symbols -source-filename %s | %FileCheck %s // REQUIRES: objc_interop +import Foundation + struct MyStruct { struct Inner { let myProp = 1 } } -class MyClass { - class Inner { - @objc var myProp = 1 - } -} - let a = \MyStruct.Inner.myProp // CHECK: [[@LINE-1]]:25 | {{.*}} | myProp // CHECK: [[@LINE-2]]:10 | {{.*}} | MyStruct // CHECK: [[@LINE-3]]:19 | {{.*}} | Inner let b: KeyPath = \.myProp // CHECK: [[@LINE-1]]:41 | {{.*}} | myProp -let c = \MyClass.Inner.myProp + +@objc class MyClass: NSObject { + @objc class Inner: NSObject { + @objc var myProp = 1 + @objc var otherProp:[String: MyClass.Inner] = [:] + func method() { + let c: String = #keyPath(myProp) + // CHECK: [[@LINE-1]]:32 | {{.*}} | myProp + } + } +} + +let d: String = #keyPath(MyClass.Inner.myProp) +// CHECK: [[@LINE-1]]:26 | {{.*}} | MyClass +// CHECK: [[@LINE-2]]:34 | {{.*}} | Inner +// CHECK: [[@LINE-3]]:40 | {{.*}} | myProp + +let e = \MyClass.Inner.myProp // CHECK: [[@LINE-1]]:24 | {{.*}} | myProp // CHECK: [[@LINE-2]]:10 | {{.*}} | MyClass // CHECK: [[@LINE-3]]:18 | {{.*}} | Inner -let d: KeyPath = \.myProp + +let f: KeyPath = \.myProp // CHECK: [[@LINE-1]]:40 | {{.*}} | myProp + +let g: String = #keyPath(MyClass.Inner.otherProp.someDictKey.myProp) +// CHECK: [[@LINE-1]]:26 | {{.*}} | MyClass +// CHECK: [[@LINE-2]]:34 | {{.*}} | Inner +// CHECK: [[@LINE-3]]:40 | {{.*}} | otherProp +// CHECK: [[@LINE-4]]:62 | {{.*}} | myProp diff --git a/test/expr/primary/keypath/keypath-objc.swift b/test/expr/primary/keypath/keypath-objc.swift index 8f381e92fe925..2a4fa881403b7 100644 --- a/test/expr/primary/keypath/keypath-objc.swift +++ b/test/expr/primary/keypath/keypath-objc.swift @@ -57,7 +57,7 @@ func testKeyPath(a: A, b: B) { let _: String = #keyPath(A.propString) // Property of String property (which looks on NSString) - let _: String = #keyPath(A.propString.URLsInText) + let _: String = #keyPath(A.propString.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} // String property with a suffix let _: String = #keyPath(A.propString).description @@ -72,7 +72,7 @@ func testKeyPath(a: A, b: B) { // Array property (make sure we look at the array element). let _: String = #keyPath(A.propArray) - let _: String = #keyPath(A.propArray.URLsInText) + let _: String = #keyPath(A.propArray.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} // Dictionary property (make sure we look at the value type). let _: String = #keyPath(A.propDict.anyKeyName) @@ -80,20 +80,20 @@ func testKeyPath(a: A, b: B) { // Set property (make sure we look at the set element). let _: String = #keyPath(A.propSet) - let _: String = #keyPath(A.propSet.URLsInText) + let _: String = #keyPath(A.propSet.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} // AnyObject property - let _: String = #keyPath(A.propAnyObject.URLsInText) + let _: String = #keyPath(A.propAnyObject.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} let _: String = #keyPath(A.propAnyObject.propA) let _: String = #keyPath(A.propAnyObject.propB) let _: String = #keyPath(A.propAnyObject.description) // NSString property - let _: String = #keyPath(A.propNSString.URLsInText) + let _: String = #keyPath(A.propNSString.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} // NSArray property (AnyObject array element). let _: String = #keyPath(A.propNSArray) - let _: String = #keyPath(A.propNSArray.URLsInText) + let _: String = #keyPath(A.propNSArray.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} // NSDictionary property (AnyObject value type). let _: String = #keyPath(A.propNSDict.anyKeyName) @@ -101,7 +101,7 @@ func testKeyPath(a: A, b: B) { // NSSet property (AnyObject set element). let _: String = #keyPath(A.propNSSet) - let _: String = #keyPath(A.propNSSet.URLsInText) + let _: String = #keyPath(A.propNSSet.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} // Property with keyword name. let _: String = #keyPath(A.repeat) From a84cf7f9e8a01dabf931d390ecf4a74b54b067cb Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Mon, 27 Jul 2020 12:18:47 +0200 Subject: [PATCH 014/123] [Locale] Serialize YAML to an OnDiskHashTable format and create a tool for serialization --- include/swift/AST/DiagnosticEngine.h | 23 ++- include/swift/AST/LocalizationFormat.h | 150 +++++++++++++++++- lib/AST/LocalizationFormat.cpp | 64 ++++++-- localization/CMakeLists.txt | 4 + .../Localization/fr_localization.swift | 5 +- tools/CMakeLists.txt | 1 + .../CMakeLists.txt | 7 + .../swift-serialize-diagnostics.cpp | 84 ++++++++++ 8 files changed, 321 insertions(+), 17 deletions(-) create mode 100644 tools/swift-serialize-diagnostics/CMakeLists.txt create mode 100644 tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index ef9160641981e..682cb8e34246b 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -24,6 +24,7 @@ #include "swift/AST/TypeLoc.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Path.h" #include "llvm/Support/VersionTuple.h" namespace swift { @@ -742,8 +743,26 @@ namespace swift { void setLocalization(std::string locale, std::string path) { assert(!locale.empty()); assert(!path.empty()); - localization = - std::make_unique(locale, path); + llvm::SmallString<128> filePath(path); + llvm::sys::path::append(filePath, locale); + llvm::sys::path::replace_extension(filePath, ".db"); + + // If the serialized diagnostics file not available, + // fallback to the `YAML` file. + if (llvm::sys::fs::exists(filePath)) { + if (auto file = llvm::MemoryBuffer::getFile(filePath)) { + localization = std::make_unique( + std::move(file.get())); + } + } else { + llvm::sys::path::replace_extension(filePath, ".yaml"); + // In case of missing localization files, we should fallback to messages + // from `.def` files. + if (llvm::sys::fs::exists(filePath)) { + localization = + std::make_unique(filePath.str()); + } + } } void ignoreDiagnostic(DiagID id) { diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/AST/LocalizationFormat.h index a4205bb85be72..d2ac1dec5affc 100644 --- a/include/swift/AST/LocalizationFormat.h +++ b/include/swift/AST/LocalizationFormat.h @@ -1,5 +1,4 @@ -//===--- LocalizationFormat.h - YAML format for Diagnostic Messages ---*- -// C++ -*-===// +//===--- LocalizationFormat.h - Format for Diagnostic Messages --*- C++ -*-===// // // This source file is part of the Swift.org open source project // @@ -19,6 +18,10 @@ #define SWIFT_LOCALIZATIONFORMAT_H #include "llvm/ADT/StringRef.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Support/DJB.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/OnDiskHashTable.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" #include @@ -28,6 +31,101 @@ namespace swift { enum class DiagID : uint32_t; namespace diag { +using namespace llvm::support; + +class LocalizationWriterInfo { +public: + using key_type = llvm::StringRef; + using key_type_ref = key_type; + using data_type = llvm::StringRef; + using data_type_ref = data_type; + using hash_value_type = uint32_t; + using offset_type = uint32_t; + + hash_value_type ComputeHash(key_type_ref key) { return llvm::djbHash(key); } + + std::pair EmitKeyDataLength(llvm::raw_ostream &out, + key_type_ref key, + data_type_ref data) { + offset_type keyLength = static_cast(key.size()); + offset_type dataLength = static_cast(data.size()); + endian::write(out, keyLength, little); + endian::write(out, dataLength, little); + return {keyLength, dataLength}; + } + + void EmitKey(llvm::raw_ostream &out, key_type_ref key, unsigned len) { + out << key; + } + + void EmitData(llvm::raw_ostream &out, key_type_ref key, data_type_ref data, + unsigned len) { + out << data; + } +}; + +class LocalizationReaderInfo { +public: + using internal_key_type = llvm::StringRef; + using external_key_type = internal_key_type; + using data_type = llvm::StringRef; + using hash_value_type = uint32_t; + using offset_type = uint32_t; + + internal_key_type GetInternalKey(external_key_type key) { return key; } + + external_key_type GetExternalKey(internal_key_type key) { return key; } + + static bool EqualKey(internal_key_type lhs, internal_key_type rhs) { + return lhs == rhs; + } + + hash_value_type ComputeHash(internal_key_type key) { + return llvm::djbHash(key); + } + + static std::pair ReadKeyDataLength(const uint8_t *&data) { + offset_type keyLength = + endian::readNext(data); + offset_type dataLength = + endian::readNext(data); + return {keyLength, dataLength}; + } + + internal_key_type ReadKey(const uint8_t *data, offset_type length) { + return internal_key_type((const char *)data, length); + } + + data_type ReadData(llvm::StringRef Key, const uint8_t *data, + offset_type length) { + return data_type((const char *)data, length); + } +}; + +class SerializedLocalizationWriter { + using offset_type = LocalizationWriterInfo::offset_type; + llvm::OnDiskChainedHashTableGenerator generator; + +public: + /// Enqueue the given diagnostic to be included in a serialized translations + /// file. + /// + /// \param id The identifier associated with the given diagnostic message e.g. + /// 'cannot_convert_argument'. + /// \param translation The localized diagnostic + /// message for the given identifier. + void insert(llvm::StringRef id, llvm::StringRef translation); + + /// Write out previously inserted diagnostic translations into the given + /// location. + /// + /// \param filePath The location of the serialized diagnostics file. It's + /// supposed to be a file with '.db' postfix. + /// \returns true if all diagnostic + /// messages have been successfully serialized, false otherwise. + bool emit(llvm::StringRef filePath); +}; + class LocalizationProducer { public: /// If the message isn't available/localized in the current `yaml` file, @@ -41,9 +139,55 @@ class LocalizationProducer { }; class YAMLLocalizationProducer final : public LocalizationProducer { + // Type of the `diagnostics` vector. + using T = std::vector; + struct Node { + uint32_t id; + typename T::value_type &msg; + }; + typedef Node value_type; + + class iterator { + typename T::iterator it; + uint32_t counter; + + public: + iterator(T::iterator _it, uint32_t counter = 0) + : it(_it), counter(counter) {} + + iterator operator++() { return iterator(++it, ++counter); } + + bool operator!=(iterator other) { return it != other.it; } + + typename T::iterator::value_type node() { return *it; } + + value_type operator*() { return value_type{counter, *it}; } + + uint32_t index() { return counter; } + }; + public: std::vector diagnostics; - explicit YAMLLocalizationProducer(std::string locale, std::string path); + explicit YAMLLocalizationProducer(llvm::StringRef filePath); + llvm::StringRef getMessageOr(swift::DiagID id, + llvm::StringRef defaultMessage) const override; + + iterator begin() { return iterator(diagnostics.begin()); } + + iterator end() { return iterator(diagnostics.end()); } +}; + +class SerializedLocalizationProducer final : public LocalizationProducer { + using SerializedLocalizationTable = + llvm::OnDiskIterableChainedHashTable; + using offset_type = LocalizationReaderInfo::offset_type; + std::unique_ptr Buffer; + std::unique_ptr SerializedTable; + +public: + explicit SerializedLocalizationProducer( + std::unique_ptr buffer); + llvm::StringRef getMessageOr(swift::DiagID id, llvm::StringRef defaultMessage) const override; }; diff --git a/lib/AST/LocalizationFormat.cpp b/lib/AST/LocalizationFormat.cpp index bf08c5110ebb3..767f2985a3374 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/AST/LocalizationFormat.cpp @@ -1,5 +1,4 @@ -//===--- LocalizationFormat.cpp - YAML format for Diagnostic Messages ---*- -// C++ -*-===// +//===-- LocalizationFormat.cpp - Format for Diagnostic Messages -*- C++ -*-===// // // This source file is part of the Swift.org open source project // @@ -18,6 +17,7 @@ #include "swift/AST/LocalizationFormat.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLParser.h" @@ -32,6 +32,11 @@ enum LocalDiagID : uint32_t { NumDiags }; +static constexpr const char *const diagnosticID[] = { +#define DIAG(KIND, ID, Options, Text, Signature) #ID, +#include "swift/AST/DiagnosticsAll.def" +}; + struct DiagnosticNode { uint32_t id; std::string msg; @@ -68,15 +73,52 @@ template <> struct MappingTraits { namespace swift { namespace diag { -YAMLLocalizationProducer::YAMLLocalizationProducer(std::string locale, - std::string path) { - llvm::SmallString<128> DiagnosticsFilePath(path); - llvm::sys::path::append(DiagnosticsFilePath, locale); - llvm::sys::path::replace_extension(DiagnosticsFilePath, ".yaml"); - auto FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(DiagnosticsFilePath); - // Absence of localizations shouldn't crash the compiler. - if (!FileBufOrErr) - return; +void SerializedLocalizationWriter::insert(llvm::StringRef id, + llvm::StringRef translation) { + generator.insert(id, translation); +} + +bool SerializedLocalizationWriter::emit(llvm::StringRef filePath) { + assert(llvm::sys::path::extension(filePath) == ".db"); + std::error_code error; + llvm::raw_fd_ostream OS(filePath, error, llvm::sys::fs::F_None); + if (OS.has_error()) { + return true; + } + + offset_type offset; + { + llvm::support::endian::write(OS, 0, llvm::support::little); + offset = generator.Emit(OS); + } + OS.seek(0); + llvm::support::endian::write(OS, offset, llvm::support::little); + OS.close(); + + return OS.has_error(); +} + +SerializedLocalizationProducer::SerializedLocalizationProducer( + std::unique_ptr buffer) + : Buffer(std::move(buffer)) { + auto base = reinterpret_cast(Buffer.get()->getBufferStart()); + auto tableOffset = endian::read(base, little); + SerializedTable.reset(SerializedLocalizationTable::Create( + base + tableOffset, base + sizeof(offset_type), base)); +} + +llvm::StringRef SerializedLocalizationProducer::getMessageOr( + swift::DiagID id, llvm::StringRef defaultMessage) const { + auto value = SerializedTable.get()->find(diagnosticID[(unsigned)id]); + llvm::StringRef diagnosticMessage((const char *)value.getDataPtr(), + value.getDataLen()); + if (diagnosticMessage.empty()) + return defaultMessage; + return diagnosticMessage; +} + +YAMLLocalizationProducer::YAMLLocalizationProducer(llvm::StringRef filePath) { + auto FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(filePath); llvm::MemoryBuffer *document = FileBufOrErr->get(); diag::LocalizationInput yin(document->getBuffer()); yin >> diagnostics; diff --git a/localization/CMakeLists.txt b/localization/CMakeLists.txt index 8ef1584ac29b6..c8359ce027c7b 100644 --- a/localization/CMakeLists.txt +++ b/localization/CMakeLists.txt @@ -6,6 +6,10 @@ add_custom_command( DEPENDS diagnostics COMMAND "${CMAKE_COMMAND}" -E copy_directory diagnostics/ "${SWIFT_BINARY_DIR}/share/swift/diagnostics/") +add_custom_command( + TARGET diagnostic-translation-database + COMMAND swift-serialize-diagnostics --input-file-path="${SWIFT_BINARY_DIR}/share/swift/diagnostics/en.yaml" --output-directory="${SWIFT_BINARY_DIR}/share/swift/diagnostics/") + add_dependencies(swift-frontend diagnostic-translation-database) swift_install_in_component( diff --git a/test/diagnostics/Localization/fr_localization.swift b/test/diagnostics/Localization/fr_localization.swift index 50db4c8e33206..27d8e29f8cda9 100644 --- a/test/diagnostics/Localization/fr_localization.swift +++ b/test/diagnostics/Localization/fr_localization.swift @@ -1,4 +1,7 @@ -// RUN: %target-typecheck-verify-swift -localization-path %S/Inputs -locale fr +// RUN: %empty-directory(%t) +// RUN: swift-serialize-diagnostics --input-file-path=%S/Inputs/fr.yaml --output-directory=%t/ +// RUN: swift-serialize-diagnostics --input-file-path=%S/Inputs/en.yaml --output-directory=%t/ +// RUN: %target-typecheck-verify-swift -localization-path %t -locale fr _ = "HI! // expected-error@-1{{chaîne non terminée littérale}} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 8eafc0873899b..08a4083abdf15 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -22,6 +22,7 @@ add_swift_tool_subdirectory(swift-ide-test) add_swift_tool_subdirectory(swift-remoteast-test) add_swift_tool_subdirectory(swift-demangle) add_swift_tool_subdirectory(swift-demangle-yamldump) +add_swift_tool_subdirectory(swift-serialize-diagnostics) add_swift_tool_subdirectory(lldb-moduleimport-test) add_swift_tool_subdirectory(sil-func-extractor) add_swift_tool_subdirectory(sil-llvm-gen) diff --git a/tools/swift-serialize-diagnostics/CMakeLists.txt b/tools/swift-serialize-diagnostics/CMakeLists.txt new file mode 100644 index 0000000000000..13cf756c13c49 --- /dev/null +++ b/tools/swift-serialize-diagnostics/CMakeLists.txt @@ -0,0 +1,7 @@ +add_swift_host_tool(swift-serialize-diagnostics + swift-serialize-diagnostics.cpp + SWIFT_COMPONENT tools +) +target_link_libraries(swift-serialize-diagnostics + PRIVATE + swiftAST) diff --git a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp new file mode 100644 index 0000000000000..eb63112e722de --- /dev/null +++ b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp @@ -0,0 +1,84 @@ +//===--- swift-serialize-diagnostics.cpp ----------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Convert localization YAML files to a srialized format. +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/LocalizationFormat.h" +#include "swift/Basic/LLVMInitialize.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/YAMLParser.h" +#include "llvm/Support/YAMLTraits.h" + +using namespace swift; +using namespace swift::diag; + +namespace { +static constexpr const char *const diagnosticID[] = { +#define DIAG(KIND, ID, Options, Text, Signature) #ID, +#include "swift/AST/DiagnosticsAll.def" +}; +} // namespace + +namespace options { + +static llvm::cl::OptionCategory Category("swift-serialize-diagnostics Options"); + +static llvm::cl::opt + InputFilePath("input-file-path", + llvm::cl::desc("Path to the YAML input file"), + llvm::cl::cat(Category)); + +static llvm::cl::opt + OutputDirectory("output-directory", + llvm::cl::desc("Directory for the output file"), + llvm::cl::cat(Category)); + +} // namespace options + +int main(int argc, char *argv[]) { + PROGRAM_START(argc, argv); + INITIALIZE_LLVM(); + + llvm::cl::HideUnrelatedOptions(options::Category); + llvm::cl::ParseCommandLineOptions(argc, argv, + "Swift Serialize Diagnostics Tool\n"); + + if (!llvm::sys::fs::exists(options::InputFilePath)) { + llvm::errs() << "YAML file not found\n"; + return 1; + } + + YAMLLocalizationProducer yaml(options::InputFilePath); + + auto localeCode = llvm::sys::path::filename(options::InputFilePath); + llvm::SmallString<128> SerializedFilePath(options::OutputDirectory); + llvm::sys::path::append(SerializedFilePath, localeCode); + llvm::sys::path::replace_extension(SerializedFilePath, ".db"); + + SerializedLocalizationWriter Serializer; + for (const auto translation : yaml) { + Serializer.insert(diagnosticID[translation.id], translation.msg); + } + + if (Serializer.emit(SerializedFilePath.str())) { + llvm::errs() << "Cannot serialize diagnostic file " + << options::InputFilePath << '\n'; + return 1; + } + + return 0; +} From 8ee4e93f97376fa98cbbc58757fb3a0206ab1c5f Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 29 Jul 2020 16:39:19 -0700 Subject: [PATCH 015/123] [Localization] Simplify implementation of iterator over YAML --- include/swift/AST/LocalizationFormat.h | 37 ++++--------------- lib/AST/LocalizationFormat.cpp | 10 +++++ .../swift-serialize-diagnostics.cpp | 7 ++-- 3 files changed, 21 insertions(+), 33 deletions(-) diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/AST/LocalizationFormat.h index d2ac1dec5affc..8bd4885b72745 100644 --- a/include/swift/AST/LocalizationFormat.h +++ b/include/swift/AST/LocalizationFormat.h @@ -17,6 +17,7 @@ #ifndef SWIFT_LOCALIZATIONFORMAT_H #define SWIFT_LOCALIZATIONFORMAT_H +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/DJB.h" @@ -139,42 +140,18 @@ class LocalizationProducer { }; class YAMLLocalizationProducer final : public LocalizationProducer { - // Type of the `diagnostics` vector. - using T = std::vector; - struct Node { - uint32_t id; - typename T::value_type &msg; - }; - typedef Node value_type; - - class iterator { - typename T::iterator it; - uint32_t counter; - - public: - iterator(T::iterator _it, uint32_t counter = 0) - : it(_it), counter(counter) {} - - iterator operator++() { return iterator(++it, ++counter); } - - bool operator!=(iterator other) { return it != other.it; } - - typename T::iterator::value_type node() { return *it; } - - value_type operator*() { return value_type{counter, *it}; } - - uint32_t index() { return counter; } - }; + std::vector diagnostics; public: - std::vector diagnostics; explicit YAMLLocalizationProducer(llvm::StringRef filePath); llvm::StringRef getMessageOr(swift::DiagID id, llvm::StringRef defaultMessage) const override; - iterator begin() { return iterator(diagnostics.begin()); } - - iterator end() { return iterator(diagnostics.end()); } + /// Iterate over all of the available (non-empty) translations + /// maintained by this producer, callback gets each translation + /// with its unique identifier. + void forEachAvailable( + llvm::function_ref callback) const; }; class SerializedLocalizationProducer final : public LocalizationProducer { diff --git a/lib/AST/LocalizationFormat.cpp b/lib/AST/LocalizationFormat.cpp index 767f2985a3374..09ffe085300ac 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/AST/LocalizationFormat.cpp @@ -114,6 +114,7 @@ llvm::StringRef SerializedLocalizationProducer::getMessageOr( value.getDataLen()); if (diagnosticMessage.empty()) return defaultMessage; + return diagnosticMessage; } @@ -135,6 +136,15 @@ YAMLLocalizationProducer::getMessageOr(swift::DiagID id, return diagnosticMessage; } +void YAMLLocalizationProducer::forEachAvailable( + llvm::function_ref callback) const { + for (uint32_t i = 0, n = diagnostics.size(); i != n; ++i) { + auto translation = diagnostics[i]; + if (!translation.empty()) + callback(i, translation); + } +} + template typename std::enable_if::value, void>::type readYAML(llvm::yaml::IO &io, T &Seq, bool, Context &Ctx) { diff --git a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp index eb63112e722de..9905284dbf148 100644 --- a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp +++ b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp @@ -70,9 +70,10 @@ int main(int argc, char *argv[]) { llvm::sys::path::replace_extension(SerializedFilePath, ".db"); SerializedLocalizationWriter Serializer; - for (const auto translation : yaml) { - Serializer.insert(diagnosticID[translation.id], translation.msg); - } + yaml.forEachAvailable( + [&Serializer](uint32_t id, llvm::StringRef translation) { + Serializer.insert(diagnosticID[id], translation); + }); if (Serializer.emit(SerializedFilePath.str())) { llvm::errs() << "Cannot serialize diagnostic file " From 8a1b6201bcc7472ca8be23d5ea8435370f73fcc3 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 29 Jul 2020 16:40:55 -0700 Subject: [PATCH 016/123] [Localization] Serialization writer should own the inserted data --- include/swift/AST/LocalizationFormat.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/AST/LocalizationFormat.h index 8bd4885b72745..5f46b1907f4bc 100644 --- a/include/swift/AST/LocalizationFormat.h +++ b/include/swift/AST/LocalizationFormat.h @@ -36,9 +36,9 @@ using namespace llvm::support; class LocalizationWriterInfo { public: - using key_type = llvm::StringRef; + using key_type = std::string; using key_type_ref = key_type; - using data_type = llvm::StringRef; + using data_type = std::string; using data_type_ref = data_type; using hash_value_type = uint32_t; using offset_type = uint32_t; From 8d8da1b0879176850fe25cdcae0a77217fb710fe Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 30 Jul 2020 12:03:57 -0700 Subject: [PATCH 017/123] [Localization] Adjust types associated with reader/writer info Add more usages of `offset_type` where appropriate and change buffer type to `const unsigned char *`. --- include/swift/AST/LocalizationFormat.h | 13 +++++++------ lib/AST/LocalizationFormat.cpp | 3 ++- localization/CMakeLists.txt | 5 ++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/AST/LocalizationFormat.h index 5f46b1907f4bc..24d34454cb882 100644 --- a/include/swift/AST/LocalizationFormat.h +++ b/include/swift/AST/LocalizationFormat.h @@ -45,9 +45,9 @@ class LocalizationWriterInfo { hash_value_type ComputeHash(key_type_ref key) { return llvm::djbHash(key); } - std::pair EmitKeyDataLength(llvm::raw_ostream &out, - key_type_ref key, - data_type_ref data) { + std::pair EmitKeyDataLength(llvm::raw_ostream &out, + key_type_ref key, + data_type_ref data) { offset_type keyLength = static_cast(key.size()); offset_type dataLength = static_cast(data.size()); endian::write(out, keyLength, little); @@ -85,7 +85,8 @@ class LocalizationReaderInfo { return llvm::djbHash(key); } - static std::pair ReadKeyDataLength(const uint8_t *&data) { + static std::pair + ReadKeyDataLength(const unsigned char *&data) { offset_type keyLength = endian::readNext(data); offset_type dataLength = @@ -93,11 +94,11 @@ class LocalizationReaderInfo { return {keyLength, dataLength}; } - internal_key_type ReadKey(const uint8_t *data, offset_type length) { + internal_key_type ReadKey(const unsigned char *data, offset_type length) { return internal_key_type((const char *)data, length); } - data_type ReadData(llvm::StringRef Key, const uint8_t *data, + data_type ReadData(llvm::StringRef Key, const unsigned char *data, offset_type length) { return data_type((const char *)data, length); } diff --git a/lib/AST/LocalizationFormat.cpp b/lib/AST/LocalizationFormat.cpp index 09ffe085300ac..8ff0add760b27 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/AST/LocalizationFormat.cpp @@ -101,7 +101,8 @@ bool SerializedLocalizationWriter::emit(llvm::StringRef filePath) { SerializedLocalizationProducer::SerializedLocalizationProducer( std::unique_ptr buffer) : Buffer(std::move(buffer)) { - auto base = reinterpret_cast(Buffer.get()->getBufferStart()); + auto base = + reinterpret_cast(Buffer.get()->getBufferStart()); auto tableOffset = endian::read(base, little); SerializedTable.reset(SerializedLocalizationTable::Create( base + tableOffset, base + sizeof(offset_type), base)); diff --git a/localization/CMakeLists.txt b/localization/CMakeLists.txt index c8359ce027c7b..eef5c82f53407 100644 --- a/localization/CMakeLists.txt +++ b/localization/CMakeLists.txt @@ -8,7 +8,10 @@ add_custom_command( add_custom_command( TARGET diagnostic-translation-database - COMMAND swift-serialize-diagnostics --input-file-path="${SWIFT_BINARY_DIR}/share/swift/diagnostics/en.yaml" --output-directory="${SWIFT_BINARY_DIR}/share/swift/diagnostics/") + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND swift-serialize-diagnostics + --input-file-path diagnostics/en.yaml + --output-directory ${SWIFT_BINARY_DIR}/share/swift/diagnostics) add_dependencies(swift-frontend diagnostic-translation-database) From 6b28c2fe89614386b6835c9f1340a9df6152b1f5 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 3 Aug 2020 17:28:34 -0700 Subject: [PATCH 018/123] [SIL] Add flag to SILFunction to indicate async. Includes boilerplate to parse and print as well as to serialize and deserialize. --- include/swift/SIL/SILFunction.h | 7 +++++++ lib/SIL/IR/SILFunction.cpp | 2 +- lib/SIL/IR/SILFunctionBuilder.cpp | 4 ++++ lib/SIL/IR/SILPrinter.cpp | 3 +++ lib/SIL/Parser/ParseSIL.cpp | 24 +++++++++++++----------- lib/Serialization/DeserializeSIL.cpp | 14 ++++++++++---- lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/SILFormat.h | 1 + lib/Serialization/SerializeSIL.cpp | 14 +++++++------- test/SIL/Parser/async.sil | 8 ++++++++ test/SIL/Serialization/basic.sil | 7 +++++++ test/SILGen/async.swift | 20 ++++++++++++++++++++ 12 files changed, 82 insertions(+), 24 deletions(-) create mode 100644 test/SIL/Parser/async.sil create mode 100644 test/SILGen/async.swift diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index ae3f940d21ad4..8125736fc391f 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -274,6 +274,9 @@ class SILFunction /// that it may have unboxed capture (i.e. @inout_aliasable parameters). unsigned IsWithoutActuallyEscapingThunk : 1; + /// True if this function is an async function. + unsigned IsAsync : 1; + /// If != OptimizationMode::NotSet, the optimization mode specified with an /// function attribute. unsigned OptMode : NumOptimizationModeBits; @@ -501,6 +504,10 @@ class SILFunction IsWithoutActuallyEscapingThunk = val; } + bool isAsync() const { return IsAsync; } + + void setAsync(bool val = true) { IsAsync = val; } + /// Returns the calling convention used by this entry point. SILFunctionTypeRepresentation getRepresentation() const { return getLoweredFunctionType()->getRepresentation(); diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index c31d6e1fb7340..f5e27bbd56c1b 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -107,7 +107,7 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, StringRef Name, ExactSelfClass(isExactSelfClass), Inlined(false), Zombie(false), HasOwnership(true), WasDeserializedCanonical(false), IsWithoutActuallyEscapingThunk(false), - OptMode(unsigned(OptimizationMode::NotSet)), + IsAsync(false), OptMode(unsigned(OptimizationMode::NotSet)), EffectsKindAttr(unsigned(E)) { assert(!Transparent || !IsDynamicReplaceable); validateSubclassScope(classSubclassScope, isThunk, nullptr); diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index b56d34ea74d00..c28ba05090b1b 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -217,6 +217,10 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction( } addFunctionAttributes(F, decl->getAttrs(), mod, getOrCreateDeclaration, constant); + + if (auto *funcDecl = dyn_cast(decl)) { + F->setAsync(funcDecl->hasAsync()); + } } return F; diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index b1d92dd8ee5a4..d4da68de7622f 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2599,6 +2599,9 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { if (isWithoutActuallyEscapingThunk()) OS << "[without_actually_escaping] "; + if (isAsync()) + OS << "[async] "; + switch (getSpecialPurpose()) { case SILFunction::Purpose::None: break; diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 24512ef895c38..61f099db1956f 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -919,6 +919,7 @@ static bool parseDeclSILOptional(bool *isTransparent, bool *isWeakImported, AvailabilityContext *availability, bool *isWithoutActuallyEscapingThunk, + bool *isAsync, SmallVectorImpl *Semantics, SmallVectorImpl *SpecAttrs, ValueDecl **ClangDecl, @@ -957,6 +958,8 @@ static bool parseDeclSILOptional(bool *isTransparent, else if (isWithoutActuallyEscapingThunk && SP.P.Tok.getText() == "without_actually_escaping") *isWithoutActuallyEscapingThunk = true; + else if (isAsync && SP.P.Tok.getText() == "async") + *isAsync = true; else if (specialPurpose && SP.P.Tok.getText() == "global_init") *specialPurpose = SILFunction::Purpose::GlobalInit; else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter") @@ -5681,6 +5684,7 @@ bool SILParserState::parseDeclSIL(Parser &P) { bool isWeakImported = false; AvailabilityContext availability = AvailabilityContext::alwaysAvailable(); bool isWithoutActuallyEscapingThunk = false; + bool isAsync = false; Inline_t inlineStrategy = InlineDefault; OptimizationMode optimizationMode = OptimizationMode::NotSet; SmallVector Semantics; @@ -5695,8 +5699,8 @@ bool SILParserState::parseDeclSIL(Parser &P) { &isThunk, &isDynamic, &isExactSelfClass, &DynamicallyReplacedFunction, &objCReplacementFor, &specialPurpose, &inlineStrategy, &optimizationMode, nullptr, &isWeakImported, &availability, - &isWithoutActuallyEscapingThunk, &Semantics, - &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) || + &isWithoutActuallyEscapingThunk, &isAsync, &Semantics, &SpecAttrs, + &ClangDecl, &MRK, FunctionState, M) || P.parseToken(tok::at_sign, diag::expected_sil_function_name) || P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) || P.parseToken(tok::colon, diag::expected_sil_type)) @@ -5734,6 +5738,7 @@ bool SILParserState::parseDeclSIL(Parser &P) { FunctionState.F->setAvailabilityForLinkage(availability); FunctionState.F->setWithoutActuallyEscapingThunk( isWithoutActuallyEscapingThunk); + FunctionState.F->setAsync(isAsync); FunctionState.F->setInlineStrategy(inlineStrategy); FunctionState.F->setOptimizationMode(optimizationMode); FunctionState.F->setEffectsKind(MRK); @@ -5919,10 +5924,9 @@ bool SILParserState::parseSILGlobal(Parser &P) { SILParser State(P); if (parseSILLinkage(GlobalLinkage, P) || parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, - &isLet, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, State, M) || + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, &isLet, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, State, M) || P.parseToken(tok::at_sign, diag::expected_sil_value_name) || P.parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) || P.parseToken(tok::colon, diag::expected_sil_type)) @@ -5971,7 +5975,7 @@ bool SILParserState::parseSILProperty(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, SP, M)) + nullptr, nullptr, nullptr, nullptr, SP, M)) return true; ValueDecl *VD; @@ -6041,8 +6045,7 @@ bool SILParserState::parseSILVTable(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - VTableState, M)) + nullptr, nullptr, nullptr, nullptr, VTableState, M)) return true; // Parse the class name. @@ -6578,8 +6581,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) { if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - WitnessState, M)) + nullptr, nullptr, nullptr, nullptr, WitnessState, M)) return true; Scope S(&P, ScopeKind::TopLevel); diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 86565d2ee9314..26ee442264524 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -511,14 +511,14 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, IdentifierID replacedFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, + isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, + isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, @@ -627,6 +627,11 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, MF->fatal(); } + if (fn->isAsync() != isAsync) { + LLVM_DEBUG(llvm::dbgs() << "SILFunction type mismatch.\n"); + MF->fatal(); + } + } else { // Otherwise, create a new function. fn = builder.createDeclaration(name, ty, loc); @@ -635,6 +640,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setSerialized(IsSerialized_t(isSerialized)); fn->setThunk(IsThunk_t(isThunk)); fn->setWithoutActuallyEscapingThunk(bool(isWithoutactuallyEscapingThunk)); + fn->setAsync((bool)isAsync); fn->setInlineStrategy(Inline_t(inlineStrategy)); fn->setSpecialPurpose(SILFunction::Purpose(specialPurpose)); fn->setEffectsKind(EffectsKind(effect)); @@ -2824,14 +2830,14 @@ bool SILDeserializer::hasSILFunction(StringRef Name, IdentifierID replacedFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, + isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, + isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 351721a916022..6bf15541faf97 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 566; // async +const uint16_t SWIFTMODULE_VERSION_MINOR = 567; // async sil modifier /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index ec16f5e92b975..3a68d6c0baddf 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -278,6 +278,7 @@ namespace sil_block { BCFixed<2>, // serialized BCFixed<2>, // thunks: signature optimized/reabstraction BCFixed<1>, // without_actually_escaping + BCFixed<1>, // async BCFixed<3>, // specialPurpose BCFixed<2>, // inlineStrategy BCFixed<2>, // optimizationMode diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 285db801310ff..849138d351534 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -434,13 +434,13 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage), (unsigned)F.isTransparent(), (unsigned)F.isSerialized(), (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(), - (unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(), - (unsigned)F.getOptimizationMode(), (unsigned)F.getEffectsKind(), - (unsigned)numSpecAttrs, (unsigned)F.hasOwnership(), - F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), - (unsigned)F.isDynamicallyReplaceable(), - (unsigned)F.isExactSelfClass(), - FnID, replacedFunctionID, genericSigID, clangNodeOwnerID, SemanticsIDs); + (unsigned)F.isAsync(), (unsigned)F.getSpecialPurpose(), + (unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(), + (unsigned)F.getEffectsKind(), (unsigned)numSpecAttrs, + (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), + LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(), + (unsigned)F.isExactSelfClass(), FnID, replacedFunctionID, genericSigID, + clangNodeOwnerID, SemanticsIDs); if (NoBody) return; diff --git a/test/SIL/Parser/async.sil b/test/SIL/Parser/async.sil new file mode 100644 index 0000000000000..694f66de78175 --- /dev/null +++ b/test/SIL/Parser/async.sil @@ -0,0 +1,8 @@ +// RUN: %target-sil-opt -enable-sil-verify-all=true %s | %target-sil-opt -enable-sil-verify-all=true | %FileCheck %s + +// CHECK: sil [async] @async_test +sil [async] @async_test : $() -> () { +bb0: + %0 = tuple () + return %0 : $() +} diff --git a/test/SIL/Serialization/basic.sil b/test/SIL/Serialization/basic.sil index e2fff2ea050db..dd7f9ba3a54d4 100644 --- a/test/SIL/Serialization/basic.sil +++ b/test/SIL/Serialization/basic.sil @@ -15,6 +15,13 @@ bb0(%0 : @guaranteed $Builtin.NativeObject): return undef : $() } +// CHECK-LABEL: sil [async] @async_test +sil [async] @async_test : $() -> () { +bb0: + %0 = tuple () + return %0 : $() +} + // CHECK-LABEL: sil [serialized] [ossa] @test_end_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () { // CHECK: end_lifetime {{%.*}} : $Builtin.NativeObject sil [serialized] [ossa] @test_end_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () { diff --git a/test/SILGen/async.swift b/test/SILGen/async.swift new file mode 100644 index 0000000000000..901978a7ac493 --- /dev/null +++ b/test/SILGen/async.swift @@ -0,0 +1,20 @@ +// RUN: %target-swift-frontend -emit-silgen -enable-experimental-concurrency -module-name Async -Xllvm -sil-full-demangle -parse-as-library %s | %FileCheck %s + +import Swift + +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async04testA0yyYF : $@convention(thin) () -> () { +func testAsync() async {} +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async11testAsyncp1SiyYF : $@convention(thin) () -> Int { +func testAsyncp1() async -> Int { return 0 } + +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async5test2yyYKF : $@convention(thin) () -> @error Error { +func test2() async throws {} +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async7test2p1SiyYKF : $@convention(thin) () -> (Int, @error Error) { +func test2p1() async throws -> Int { return 0 } + +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async5test3yyyyKXEYKF : $@convention(thin) (@noescape @callee_guaranteed () -> @error Error) -> @error Error { +func test3(_ cl: () throws -> ()) async rethrows {} +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async7test3p1yS2iyKXEYKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error) { +func test3p1(_ cl: () throws -> Int) async rethrows -> Int { return try cl() } + + From d0c1a45068ee54907e6d3a13b3220e0bc0bddd3d Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Wed, 5 Aug 2020 16:35:32 -0700 Subject: [PATCH 019/123] DependenciesScanner: teach the scanner to diagnose dependency cycles --- include/swift/AST/DiagnosticsCommon.def | 7 +++ lib/FrontendTool/ScanDependencies.cpp | 55 +++++++++++++++++++ .../Inputs/Swift/CycleOne.swiftinterface | 5 ++ .../Inputs/Swift/CycleThree.swiftinterface | 5 ++ .../Inputs/Swift/CycleTwo.swiftinterface | 4 ++ .../diagnose_dependency_cycle.swift | 10 ++++ 6 files changed, 86 insertions(+) create mode 100644 test/ScanDependencies/Inputs/Swift/CycleOne.swiftinterface create mode 100644 test/ScanDependencies/Inputs/Swift/CycleThree.swiftinterface create mode 100644 test/ScanDependencies/Inputs/Swift/CycleTwo.swiftinterface create mode 100644 test/ScanDependencies/diagnose_dependency_cycle.swift diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index 788fb0e09f767..cdeef09e3058e 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -178,5 +178,12 @@ WARNING(cross_imported_by_both_modules, none, "please report this bug to the maintainers of these modules", (Identifier, Identifier, Identifier)) +//------------------------------------------------------------------------------ +// MARK: dependencies scanner diagnostics +//------------------------------------------------------------------------------ + +ERROR(scanner_find_cycle, none, + "dependency scanner detected dependency cycle: '%0'", (StringRef)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index e68955216b343..6a90ae8231c86 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -470,6 +470,57 @@ static void writeJSON(llvm::raw_ostream &out, } } +static bool diagnoseCycle(CompilerInstance &instance, + ModuleDependenciesCache &cache, + ModuleDependencyID mainId, + InterfaceSubContextDelegate &astDelegate) { + llvm::SetVector, + std::set> openSet; + llvm::SetVector, + std::set> closeSet; + // Start from the main module. + openSet.insert(mainId); + while(!openSet.empty()) { + auto &lastOpen = openSet.back(); + auto beforeSize = openSet.size(); + for (auto dep: resolveDirectDependencies(instance, lastOpen, cache, + astDelegate)) { + if (closeSet.count(dep)) + continue; + if (openSet.insert(dep)) { + break; + } else { + // Find a cycle, diagnose. + auto startIt = std::find(openSet.begin(), openSet.end(), dep); + assert(startIt != openSet.end()); + llvm::SmallString<64> buffer; + for (auto it = startIt; it != openSet.end(); ++ it) { + buffer.append(it->first); + buffer.append(it->second == ModuleDependenciesKind::Swift? + ".swiftmodule": ".pcm"); + buffer.append(" -> "); + } + buffer.append(startIt->first); + buffer.append(startIt->second == ModuleDependenciesKind::Swift? + ".swiftmodule": ".pcm"); + instance.getASTContext().Diags.diagnose(SourceLoc(), + diag::scanner_find_cycle, + buffer.str()); + return true; + } + } + // No new node added. We can close this node + if (openSet.size() == beforeSize) { + closeSet.insert(openSet.back()); + openSet.pop_back(); + } else { + assert(openSet.size() == beforeSize + 1); + } + } + assert(openSet.empty()); + return false; +} + bool swift::scanDependencies(CompilerInstance &instance) { ASTContext &Context = instance.getASTContext(); ModuleDecl *mainModule = instance.getMainModule(); @@ -592,6 +643,10 @@ bool swift::scanDependencies(CompilerInstance &instance) { allModules.insert(id); }); + // Dignose cycle in dependency graph. + if (diagnoseCycle(instance, cache, /*MainModule*/allModules.front(), ASTDelegate)) + return true; + // Write out the JSON description. writeJSON(out, instance, cache, ASTDelegate, allModules.getArrayRef()); diff --git a/test/ScanDependencies/Inputs/Swift/CycleOne.swiftinterface b/test/ScanDependencies/Inputs/Swift/CycleOne.swiftinterface new file mode 100644 index 0000000000000..fc36a2faed446 --- /dev/null +++ b/test/ScanDependencies/Inputs/Swift/CycleOne.swiftinterface @@ -0,0 +1,5 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name CycleOne +import Swift +import CycleTwo + diff --git a/test/ScanDependencies/Inputs/Swift/CycleThree.swiftinterface b/test/ScanDependencies/Inputs/Swift/CycleThree.swiftinterface new file mode 100644 index 0000000000000..0ecabbea84dfb --- /dev/null +++ b/test/ScanDependencies/Inputs/Swift/CycleThree.swiftinterface @@ -0,0 +1,5 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name CycleThree +import Swift +import CycleOne + diff --git a/test/ScanDependencies/Inputs/Swift/CycleTwo.swiftinterface b/test/ScanDependencies/Inputs/Swift/CycleTwo.swiftinterface new file mode 100644 index 0000000000000..9e97dd3b2244e --- /dev/null +++ b/test/ScanDependencies/Inputs/Swift/CycleTwo.swiftinterface @@ -0,0 +1,4 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name CycleTwo +import Swift +import CycleThree diff --git a/test/ScanDependencies/diagnose_dependency_cycle.swift b/test/ScanDependencies/diagnose_dependency_cycle.swift new file mode 100644 index 0000000000000..1157d364a7954 --- /dev/null +++ b/test/ScanDependencies/diagnose_dependency_cycle.swift @@ -0,0 +1,10 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache + +// RUN: not %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules &> %t/out.txt + +// RUN: %FileCheck %s < %t/out.txt + +// CHECK: dependency scanner detected dependency cycle: 'CycleOne.swiftmodule -> CycleTwo.swiftmodule -> CycleThree.swiftmodule -> CycleOne.swiftmodule' + +import CycleOne From 0103b79579f6129cff78d05dce35b56452629902 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 31 Jul 2020 12:19:03 -0700 Subject: [PATCH 020/123] [Localization] Adjust cmake to include serialized diagnostics in toolchain Building of the diagnostic database to be done in three steps: - Copy YAMLs from /localization/diagnostics to /share/swift/diagnostics - Serialize English into /share/swift/diagnostics - Install everything (YAML and `.db`) from /share/swift/diagnostics to share/swift/diagnostics in toolchain --- localization/CMakeLists.txt | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/localization/CMakeLists.txt b/localization/CMakeLists.txt index eef5c82f53407..8f0d3f6b9c29a 100644 --- a/localization/CMakeLists.txt +++ b/localization/CMakeLists.txt @@ -1,21 +1,17 @@ -add_custom_target(diagnostic-translation-database) +add_custom_target(diagnostic-database) -add_custom_command( - TARGET diagnostic-translation-database - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS diagnostics - COMMAND "${CMAKE_COMMAND}" -E copy_directory diagnostics/ "${SWIFT_BINARY_DIR}/share/swift/diagnostics/") +add_custom_command(TARGET diagnostic-database + COMMAND + ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/diagnostics/ ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ + COMMAND + swift-serialize-diagnostics + --input-file-path ${CMAKE_BINARY_DIR}/share/swift/diagnostics/en.yaml + --output-directory ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ +) -add_custom_command( - TARGET diagnostic-translation-database - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND swift-serialize-diagnostics - --input-file-path diagnostics/en.yaml - --output-directory ${SWIFT_BINARY_DIR}/share/swift/diagnostics) - -add_dependencies(swift-frontend diagnostic-translation-database) +add_dependencies(swift-frontend diagnostic-database) swift_install_in_component( - DIRECTORY diagnostics - DESTINATION "share/swift" + DIRECTORY ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ + DESTINATION "share/swift/diagnostics" COMPONENT compiler) From 67dbef5aeb8ad864a9ca69a6335e1bd77cf0f083 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 5 Aug 2020 11:49:37 -0700 Subject: [PATCH 021/123] [Localization] NFC: Include all of the headers based on the types used --- include/swift/AST/LocalizationFormat.h | 6 ++++++ lib/AST/LocalizationFormat.cpp | 2 ++ .../swift-serialize-diagnostics.cpp | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/AST/LocalizationFormat.h index 24d34454cb882..7649188dd58e4 100644 --- a/include/swift/AST/LocalizationFormat.h +++ b/include/swift/AST/LocalizationFormat.h @@ -21,12 +21,18 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/DJB.h" +#include "llvm/Support/EndianStream.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include +#include #include #include +#include +#include namespace swift { enum class DiagID : uint32_t; diff --git a/lib/AST/LocalizationFormat.cpp b/lib/AST/LocalizationFormat.cpp index 8ff0add760b27..b242dad39c421 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/AST/LocalizationFormat.cpp @@ -22,7 +22,9 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" +#include #include +#include #include namespace { diff --git a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp index 9905284dbf148..d0ef60a5fb936 100644 --- a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp +++ b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp @@ -16,12 +16,21 @@ #include "swift/AST/LocalizationFormat.h" #include "swift/Basic/LLVMInitialize.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/OnDiskHashTable.h" +#include "llvm/Support/Path.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include using namespace swift; using namespace swift::diag; From 3a4d1569aa2fe1688c4f520e37e7d0c759d80c00 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 5 Aug 2020 14:09:04 -0700 Subject: [PATCH 022/123] [Localization] Switch serialization format to use DiagID as a key --- include/swift/AST/LocalizationFormat.h | 50 ++++++++++--------- lib/AST/LocalizationFormat.cpp | 15 ++---- .../swift-serialize-diagnostics.cpp | 11 +--- 3 files changed, 33 insertions(+), 43 deletions(-) diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/AST/LocalizationFormat.h index 7649188dd58e4..0b0c524eef2d0 100644 --- a/include/swift/AST/LocalizationFormat.h +++ b/include/swift/AST/LocalizationFormat.h @@ -17,10 +17,10 @@ #ifndef SWIFT_LOCALIZATIONFORMAT_H #define SWIFT_LOCALIZATIONFORMAT_H +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitstreamReader.h" -#include "llvm/Support/DJB.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" @@ -42,27 +42,27 @@ using namespace llvm::support; class LocalizationWriterInfo { public: - using key_type = std::string; - using key_type_ref = key_type; + using key_type = uint32_t; + using key_type_ref = const uint32_t &; using data_type = std::string; - using data_type_ref = data_type; + using data_type_ref = llvm::StringRef; using hash_value_type = uint32_t; using offset_type = uint32_t; - hash_value_type ComputeHash(key_type_ref key) { return llvm::djbHash(key); } + hash_value_type ComputeHash(key_type_ref key) { return llvm::hash_code(key); } std::pair EmitKeyDataLength(llvm::raw_ostream &out, key_type_ref key, data_type_ref data) { - offset_type keyLength = static_cast(key.size()); offset_type dataLength = static_cast(data.size()); - endian::write(out, keyLength, little); endian::write(out, dataLength, little); - return {keyLength, dataLength}; + // No need to write the key length; it's constant. + return {sizeof(key_type), dataLength}; } void EmitKey(llvm::raw_ostream &out, key_type_ref key, unsigned len) { - out << key; + assert(len == sizeof(key_type)); + endian::write(out, key, little); } void EmitData(llvm::raw_ostream &out, key_type_ref key, data_type_ref data, @@ -73,38 +73,40 @@ class LocalizationWriterInfo { class LocalizationReaderInfo { public: - using internal_key_type = llvm::StringRef; - using external_key_type = internal_key_type; + using internal_key_type = uint32_t; + using external_key_type = swift::DiagID; using data_type = llvm::StringRef; using hash_value_type = uint32_t; using offset_type = uint32_t; - internal_key_type GetInternalKey(external_key_type key) { return key; } + internal_key_type GetInternalKey(external_key_type key) { + return static_cast(key); + } - external_key_type GetExternalKey(internal_key_type key) { return key; } + external_key_type GetExternalKey(internal_key_type key) { + return static_cast(key); + } static bool EqualKey(internal_key_type lhs, internal_key_type rhs) { return lhs == rhs; } hash_value_type ComputeHash(internal_key_type key) { - return llvm::djbHash(key); + return llvm::hash_code(key); } static std::pair ReadKeyDataLength(const unsigned char *&data) { - offset_type keyLength = - endian::readNext(data); offset_type dataLength = endian::readNext(data); - return {keyLength, dataLength}; + return {sizeof(uint32_t), dataLength}; } internal_key_type ReadKey(const unsigned char *data, offset_type length) { - return internal_key_type((const char *)data, length); + return endian::readNext(data); } - data_type ReadData(llvm::StringRef Key, const unsigned char *data, + data_type ReadData(internal_key_type Key, const unsigned char *data, offset_type length) { return data_type((const char *)data, length); } @@ -119,10 +121,10 @@ class SerializedLocalizationWriter { /// file. /// /// \param id The identifier associated with the given diagnostic message e.g. - /// 'cannot_convert_argument'. - /// \param translation The localized diagnostic - /// message for the given identifier. - void insert(llvm::StringRef id, llvm::StringRef translation); + /// 'cannot_convert_argument'. + /// \param translation The localized diagnostic message for the given + /// identifier. + void insert(swift::DiagID id, llvm::StringRef translation); /// Write out previously inserted diagnostic translations into the given /// location. @@ -158,7 +160,7 @@ class YAMLLocalizationProducer final : public LocalizationProducer { /// maintained by this producer, callback gets each translation /// with its unique identifier. void forEachAvailable( - llvm::function_ref callback) const; + llvm::function_ref callback) const; }; class SerializedLocalizationProducer final : public LocalizationProducer { diff --git a/lib/AST/LocalizationFormat.cpp b/lib/AST/LocalizationFormat.cpp index b242dad39c421..4c8ead4d9729a 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/AST/LocalizationFormat.cpp @@ -34,11 +34,6 @@ enum LocalDiagID : uint32_t { NumDiags }; -static constexpr const char *const diagnosticID[] = { -#define DIAG(KIND, ID, Options, Text, Signature) #ID, -#include "swift/AST/DiagnosticsAll.def" -}; - struct DiagnosticNode { uint32_t id; std::string msg; @@ -75,9 +70,9 @@ template <> struct MappingTraits { namespace swift { namespace diag { -void SerializedLocalizationWriter::insert(llvm::StringRef id, +void SerializedLocalizationWriter::insert(swift::DiagID id, llvm::StringRef translation) { - generator.insert(id, translation); + generator.insert(static_cast(id), translation); } bool SerializedLocalizationWriter::emit(llvm::StringRef filePath) { @@ -112,7 +107,7 @@ SerializedLocalizationProducer::SerializedLocalizationProducer( llvm::StringRef SerializedLocalizationProducer::getMessageOr( swift::DiagID id, llvm::StringRef defaultMessage) const { - auto value = SerializedTable.get()->find(diagnosticID[(unsigned)id]); + auto value = SerializedTable.get()->find(id); llvm::StringRef diagnosticMessage((const char *)value.getDataPtr(), value.getDataLen()); if (diagnosticMessage.empty()) @@ -140,11 +135,11 @@ YAMLLocalizationProducer::getMessageOr(swift::DiagID id, } void YAMLLocalizationProducer::forEachAvailable( - llvm::function_ref callback) const { + llvm::function_ref callback) const { for (uint32_t i = 0, n = diagnostics.size(); i != n; ++i) { auto translation = diagnostics[i]; if (!translation.empty()) - callback(i, translation); + callback(static_cast(i), translation); } } diff --git a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp index d0ef60a5fb936..a3beba7a459bf 100644 --- a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp +++ b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp @@ -35,13 +35,6 @@ using namespace swift; using namespace swift::diag; -namespace { -static constexpr const char *const diagnosticID[] = { -#define DIAG(KIND, ID, Options, Text, Signature) #ID, -#include "swift/AST/DiagnosticsAll.def" -}; -} // namespace - namespace options { static llvm::cl::OptionCategory Category("swift-serialize-diagnostics Options"); @@ -80,8 +73,8 @@ int main(int argc, char *argv[]) { SerializedLocalizationWriter Serializer; yaml.forEachAvailable( - [&Serializer](uint32_t id, llvm::StringRef translation) { - Serializer.insert(diagnosticID[id], translation); + [&Serializer](swift::DiagID id, llvm::StringRef translation) { + Serializer.insert(id, translation); }); if (Serializer.emit(SerializedFilePath.str())) { From 5e13a539aa905c01f50110905ecdcd8fabd7b715 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 6 Aug 2020 10:06:49 -0700 Subject: [PATCH 023/123] [Localization] Make return type of the serialization main cross platform --- .../swift-serialize-diagnostics.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp index a3beba7a459bf..14bda88c7a7f3 100644 --- a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp +++ b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp @@ -53,7 +53,6 @@ static llvm::cl::opt int main(int argc, char *argv[]) { PROGRAM_START(argc, argv); - INITIALIZE_LLVM(); llvm::cl::HideUnrelatedOptions(options::Category); llvm::cl::ParseCommandLineOptions(argc, argv, @@ -61,7 +60,7 @@ int main(int argc, char *argv[]) { if (!llvm::sys::fs::exists(options::InputFilePath)) { llvm::errs() << "YAML file not found\n"; - return 1; + return EXIT_FAILURE; } YAMLLocalizationProducer yaml(options::InputFilePath); @@ -80,8 +79,8 @@ int main(int argc, char *argv[]) { if (Serializer.emit(SerializedFilePath.str())) { llvm::errs() << "Cannot serialize diagnostic file " << options::InputFilePath << '\n'; - return 1; + return EXIT_FAILURE; } - return 0; + return EXIT_SUCCESS; } From 3ad98a504cf881f0e70b1d54bbb57fe2cdd9dccc Mon Sep 17 00:00:00 2001 From: Gabriel Igliozzi Date: Wed, 5 Aug 2020 22:12:38 -0400 Subject: [PATCH 024/123] [Docs] Fix broken url and filename (#33318) --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 1492d1ef48430..cc4c4815bc9a9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -105,7 +105,7 @@ documentation, please create a thread on the Swift forums under the - [RequestEvaluator.md](/docs/RequestEvaluator.md): Describes the request evaluator architecture, which is used for lazy type-checking and efficient caching. - - [Literal.md](/docs/Literal.md): + - [Literals.md](/docs/Literals.md): Describes type-checking and inference specifically for literals. - [Serialization.rst](/docs/Serialization.rst): Gives an overview of the LLVM bitcode format used for swiftmodules. From ceeb7245f11cf61cf0836ee461818b9dcb87aad6 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Wed, 5 Aug 2020 23:51:24 -0700 Subject: [PATCH 025/123] Don't build SwiftUnitTests for cross compile host --- utils/build-script-impl | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index bb5da6a7e360a..5d8720cfb92c5 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -2468,13 +2468,15 @@ for host in "${ALL_HOSTS[@]}"; do executable_target= results_targets= if ! [[ "${SKIP_TEST_SWIFT}" ]]; then - executable_target=SwiftUnitTests - results_targets=("${SWIFT_TEST_TARGETS[@]}") - if [[ "${STRESS_TEST_SOURCEKIT}" ]]; then - results_targets=( - "${results_targets[@]}" - stress-SourceKit - ) + if ! [[ $(is_cross_tools_host ${host}) ]] ; then + executable_target=SwiftUnitTests + results_targets=("${SWIFT_TEST_TARGETS[@]}") + if [[ "${STRESS_TEST_SOURCEKIT}" ]]; then + results_targets=( + "${results_targets[@]}" + stress-SourceKit + ) + fi fi fi if ! [[ "${SKIP_TEST_BENCHMARKS}" ]]; then From bb356d3ac1ae8068dfa575d3a112977799bfe109 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Wed, 5 Aug 2020 23:52:40 -0700 Subject: [PATCH 026/123] Don't run LLDB cross compile host test suite --- utils/build-script-impl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/build-script-impl b/utils/build-script-impl index 5d8720cfb92c5..2b995d047bfca 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -2493,6 +2493,10 @@ for host in "${ALL_HOSTS[@]}"; do if [[ "${SKIP_TEST_LLDB}" ]]; then continue fi + if [[ $(is_cross_tools_host ${host}) ]]; then + echo "--- Can't execute tests for ${host}, skipping... ---" + continue + fi llvm_build_dir=$(build_directory ${host} llvm) lldb_build_dir=$(build_directory ${host} lldb) results_dir="${lldb_build_dir}/test-results" From 9adbace82379a7800478ce69d84a1ec151c2422c Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Wed, 5 Aug 2020 23:54:29 -0700 Subject: [PATCH 027/123] Remove compiler-rt from install targets for cross compile host --- utils/build-script-impl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/build-script-impl b/utils/build-script-impl index 2b995d047bfca..08e4778ac21ce 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -2792,7 +2792,11 @@ for host in "${ALL_HOSTS[@]}"; do if [[ "${LLVM_INSTALL_COMPONENTS}" == "all" ]] ; then INSTALL_TARGETS=install elif [[ -n "${LLVM_INSTALL_COMPONENTS}" ]] ; then - INSTALL_TARGETS=install-$(echo ${LLVM_INSTALL_COMPONENTS} | sed -E 's/;/ install-/g') + if [[ $(is_cross_tools_host ${host}) && "${LLVM_INSTALL_COMPONENTS}" == *"compiler-rt"* ]]; then + INSTALL_TARGETS=install-$(echo ${LLVM_INSTALL_COMPONENTS} | sed -E 's/compiler-rt;//g' |sed -E 's/;/ install-/g') + else + INSTALL_TARGETS=install-$(echo ${LLVM_INSTALL_COMPONENTS} | sed -E 's/;/ install-/g') + fi fi ;; libcxx) From 0efb86a7fbef173e473a79f69415eb20c296cea0 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Tue, 4 Aug 2020 13:35:11 -0700 Subject: [PATCH 028/123] [ConstraintSystem] Add an overload of addJoinConstraint that takes in an iterator range and a callback to get the type. This allows callers to lazily compute the input types to join rather than constructing an array first. The old addJoinConstraint is now a wrapper for this new overload. --- lib/Sema/CSSimplify.cpp | 59 ++-------------------------------- lib/Sema/ConstraintSystem.h | 63 +++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 59 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 4957153e7b349..62f9b9291f3a9 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -10420,10 +10420,8 @@ void ConstraintSystem::addContextualConversionConstraint( convertTypeLocator, /*isFavored*/ true); } -/// Returns the \c ExprKind of the given type variable if it's the type of an -/// atomic literal expression, meaning the literal can't be composed of subexpressions. -/// Otherwise, returns \c None. -static Optional getAtomicLiteralKind(TypeVariableType *typeVar) { +Optional +ConstraintSystem::getAtomicLiteralKind(TypeVariableType *typeVar) const { const std::unordered_set atomicLiteralKinds = { ExprKind::IntegerLiteral, ExprKind::FloatLiteral, @@ -10446,59 +10444,6 @@ static Optional getAtomicLiteralKind(TypeVariableType *typeVar) { return literalKind; } -Type ConstraintSystem::addJoinConstraint( - ConstraintLocator *locator, - ArrayRef> inputs, - Optional supertype) { - switch (inputs.size()) { - case 0: - return Type(); - - case 1: - if (supertype.hasValue()) - break; - - return inputs.front().first; - - default: - // Produce the join below. - break; - } - - // Create a type variable to capture the result of the join. - Type resultTy = supertype.hasValue() ? supertype.getValue() : - createTypeVariable(locator, (TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape)); - - using RawExprKind = uint8_t; - llvm::SmallDenseMap representativeForKind; - - // Join the input types. - for (const auto &input : inputs) { - // We can merge the type variables of same-kind atomic literal expressions because they - // will all have the same set of constraints and therefore can never resolve to anything - // different. - auto *typeVar = input.first->getAs(); - if (auto literalKind = getAtomicLiteralKind(typeVar)) { - auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; - auto *currentRep = getRepresentative(typeVar); - - if (originalRep) { - if (originalRep != currentRep) - mergeEquivalenceClasses(currentRep, originalRep); - continue; - } - - originalRep = currentRep; - } - - // Introduce conversions from each input type to the supertype. - addConstraint( - ConstraintKind::Conversion, input.first, resultTy, input.second); - } - - return resultTy; -} - void ConstraintSystem::addFixConstraint(ConstraintFix *fix, ConstraintKind kind, Type first, Type second, ConstraintLocatorBuilder locator, diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 391dc445b3a0d..7ec7c1d71e760 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -2994,6 +2994,11 @@ class ConstraintSystem { bool isDeclUnavailable(const Decl *D, ConstraintLocator *locator = nullptr) const; + /// Returns the \c ExprKind of the given type variable if it's the type of an + /// atomic literal expression, meaning the literal can't be composed of subexpressions. + /// Otherwise, returns \c None. + Optional getAtomicLiteralKind(TypeVariableType *typeVar) const; + public: /// Whether we should attempt to fix problems. @@ -3076,6 +3081,14 @@ class ConstraintSystem { Expr *expr, Type conversionType, ContextualTypePurpose purpose, bool isOpaqueReturnType); + /// Convenience function to pass an \c ArrayRef to \c addJoinConstraint + Type addJoinConstraint(ConstraintLocator *locator, + ArrayRef> inputs, + Optional supertype = None) { + return addJoinConstraint( + locator, inputs.begin(), inputs.end(), supertype, [](auto it) { return *it; }); + } + /// Add a "join" constraint between a set of types, producing the common /// supertype. /// @@ -3085,9 +3098,55 @@ class ConstraintSystem { /// /// \returns the joined type, which is generally a new type variable, unless there are /// fewer than 2 input types or the \c supertype parameter is specified. + template Type addJoinConstraint(ConstraintLocator *locator, - ArrayRef> inputs, - Optional supertype = None); + Iterator begin, Iterator end, + Optional supertype, + std::function(Iterator)> getType) { + if (begin == end) + return Type(); + + // No need to generate a new type variable if there's only one type to join + if ((begin + 1 == end) && !supertype.hasValue()) + return getType(begin).first; + + // The type to capture the result of the join, which is either the specified supertype, + // or a new type variable. + Type resultTy = supertype.hasValue() ? supertype.getValue() : + createTypeVariable(locator, (TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape)); + + using RawExprKind = uint8_t; + llvm::SmallDenseMap representativeForKind; + + // Join the input types. + while (begin != end) { + Type type; + ConstraintLocator *locator; + std::tie(type, locator) = getType(begin++); + + // We can merge the type variables of same-kind atomic literal expressions because they + // will all have the same set of constraints and therefore can never resolve to anything + // different. + auto *typeVar = type->getAs(); + if (auto literalKind = getAtomicLiteralKind(typeVar)) { + auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; + auto *currentRep = getRepresentative(typeVar); + + if (originalRep) { + if (originalRep != currentRep) + mergeEquivalenceClasses(currentRep, originalRep); + continue; + } + + originalRep = currentRep; + } + + // Introduce conversions from each input type to the supertype. + addConstraint(ConstraintKind::Conversion, type, resultTy, locator); + } + + return resultTy; + } /// Add a constraint to the constraint system with an associated fix. void addFixConstraint(ConstraintFix *fix, ConstraintKind kind, From 43aafcdb8e0af170560c39a14da113d859313390 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Tue, 4 Aug 2020 14:27:34 -0700 Subject: [PATCH 029/123] [CSGen] Use addJoinConstraint for joining array literal element types. --- lib/Sema/CSGen.cpp | 42 ++++++++++--------------- lib/Sema/CSSimplify.cpp | 1 + test/Constraints/diagnostics.swift | 2 +- test/Parse/pointer_conversion.swift.gyb | 2 +- test/expr/cast/as_coerce.swift | 4 +-- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 0963b7f02663c..31414f975c6bc 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1803,31 +1803,28 @@ namespace { auto locator = CS.getConstraintLocator(expr); auto contextualType = CS.getContextualType(expr); - Type contextualArrayType = nullptr; - Type contextualArrayElementType = nullptr; - + + auto joinElementTypes = [&](Optional elementType) { + const auto elements = expr->getElements(); + unsigned index = 0; + + using Iterator = decltype(elements)::iterator; + CS.addJoinConstraint(locator, elements.begin(), elements.end(), + elementType, [&](const auto it) { + auto *locator = CS.getConstraintLocator(expr, LocatorPathElt::TupleElement(index++)); + return std::make_pair(CS.getType(*it), locator); + }); + }; + // If a contextual type exists for this expression, apply it directly. Optional arrayElementType; if (contextualType && (arrayElementType = ConstraintSystem::isArrayType(contextualType))) { - // Is the array type a contextual type - contextualArrayType = contextualType; - contextualArrayElementType = *arrayElementType; - CS.addConstraint(ConstraintKind::LiteralConformsTo, contextualType, arrayProto->getDeclaredType(), locator); - - unsigned index = 0; - for (auto element : expr->getElements()) { - CS.addConstraint(ConstraintKind::Conversion, - CS.getType(element), - contextualArrayElementType, - CS.getConstraintLocator( - expr, LocatorPathElt::TupleElement(index++))); - } - - return contextualArrayType; + joinElementTypes(arrayElementType); + return contextualType; } // Produce a specialized diagnostic if this is an attempt to initialize @@ -1893,14 +1890,7 @@ namespace { // Introduce conversions from each element to the element type of the // array. - unsigned index = 0; - for (auto element : expr->getElements()) { - CS.addConstraint(ConstraintKind::Conversion, - CS.getType(element), - arrayElementTy, - CS.getConstraintLocator( - expr, LocatorPathElt::TupleElement(index++))); - } + joinElementTypes(arrayElementTy); // The array element type defaults to 'Any'. CS.addConstraint(ConstraintKind::Defaultable, arrayElementTy, diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 62f9b9291f3a9..4dff72adf8ecf 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4216,6 +4216,7 @@ bool ConstraintSystem::repairFailures( conversionsOrFixes.push_back(CollectionElementContextualMismatch::create( *this, lhs, rhs, getConstraintLocator(locator))); + break; } // Drop the `tuple element` locator element so that all tuple element diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index bff33fe7caa73..e961b108bda48 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -338,7 +338,7 @@ variadic(arrayWithOtherEltType) // expected-error {{cannot convert value of type variadic(1, arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Int'}} // FIXME: SR-11104 -variadic(["hello", "world"]) // expected-error 2 {{cannot convert value of type 'String' to expected element type 'Int'}} +variadic(["hello", "world"]) // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} // expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} // expected-note@-2 {{remove brackets to pass array elements directly}} diff --git a/test/Parse/pointer_conversion.swift.gyb b/test/Parse/pointer_conversion.swift.gyb index 616285d4fbda6..4c9af4a6a5568 100644 --- a/test/Parse/pointer_conversion.swift.gyb +++ b/test/Parse/pointer_conversion.swift.gyb @@ -164,7 +164,7 @@ func constPointerArguments(_ p: UnsafeMutablePointer, takesConstPointer([0, 1, 2]) // QoI: CSDiags doesn't handle array -> pointer impl conversions well takesConstPointer([0.0, 1.0, 2.0]) - // expected-error@-1 3 {{cannot convert value of type 'Double' to expected element type 'Int'}} + // expected-error@-1 {{cannot convert value of type 'Double' to expected element type 'Int'}} // We don't allow these conversions outside of function arguments. var x: UnsafePointer = &i // expected-error {{use of extraneous '&'}} diff --git a/test/expr/cast/as_coerce.swift b/test/expr/cast/as_coerce.swift index 962c656322ca1..3821104d339e1 100644 --- a/test/expr/cast/as_coerce.swift +++ b/test/expr/cast/as_coerce.swift @@ -84,13 +84,13 @@ c3 as C4 // expected-error {{'C3' is not convertible to 'C4'; did you mean to us Double(1) as Double as String // expected-error{{cannot convert value of type 'Double' to type 'String' in coercion}} ["awd"] as [Int] // expected-error{{cannot convert value of type 'String' to expected element type 'Int'}} ([1, 2, 1.0], 1) as ([String], Int) -// expected-error@-1 2 {{cannot convert value of type 'Int' to expected element type 'String'}} +// expected-error@-1 {{cannot convert value of type 'Int' to expected element type 'String'}} // expected-error@-2 {{cannot convert value of type 'Double' to expected element type 'String'}} [[1]] as [[String]] // expected-error{{cannot convert value of type 'Int' to expected element type 'String'}} (1, 1.0) as (Int, Int) // expected-error{{cannot convert value of type '(Int, Double)' to type '(Int, Int)' in coercion}} (1.0, 1, "asd") as (String, Int, Float) // expected-error{{cannot convert value of type '(Double, Int, String)' to type '(String, Int, Float)' in coercion}} (1, 1.0, "a", [1, 23]) as (Int, Double, String, [String]) -// expected-error@-1 2 {{cannot convert value of type 'Int' to expected element type 'String'}} +// expected-error@-1 {{cannot convert value of type 'Int' to expected element type 'String'}} _ = [1] as! [String] // OK _ = [(1, (1, 1))] as! [(Int, (String, Int))] // OK From cd44ca87a95e4b3d16092650fd7d6c274c9f60b5 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Wed, 5 Aug 2020 14:23:15 -0700 Subject: [PATCH 030/123] [ConstraintSystem] Move getAtomicLiteralKind to TypeVariableType::Implementation --- lib/Sema/CSSimplify.cpp | 26 ------------------------ lib/Sema/ConstraintSystem.h | 33 ++++++++++++++++--------------- lib/Sema/TypeCheckConstraints.cpp | 18 +++++++++++++++++ 3 files changed, 35 insertions(+), 42 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 4dff72adf8ecf..1b56708233a73 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -32,8 +32,6 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Support/Compiler.h" -#include - using namespace swift; using namespace constraints; @@ -10421,30 +10419,6 @@ void ConstraintSystem::addContextualConversionConstraint( convertTypeLocator, /*isFavored*/ true); } -Optional -ConstraintSystem::getAtomicLiteralKind(TypeVariableType *typeVar) const { - const std::unordered_set atomicLiteralKinds = { - ExprKind::IntegerLiteral, - ExprKind::FloatLiteral, - ExprKind::StringLiteral, - ExprKind::BooleanLiteral, - ExprKind::NilLiteral, - }; - - if (!typeVar) - return None; - - auto *locator = typeVar->getImpl().getLocator(); - if (!locator->directlyAt()) - return None; - - auto literalKind = getAsExpr(locator->getAnchor())->getKind(); - if (!atomicLiteralKinds.count(literalKind)) - return None; - - return literalKind; -} - void ConstraintSystem::addFixConstraint(ConstraintFix *fix, ConstraintKind kind, Type first, Type second, ConstraintLocatorBuilder locator, diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 7ec7c1d71e760..d92deeb275fc3 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -306,6 +306,11 @@ class TypeVariableType::Implementation { /// Retrieve the generic parameter opened by this type variable. GenericTypeParamType *getGenericParameter() const; + /// Returns the \c ExprKind of this type variable if it's the type of an + /// atomic literal expression, meaning the literal can't be composed of subexpressions. + /// Otherwise, returns \c None. + Optional getAtomicLiteralKind() const; + /// Determine whether this type variable represents a closure type. bool isClosureType() const; @@ -2994,11 +2999,6 @@ class ConstraintSystem { bool isDeclUnavailable(const Decl *D, ConstraintLocator *locator = nullptr) const; - /// Returns the \c ExprKind of the given type variable if it's the type of an - /// atomic literal expression, meaning the literal can't be composed of subexpressions. - /// Otherwise, returns \c None. - Optional getAtomicLiteralKind(TypeVariableType *typeVar) const; - public: /// Whether we should attempt to fix problems. @@ -3127,18 +3127,19 @@ class ConstraintSystem { // We can merge the type variables of same-kind atomic literal expressions because they // will all have the same set of constraints and therefore can never resolve to anything // different. - auto *typeVar = type->getAs(); - if (auto literalKind = getAtomicLiteralKind(typeVar)) { - auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; - auto *currentRep = getRepresentative(typeVar); - - if (originalRep) { - if (originalRep != currentRep) - mergeEquivalenceClasses(currentRep, originalRep); - continue; - } + if (auto *typeVar = type->getAs()) { + if (auto literalKind = typeVar->getImpl().getAtomicLiteralKind()) { + auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; + auto *currentRep = getRepresentative(typeVar); + + if (originalRep) { + if (originalRep != currentRep) + mergeEquivalenceClasses(currentRep, originalRep); + continue; + } - originalRep = currentRep; + originalRep = currentRep; + } } // Introduce conversions from each input type to the supertype. diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index a1fb7d85d4568..74233bfa05004 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -82,6 +82,24 @@ TypeVariableType::Implementation::getGenericParameter() const { return locator ? locator->getGenericParameter() : nullptr; } +Optional +TypeVariableType::Implementation::getAtomicLiteralKind() const { + if (!locator || !locator->directlyAt()) + return None; + + auto kind = getAsExpr(locator->getAnchor())->getKind(); + switch (kind) { + case ExprKind::IntegerLiteral: + case ExprKind::FloatLiteral: + case ExprKind::StringLiteral: + case ExprKind::BooleanLiteral: + case ExprKind::NilLiteral: + return kind; + default: + return None; + } +} + bool TypeVariableType::Implementation::isClosureType() const { if (!(locator && locator->getAnchor())) return false; From c41dd2126cef7740ac8b7c0c5427b78777738f89 Mon Sep 17 00:00:00 2001 From: Eric Miotto <1094986+edymtt@users.noreply.github.com> Date: Wed, 5 Aug 2020 07:56:20 -0700 Subject: [PATCH 031/123] [test] Ensure clang importer sdk uses its own CoreFoundation overlay We noticed that Some tests using the clang importer sdk ended up using the CoreFoundation overlay built as part of Swift instead of the mock one provided. --- test/IDE/print_clang_header_i386.swift | 4 +++- .../clang-importer-sdk/swift-modules/CoreFoundation.swift | 2 +- test/lit.cfg | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/IDE/print_clang_header_i386.swift b/test/IDE/print_clang_header_i386.swift index 4774771e3fb83..d78436f712305 100644 --- a/test/IDE/print_clang_header_i386.swift +++ b/test/IDE/print_clang_header_i386.swift @@ -4,5 +4,7 @@ // XFAIL: linux, freebsd // RUN: echo '#include "header-to-print.h"' > %t.i386.m -// RUN: %target-swift-ide-test -source-filename %s -print-header -header-to-print %S/Inputs/print_clang_header/header-to-print.h -print-regular-comments --cc-args -arch i386 -isysroot %clang-importer-sdk-path -fsyntax-only %t.i386.m -I %S/Inputs/print_clang_header > %t.i386.txt +// RUN: %empty-directory(%t) +// RUN: %build-clang-importer-objc-overlays +// RUN: %target-swift-ide-test -source-filename %s -print-header -header-to-print %S/Inputs/print_clang_header/header-to-print.h -print-regular-comments -I %t --cc-args -arch i386 -isysroot %clang-importer-sdk-path -fsyntax-only %t.i386.m -I %S/Inputs/print_clang_header > %t.i386.txt // RUN: diff -u %S/Inputs/print_clang_header/header-to-print.h.printed.txt %t.i386.txt diff --git a/test/Inputs/clang-importer-sdk/swift-modules/CoreFoundation.swift b/test/Inputs/clang-importer-sdk/swift-modules/CoreFoundation.swift index 960250708c027..8c447d83713de 100644 --- a/test/Inputs/clang-importer-sdk/swift-modules/CoreFoundation.swift +++ b/test/Inputs/clang-importer-sdk/swift-modules/CoreFoundation.swift @@ -1,3 +1,3 @@ @_exported import CoreFoundation -protocol _CFObject {} +protocol _CFObject: Hashable {} diff --git a/test/lit.cfg b/test/lit.cfg index 629388790da42..2f82280a0494c 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -459,6 +459,7 @@ config.substitutions.append( ('%clang-include-dir', config.clang_include_dir) ) config.substitutions.append(('%build-clang-importer-objc-overlays', '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/ObjectiveC.swift -disable-objc-attr-requires-foundation-module && ' '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/CoreGraphics.swift && ' + '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/CoreFoundation.swift && ' '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/Foundation.swift')) # FIXME: BEGIN -enable-source-import hackaround From 65327aefabfc11dfff4ddbcfbe8b5195e3e78a1b Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 5 Aug 2020 18:02:52 -0700 Subject: [PATCH 032/123] test: repair the prespecialized-metadata tests on ASi Introduce `llvm_src_root` and `llvm_obj_root` to mirror `swift_src_root` and `swift_obj_root`. This allows us to repair the paths used in the tests without having to hardcode the build layout into the tests. --- test/IRGen/prespecialized-metadata/class-class-flags-run.swift | 2 +- test/IRGen/prespecialized-metadata/enum-extradata-run.swift | 2 +- .../IRGen/prespecialized-metadata/enum-trailing-flags-run.swift | 2 +- test/IRGen/prespecialized-metadata/struct-extradata-run.swift | 2 +- .../prespecialized-metadata/struct-multi-conformance.swift | 2 +- test/IRGen/prespecialized-metadata/struct-outmodule-run.swift | 2 +- .../prespecialized-metadata/struct-trailing-flags-run.swift | 2 +- test/lit.cfg | 2 ++ 8 files changed, 9 insertions(+), 7 deletions(-) diff --git a/test/IRGen/prespecialized-metadata/class-class-flags-run.swift b/test/IRGen/prespecialized-metadata/class-class-flags-run.swift index 2663a2cca72e6..55ff2d6fcc035 100644 --- a/test/IRGen/prespecialized-metadata/class-class-flags-run.swift +++ b/test/IRGen/prespecialized-metadata/class-class-flags-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -v %mcp_opt %s %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -Xfrontend -prespecialize-generic-metadata -target %module-target-future -lc++ -L %clang-include-dir/../lib/swift/macosx -sdk %sdk -o %t/main // RUN: %target-codesign %t/main diff --git a/test/IRGen/prespecialized-metadata/enum-extradata-run.swift b/test/IRGen/prespecialized-metadata/enum-extradata-run.swift index 95a5442e2b714..14b4cc981df34 100644 --- a/test/IRGen/prespecialized-metadata/enum-extradata-run.swift +++ b/test/IRGen/prespecialized-metadata/enum-extradata-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -c %S/Inputs/enum-extra-data-fields.swift -emit-library -emit-module -enable-library-evolution -module-name ExtraDataFieldsNoTrailingFlags -target %module-target-future -Xfrontend -disable-generic-metadata-prespecialization -emit-module-path %t/ExtraDataFieldsNoTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsNoTrailingFlags) // RUN: %target-build-swift -c %S/Inputs/enum-extra-data-fields.swift -emit-library -emit-module -enable-library-evolution -module-name ExtraDataFieldsTrailingFlags -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/ExtraDataFieldsTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsTrailingFlags) diff --git a/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift b/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift index ea75b7539bce4..227b8f31f23ec 100644 --- a/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift +++ b/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -v %mcp_opt %s %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -Xfrontend -prespecialize-generic-metadata -target %module-target-future -lc++ -L %clang-include-dir/../lib/swift/macosx -sdk %sdk -o %t/main // RUN: %target-codesign %t/main diff --git a/test/IRGen/prespecialized-metadata/struct-extradata-run.swift b/test/IRGen/prespecialized-metadata/struct-extradata-run.swift index f19d12e904ccc..4c17598420c26 100644 --- a/test/IRGen/prespecialized-metadata/struct-extradata-run.swift +++ b/test/IRGen/prespecialized-metadata/struct-extradata-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -c %S/Inputs/struct-extra-data-fields.swift -emit-library -emit-module -module-name ExtraDataFieldsNoTrailingFlags -target %module-target-future -Xfrontend -disable-generic-metadata-prespecialization -emit-module-path %t/ExtraDataFieldsNoTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsNoTrailingFlags) // RUN: %target-build-swift -c %S/Inputs/struct-extra-data-fields.swift -emit-library -emit-module -module-name ExtraDataFieldsTrailingFlags -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/ExtraDataFieldsTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsTrailingFlags) diff --git a/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift b/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift index 6b5673c8ce58a..2eadbb46f97ca 100644 --- a/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift +++ b/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift @@ -5,7 +5,7 @@ // RUN: %target-build-swift -c %s -DCONFORMANCE_2 -emit-library -emit-module -module-name Conformance2 -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Conformance2.swiftmodule -o %t/%target-library-name(Conformance2) -lBase -I %t -L %t // RUN: %target-build-swift -c %s -DGENERIC -emit-library -emit-module -module-name Generic -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Generic.swiftmodule -o %t/%target-library-name(Generic) -lBase -lConformance1 -I %t -L %t // RUN: %target-build-swift -c %s -DERASE -emit-library -emit-module -module-name Erase -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Erase.swiftmodule -o %t/%target-library-name(Erase) -lBase -lConformance2 -I %t -L %t -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift %s %S/Inputs/main.swift %S/Inputs/consume-logging-metadata-value.swift %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -DMAIN -target %module-target-future -Xfrontend -prespecialize-generic-metadata -lBase -lConformance1 -lConformance2 -lGeneric -lErase -lc++ -I %t -L %t -L %clang-include-dir/../lib/swift/macosx -o %t/main // RUN: %target-codesign %t/main diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift index d1358133b9288..d91573301b7ed 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift %S/Inputs/struct-public-nonfrozen-1argument.swift -emit-module -emit-library -module-name Module -Xfrontend -prespecialize-generic-metadata -target %module-target-future -emit-module-path %t/Module.swiftmodule -o %t/%target-library-name(Module) diff --git a/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift b/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift index 97001c01108c2..a896e21db6e9f 100644 --- a/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift +++ b/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -v %mcp_opt %s %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -Xfrontend -prespecialize-generic-metadata -target %module-target-future -lc++ -L %clang-include-dir/../lib/swift/macosx -sdk %sdk -o %t/main // RUN: %target-codesign %t/main diff --git a/test/lit.cfg b/test/lit.cfg index ca232b6f717a6..1cb11d6883cc7 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -386,6 +386,8 @@ lit_config.note("Using code completion cache: " + completion_cache_path) config.substitutions.append( ('%validate-incrparse', '%{python} %utils/incrparse/validate_parse.py --temp-dir %t --swift-syntax-test %swift-syntax-test') ) config.substitutions.append( ('%incr-transfer-tree', '%{python} %utils/incrparse/incr_transfer_tree.py --temp-dir %t --swift-syntax-test %swift-syntax-test') ) +config.substitutions.append( ('%llvm_obj_root', config.llvm_obj_root) ) +config.substitutions.append( ('%llvm_src_root', config.llvm_src_root) ) config.substitutions.append( ('%swift_obj_root', config.swift_obj_root) ) config.substitutions.append( ('%swift_src_root', config.swift_src_root) ) config.substitutions.append( ('%{python}', pipes.quote(sys.executable)) ) From 48b0802b6324003ec04f3164a06ad51cadb2b9d5 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 6 Aug 2020 09:02:57 -0700 Subject: [PATCH 033/123] test: swap parameters in test assertion (NFC) Swap the parameters in `assertEqual` to improve diagnostics on failure. This now prints as: ``` stdout>>> expected: -431 (of type Swift.int) stdout>>> actual: -11 (of type Swift.int) ``` --- test/stdlib/Dispatch.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/stdlib/Dispatch.swift b/test/stdlib/Dispatch.swift index 1f0403e2aade7..ee712560f306f 100644 --- a/test/stdlib/Dispatch.swift +++ b/test/stdlib/Dispatch.swift @@ -278,8 +278,8 @@ DispatchAPI.test("DispatchTime.SchedulerTimeType.Stridable") { let time1 = DispatchQueue.SchedulerTimeType(.init(uptimeNanoseconds: 10000)) let time2 = DispatchQueue.SchedulerTimeType(.init(uptimeNanoseconds: 10431)) let addedTime = time2.distance(to: time1) - expectEqual(addedTime.magnitude, (10000 - 10431)) + expectEqual((10000 - 10431), addedTime.magnitude) } } -#endif \ No newline at end of file +#endif From 7966ab4c4ccd30c3a68b1371aba2a01f226b7c95 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 6 Aug 2020 09:17:28 -0700 Subject: [PATCH 034/123] test: disable a couple of IRGen tests on ASi macOS[>=10.14.4] support the ability to update the class metadata, which is used unconditionally with resiliently-sized fields. --- test/IRGen/class_update_callback_without_fixed_layout.sil | 2 +- test/IRGen/eager-class-initialization.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/IRGen/class_update_callback_without_fixed_layout.sil b/test/IRGen/class_update_callback_without_fixed_layout.sil index 1a06330329bd2..72a1e63775cf0 100644 --- a/test/IRGen/class_update_callback_without_fixed_layout.sil +++ b/test/IRGen/class_update_callback_without_fixed_layout.sil @@ -6,7 +6,7 @@ // REQUIRES: objc_interop // UNSUPPORTED: OS=iosmac -// UNSUPPORTED: CPU=arm64e +// UNSUPPORTED: CPU=arm64 || CPU=arm64e // With the old deployment target, these classes use the 'singleton' metadata // initialization pattern. The class is not statically visible to Objective-C, diff --git a/test/IRGen/eager-class-initialization.swift b/test/IRGen/eager-class-initialization.swift index 53b172256bca3..0f19d2f5cc63e 100644 --- a/test/IRGen/eager-class-initialization.swift +++ b/test/IRGen/eager-class-initialization.swift @@ -4,7 +4,7 @@ // REQUIRES: objc_interop // UNSUPPORTED: OS=iosmac -// UNSUPPORTED: CPU=arm64e +// UNSUPPORTED: CPU=arm64 || CPU=arm64e // See also eager-class-initialization-stable-abi.swift, for the stable ABI // deployment target test. From 145b8ae35ddbf52b7b8f144daab84f12b3c7d3ba Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Thu, 6 Aug 2020 19:02:11 +0200 Subject: [PATCH 035/123] LLVMMergeFunctions: allow more parameters if the function is bigger We had a fixed limit of 4 added parameters for merged functions. But if a function is big, it makes sense to allow more parameters to be added. Now, derived the maximum number of parameters from the function size. This increases the chances that big functions (which likely require more parameters) are merged. --- lib/LLVMPasses/LLVMMergeFunctions.cpp | 61 +++++++++++++++------------ 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/lib/LLVMPasses/LLVMMergeFunctions.cpp b/lib/LLVMPasses/LLVMMergeFunctions.cpp index da76bba87217f..51db1af2f4892 100644 --- a/lib/LLVMPasses/LLVMMergeFunctions.cpp +++ b/lib/LLVMPasses/LLVMMergeFunctions.cpp @@ -222,12 +222,6 @@ class SwiftMergeFunctions : public ModulePass { bool runOnModule(Module &M) override; private: - enum { - /// The maximum number of parameters added to a merged functions. This - /// roughly corresponds to the number of differing constants. - maxAddedParams = 4 - }; - struct FunctionEntry; /// Describes the set of functions which are considered as "equivalent" (i.e. @@ -359,7 +353,7 @@ class SwiftMergeFunctions : public ModulePass { } }; - using ParamInfos = SmallVector; + using ParamInfos = SmallVector; GlobalNumberState GlobalNumbers; @@ -398,14 +392,15 @@ class SwiftMergeFunctions : public ModulePass { FunctionInfo removeFuncWithMostParams(FunctionInfos &FInfos); - bool deriveParams(ParamInfos &Params, FunctionInfos &FInfos); + bool deriveParams(ParamInfos &Params, FunctionInfos &FInfos, + unsigned maxParams); bool numOperandsDiffer(FunctionInfos &FInfos); bool constsDiffer(const FunctionInfos &FInfos, unsigned OpIdx); bool tryMapToParameter(FunctionInfos &FInfos, unsigned OpIdx, - ParamInfos &Params); + ParamInfos &Params, unsigned maxParams); void mergeWithParams(const FunctionInfos &FInfos, ParamInfos &Params); @@ -524,17 +519,9 @@ static bool mayMergeCallsToFunction(Function &F) { return true; } -/// Returns true if function \p F is eligible for merging. -static bool isEligibleFunction(Function *F) { - if (F->isDeclaration()) - return false; - - if (F->hasAvailableExternallyLinkage()) - return false; - - if (F->getFunctionType()->isVarArg()) - return false; - +/// Returns the benefit, which is approximately the size of the function. +/// Return 0, if the function should not be merged. +static unsigned getBenefit(Function *F) { unsigned Benefit = 0; // We don't want to merge very small functions, because the overhead of @@ -545,7 +532,7 @@ static bool isEligibleFunction(Function *F) { if (CallBase *CB = dyn_cast(&I)) { Function *Callee = CB->getCalledFunction(); if (Callee && !mayMergeCallsToFunction(*Callee)) - return false; + return 0; if (!Callee || !Callee->isIntrinsic()) { Benefit += 5; continue; @@ -554,6 +541,21 @@ static bool isEligibleFunction(Function *F) { Benefit += 1; } } + return Benefit; +} + +/// Returns true if function \p F is eligible for merging. +static bool isEligibleFunction(Function *F) { + if (F->isDeclaration()) + return false; + + if (F->hasAvailableExternallyLinkage()) + return false; + + if (F->getFunctionType()->isVarArg()) + return false; + + unsigned Benefit = getBenefit(F); if (Benefit < FunctionMergeThreshold) return false; @@ -723,12 +725,17 @@ bool SwiftMergeFunctions::tryMergeEquivalenceClass(FunctionEntry *FirstInClass) bool Changed = false; int Try = 0; + unsigned Benefit = getBenefit(FirstInClass->F); + + // The bigger the function, the more parameters are allowed. + unsigned maxParams = std::max(4u, Benefit / 100); + // We need multiple tries if there are some functions in FInfos which differ // too much from the first function in FInfos. But we limit the number of // tries to a small number, because this is quadratic. while (FInfos.size() >= 2 && Try++ < 4) { ParamInfos Params; - bool Merged = deriveParams(Params, FInfos); + bool Merged = deriveParams(Params, FInfos, maxParams); if (Merged) { mergeWithParams(FInfos, Params); Changed = true; @@ -767,7 +774,8 @@ removeFuncWithMostParams(FunctionInfos &FInfos) { /// Returns true on success, i.e. the functions in \p FInfos can be merged with /// the parameters returned in \p Params. bool SwiftMergeFunctions::deriveParams(ParamInfos &Params, - FunctionInfos &FInfos) { + FunctionInfos &FInfos, + unsigned maxParams) { for (FunctionInfo &FI : FInfos) FI.init(); @@ -796,7 +804,7 @@ bool SwiftMergeFunctions::deriveParams(ParamInfos &Params, if (constsDiffer(FInfos, OpIdx)) { // This instruction has operands which differ in at least some // functions. So we need to parameterize it. - if (!tryMapToParameter(FInfos, OpIdx, Params)) { + if (!tryMapToParameter(FInfos, OpIdx, Params, maxParams)) { // We ran out of parameters. return false; } @@ -845,7 +853,8 @@ bool SwiftMergeFunctions::constsDiffer(const FunctionInfos &FInfos, /// Returns true if a parameter could be created or found without exceeding the /// maximum number of parameters. bool SwiftMergeFunctions::tryMapToParameter(FunctionInfos &FInfos, - unsigned OpIdx, ParamInfos &Params) { + unsigned OpIdx, ParamInfos &Params, + unsigned maxParams) { ParamInfo *Matching = nullptr; // Try to find an existing parameter which exactly matches the differing // operands of the current instruction. @@ -858,7 +867,7 @@ bool SwiftMergeFunctions::tryMapToParameter(FunctionInfos &FInfos, if (!Matching) { // We need a new parameter. // Check if we are within the limit. - if (Params.size() >= maxAddedParams) + if (Params.size() >= maxParams) return false; Params.resize(Params.size() + 1); From 755f6aa2e40ada035887c5d167dd40dc96502a9b Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Tue, 4 Aug 2020 17:14:13 +0200 Subject: [PATCH 036/123] AST, SIL: Remove UTF16 encoding from StringLiteralExpr and StringLiteralInst The UTF16 encoding is not used (anymore). I think it became obsolete with the switch to the UTF8 String representation. --- include/swift/AST/Expr.h | 3 --- include/swift/Basic/Unicode.h | 4 ---- include/swift/SIL/SILInstruction.h | 1 - lib/AST/ASTDumper.cpp | 1 - lib/Basic/Unicode.cpp | 19 ------------------- lib/IRGen/GenConstant.cpp | 8 -------- lib/SIL/IR/SILGlobalVariable.cpp | 1 - lib/SIL/IR/SILInstructions.cpp | 3 --- lib/SIL/IR/SILPrinter.cpp | 1 - lib/SIL/Parser/ParseSIL.cpp | 2 -- lib/SILGen/SILGenApply.cpp | 10 ---------- .../Utils/SpecializationMangler.cpp | 1 - lib/Serialization/DeserializeSIL.cpp | 1 - lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/SILFormat.h | 1 - lib/Serialization/SerializeSIL.cpp | 1 - test/IRGen/literals.sil | 15 --------------- test/SILOptimizer/cse.sil | 2 +- test/SILOptimizer/sil_combine.sil | 6 +++--- 19 files changed, 5 insertions(+), 77 deletions(-) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index a62c045674a18..7d3ee3823d2a5 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -861,9 +861,6 @@ class StringLiteralExpr : public LiteralExpr { /// A UTF-8 string. UTF8, - /// A UTF-16 string. - UTF16, - /// A single UnicodeScalar, passed as an integer. OneUnicodeScalar }; diff --git a/include/swift/Basic/Unicode.h b/include/swift/Basic/Unicode.h index ff2163eb0f374..4b1108af7fac1 100644 --- a/include/swift/Basic/Unicode.h +++ b/include/swift/Basic/Unicode.h @@ -68,10 +68,6 @@ bool isSingleUnicodeScalar(StringRef S); unsigned extractFirstUnicodeScalar(StringRef S); -/// Get the length of the UTF8 string transcoded into UTF16. -/// Returns the number of code units in UTF16 representation -uint64_t getUTF16Length(StringRef Str); - } // end namespace unicode } // end namespace swift diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index dd9e3731b9ac9..d504f37085831 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -3307,7 +3307,6 @@ class StringLiteralInst final enum class Encoding { Bytes, UTF8, - UTF16, /// UTF-8 encoding of an Objective-C selector. ObjCSelector, }; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 94e6654c5562b..8d46581edb4bf 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -368,7 +368,6 @@ static StringRef getStringLiteralExprEncodingString(StringLiteralExpr::Encoding value) { switch (value) { case StringLiteralExpr::UTF8: return "utf8"; - case StringLiteralExpr::UTF16: return "utf16"; case StringLiteralExpr::OneUnicodeScalar: return "unicodeScalar"; } diff --git a/lib/Basic/Unicode.cpp b/lib/Basic/Unicode.cpp index a299c457a7805..e7479be57820f 100644 --- a/lib/Basic/Unicode.cpp +++ b/lib/Basic/Unicode.cpp @@ -123,22 +123,3 @@ unsigned swift::unicode::extractFirstUnicodeScalar(StringRef S) { (void)Result; return Scalar; } - -uint64_t swift::unicode::getUTF16Length(StringRef Str) { - uint64_t Length; - // Transcode the string to UTF-16 to get its length. - SmallVector buffer(Str.size() + 1); // +1 for ending nulls. - const llvm::UTF8 *fromPtr = (const llvm::UTF8 *) Str.data(); - llvm::UTF16 *toPtr = &buffer[0]; - llvm::ConversionResult Result = - ConvertUTF8toUTF16(&fromPtr, fromPtr + Str.size(), - &toPtr, toPtr + Str.size(), - llvm::strictConversion); - assert(Result == llvm::conversionOK && - "UTF-8 encoded string cannot be converted into UTF-16 encoding"); - (void)Result; - - // The length of the transcoded string in UTF-16 code points. - Length = toPtr - &buffer[0]; - return Length; -} diff --git a/lib/IRGen/GenConstant.cpp b/lib/IRGen/GenConstant.cpp index 071d49f82603b..0d6e021e8327f 100644 --- a/lib/IRGen/GenConstant.cpp +++ b/lib/IRGen/GenConstant.cpp @@ -102,14 +102,6 @@ llvm::Constant *irgen::emitAddrOfConstantString(IRGenModule &IGM, case StringLiteralInst::Encoding::UTF8: return IGM.getAddrOfGlobalString(SLI->getValue()); - case StringLiteralInst::Encoding::UTF16: { - // This is always a GEP of a GlobalVariable with a nul terminator. - auto addr = IGM.getAddrOfGlobalUTF16String(SLI->getValue()); - - // Cast to Builtin.RawPointer. - return llvm::ConstantExpr::getBitCast(addr, IGM.Int8PtrTy); - } - case StringLiteralInst::Encoding::ObjCSelector: llvm_unreachable("cannot get the address of an Objective-C selector"); } diff --git a/lib/SIL/IR/SILGlobalVariable.cpp b/lib/SIL/IR/SILGlobalVariable.cpp index bad50c8437f93..609a8318b153d 100644 --- a/lib/SIL/IR/SILGlobalVariable.cpp +++ b/lib/SIL/IR/SILGlobalVariable.cpp @@ -157,7 +157,6 @@ bool SILGlobalVariable::isValidStaticInitializerInst(const SILInstruction *I, switch (cast(I)->getEncoding()) { case StringLiteralInst::Encoding::Bytes: case StringLiteralInst::Encoding::UTF8: - case StringLiteralInst::Encoding::UTF16: return true; case StringLiteralInst::Encoding::ObjCSelector: // Objective-C selector string literals cannot be used in static diff --git a/lib/SIL/IR/SILInstructions.cpp b/lib/SIL/IR/SILInstructions.cpp index 85e21ea609f21..1faa9ec6ae6a1 100644 --- a/lib/SIL/IR/SILInstructions.cpp +++ b/lib/SIL/IR/SILInstructions.cpp @@ -1043,9 +1043,6 @@ CondFailInst *CondFailInst::create(SILDebugLocation DebugLoc, SILValue Operand, } uint64_t StringLiteralInst::getCodeUnitCount() { - auto E = unsigned(Encoding::UTF16); - if (SILInstruction::Bits.StringLiteralInst.TheEncoding == E) - return unicode::getUTF16Length(getValue()); return SILInstruction::Bits.StringLiteralInst.Length; } diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index d4da68de7622f..bb84c23ef1e4c 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -1339,7 +1339,6 @@ class SILPrinter : public SILInstructionVisitor { switch (kind) { case StringLiteralInst::Encoding::Bytes: return "bytes "; case StringLiteralInst::Encoding::UTF8: return "utf8 "; - case StringLiteralInst::Encoding::UTF16: return "utf16 "; case StringLiteralInst::Encoding::ObjCSelector: return "objc_selector "; } llvm_unreachable("bad string literal encoding"); diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 61f099db1956f..00ceaf52ca02e 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -2619,8 +2619,6 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, StringLiteralInst::Encoding encoding; if (P.Tok.getText() == "utf8") { encoding = StringLiteralInst::Encoding::UTF8; - } else if (P.Tok.getText() == "utf16") { - encoding = StringLiteralInst::Encoding::UTF16; } else if (P.Tok.getText() == "objc_selector") { encoding = StringLiteralInst::Encoding::ObjCSelector; } else if (P.Tok.getText() == "bytes") { diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index c8c80a3f1d3f3..bffecc2c2c187 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -1628,11 +1628,6 @@ static PreparedArguments emitStringLiteral(SILGenFunction &SGF, Expr *E, Length = Str.size(); break; - case StringLiteralExpr::UTF16: { - instEncoding = StringLiteralInst::Encoding::UTF16; - Length = unicode::getUTF16Length(Str); - break; - } case StringLiteralExpr::OneUnicodeScalar: { SILType Int32Ty = SILType::getBuiltinIntegerType(32, SGF.getASTContext()); SILValue UnicodeScalarValue = @@ -1674,11 +1669,6 @@ static PreparedArguments emitStringLiteral(SILGenFunction &SGF, Expr *E, ArrayRef Elts; ArrayRef TypeElts; switch (instEncoding) { - case StringLiteralInst::Encoding::UTF16: - Elts = llvm::makeArrayRef(EltsArray).slice(0, 2); - TypeElts = llvm::makeArrayRef(TypeEltsArray).slice(0, 2); - break; - case StringLiteralInst::Encoding::UTF8: Elts = EltsArray; TypeElts = TypeEltsArray; diff --git a/lib/SILOptimizer/Utils/SpecializationMangler.cpp b/lib/SILOptimizer/Utils/SpecializationMangler.cpp index 9807b43eb5f6d..3a37e3f3430ba 100644 --- a/lib/SILOptimizer/Utils/SpecializationMangler.cpp +++ b/lib/SILOptimizer/Utils/SpecializationMangler.cpp @@ -243,7 +243,6 @@ FunctionSignatureSpecializationMangler::mangleConstantProp(LiteralInst *LI) { switch (SLI->getEncoding()) { case StringLiteralInst::Encoding::Bytes: ArgOpBuffer << 'B'; break; case StringLiteralInst::Encoding::UTF8: ArgOpBuffer << 'b'; break; - case StringLiteralInst::Encoding::UTF16: ArgOpBuffer << 'w'; break; case StringLiteralInst::Encoding::ObjCSelector: ArgOpBuffer << 'c'; break; } break; diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 26ee442264524..97c84001d009c 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -53,7 +53,6 @@ fromStableStringEncoding(unsigned value) { switch (value) { case SIL_BYTES: return StringLiteralInst::Encoding::Bytes; case SIL_UTF8: return StringLiteralInst::Encoding::UTF8; - case SIL_UTF16: return StringLiteralInst::Encoding::UTF16; case SIL_OBJC_SELECTOR: return StringLiteralInst::Encoding::ObjCSelector; default: return None; } diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 6bf15541faf97..b3a7a893f0932 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 567; // async sil modifier +const uint16_t SWIFTMODULE_VERSION_MINOR = 568; // removed UTF16 /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index 3a68d6c0baddf..dfa1ea155b886 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -31,7 +31,6 @@ using SILTypeCategoryField = BCFixed<2>; enum SILStringEncoding : uint8_t { SIL_UTF8, - SIL_UTF16, SIL_OBJC_SELECTOR, SIL_BYTES }; diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 849138d351534..00e9443213ea0 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -49,7 +49,6 @@ static unsigned toStableStringEncoding(StringLiteralInst::Encoding encoding) { switch (encoding) { case StringLiteralInst::Encoding::Bytes: return SIL_BYTES; case StringLiteralInst::Encoding::UTF8: return SIL_UTF8; - case StringLiteralInst::Encoding::UTF16: return SIL_UTF16; case StringLiteralInst::Encoding::ObjCSelector: return SIL_OBJC_SELECTOR; } llvm_unreachable("bad string encoding"); diff --git a/test/IRGen/literals.sil b/test/IRGen/literals.sil index 193bf812b86ce..24c2b9450780d 100644 --- a/test/IRGen/literals.sil +++ b/test/IRGen/literals.sil @@ -4,8 +4,6 @@ // CHECK: [[U8_0:@.*]] = private unnamed_addr constant [8 x i8] c"help\09me\00" // CHECK: [[U8_1:@.*]] = private unnamed_addr constant [5 x i8] c"\00x\C6\AB\00" -// CHECK: [[U16_0:@.*]] = private unnamed_addr constant [8 x i16] [i16 104, i16 101, i16 108, i16 112, i16 9, i16 109, i16 101, i16 0] -// CHECK: [[U16_1:@.*]] = private unnamed_addr constant [4 x i16] [i16 0, i16 120, i16 427, i16 0] sil_stage canonical @@ -27,16 +25,3 @@ bb0: // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8* @utf8_literal_with_nul() {{.*}} { // CHECK: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[U8_1]], i64 0, i64 0) -sil @utf16_literal : $@convention(thin) () -> Builtin.RawPointer { -bb0: - %0 = string_literal utf16 "help\tme" - return %0 : $Builtin.RawPointer -} -// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8* @utf16_literal() {{.*}} { -// CHECK: ret i8* bitcast ([8 x i16]* [[U16_0]] to i8*) - -sil @utf16_literal_with_nul : $@convention(thin) () -> Builtin.RawPointer { -bb0: - %0 = string_literal utf16 "\u{00}x\u{01ab}" - return %0 : $Builtin.RawPointer -} diff --git a/test/SILOptimizer/cse.sil b/test/SILOptimizer/cse.sil index 52f65b49001b3..60df4ccb7d4a6 100644 --- a/test/SILOptimizer/cse.sil +++ b/test/SILOptimizer/cse.sil @@ -523,7 +523,7 @@ sil @helper2 : $@convention(thin) (UInt8, UInt8) -> Builtin.Word // CHECK-LABEL: sil @sil_string_different_encodings sil @sil_string_different_encodings : $@convention(thin) () -> Builtin.Word { %0 = string_literal utf8 "help" - %1 = string_literal utf16 "help" + %1 = string_literal objc_selector "help" %2 = function_ref @helper : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer) -> Builtin.Word %3 = apply %2(%0, %1) : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer) -> Builtin.Word return %3 : $Builtin.Word diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil index 81b635f2b21e4..145399c069f35 100644 --- a/test/SILOptimizer/sil_combine.sil +++ b/test/SILOptimizer/sil_combine.sil @@ -1850,7 +1850,7 @@ bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.RawPointer): //CHECK: return sil @remove_pointer_compare_to_zero : $@convention(thin) (Int) -> () { bb0(%0 : $Int): - %1 = string_literal utf16 "ss" + %1 = string_literal utf8 "ss" %2 = integer_literal $Builtin.Word, 0 %4 = builtin "inttoptr_Word"(%2 : $Builtin.Word) : $Builtin.RawPointer %6 = builtin "cmp_eq_RawPointer"(%1 : $Builtin.RawPointer, %4 : $Builtin.RawPointer) : $Builtin.Int1 @@ -1865,7 +1865,7 @@ bb0(%0 : $Int): //CHECK: unreachable sil @remove_pointer_compare_to_zero_NE : $@convention(thin) (Int) -> () { bb0(%0 : $Int): - %1 = string_literal utf16 "ss" + %1 = string_literal utf8 "ss" %2 = integer_literal $Builtin.Word, 0 %4 = builtin "inttoptr_Word"(%2 : $Builtin.Word) : $Builtin.RawPointer %6 = builtin "cmp_ne_RawPointer"(%1 : $Builtin.RawPointer, %4 : $Builtin.RawPointer) : $Builtin.Int1 @@ -1881,7 +1881,7 @@ bb0(%0 : $Int): //CHECK: return sil @remove_pointer_compare_to_zero_arith : $@convention(thin) (Builtin.Word) -> () { bb0(%0 : $Builtin.Word): - %1 = string_literal utf16 "ss" + %1 = string_literal utf8 "ss" %2 = integer_literal $Builtin.Word, 0 %3 = integer_literal $Builtin.Word, 4 %4 = integer_literal $Builtin.Int1, -1 From b26554147e850ddeedbdf942c930b5231d345275 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Thu, 6 Aug 2020 10:14:57 -0700 Subject: [PATCH 037/123] [NFC] Document the new type variable merging heuristic in addJoinConstraint --- lib/Sema/ConstraintSystem.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index d92deeb275fc3..0cd6acf1accba 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3096,6 +3096,11 @@ class ConstraintSystem { /// a new type variable or a specified supertype. At some point, we may want /// a new constraint kind to cover the join. /// + /// \note This method will merge any input type variables for atomic literal + /// expressions of the same kind. It assumes that if same-kind literal type + /// variables are joined, there will be no differing constraints on those + /// type variables. + /// /// \returns the joined type, which is generally a new type variable, unless there are /// fewer than 2 input types or the \c supertype parameter is specified. template From 38e2bd9c891e7cc2fc04cc81cc9fef13f842bf0a Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Wed, 5 Aug 2020 14:45:41 -0700 Subject: [PATCH 038/123] [Diagnostics] Demote availability errors to warning for decls in ObjC keypaths to prevent source breakage. The change to resolve ObjC #keyPath expression components caused some source breakage as they are now being checked for availability issues. This change updates availability checking to demote error diagnostics to warnings within #keyPath expressions. There were cases in the source compat suite where unavailble properites were used in #keyPath expressions, but they caused no issues at runtime because the properties' ObjC runtime name was still correct (e.g. the same as its renamed-to property in Swift). --- include/swift/AST/DiagnosticsSema.def | 11 ++++++ lib/Sema/TypeCheckAvailability.cpp | 35 +++++++++++++++----- lib/Sema/TypeCheckAvailability.h | 8 ++++- localization/diagnostics/en.yaml | 10 ++++++ test/expr/primary/keypath/keypath-objc.swift | 14 ++++---- 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index fc9b7f98dd2a0..67d2f281c6ed0 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4657,6 +4657,11 @@ ERROR(availability_decl_unavailable, none, "%select{ in %3|}2%select{|: %4}4", (unsigned, DeclName, bool, StringRef, StringRef)) +WARNING(availability_decl_unavailable_warn, none, + "%select{getter for |setter for |}0%1 is unavailable" + "%select{ in %3|}2%select{|: %4}4", + (unsigned, DeclName, bool, StringRef, StringRef)) + #define REPLACEMENT_DECL_KIND_SELECT "select{| instance method| property}" ERROR(availability_decl_unavailable_rename, none, "%select{getter for |setter for |}0%1 has been " @@ -4664,6 +4669,12 @@ ERROR(availability_decl_unavailable_rename, none, "'%4'%select{|: %5}5", (unsigned, DeclName, bool, unsigned, StringRef, StringRef)) +WARNING(availability_decl_unavailable_rename_warn, none, + "%select{getter for |setter for |}0%1 has been " + "%select{renamed to|replaced by}2%" REPLACEMENT_DECL_KIND_SELECT "3 " + "'%4'%select{|: %5}5", + (unsigned, DeclName, bool, unsigned, StringRef, StringRef)) + NOTE(availability_marked_unavailable, none, "%select{getter for |setter for |}0%1 has been explicitly marked " "unavailable here", (unsigned, DeclName)) diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index b2f41c94c6a37..7fff3ba04aa1f 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -2067,6 +2067,7 @@ void swift::diagnoseUnavailableOverride(ValueDecl *override, diagnoseExplicitUnavailability(base, override->getLoc(), override->getDeclContext(), + /*Flags*/None, [&](InFlightDiagnostic &diag) { ParsedDeclName parsedName = parseDeclName(attr->Rename); if (!parsedName || parsedName.isPropertyAccessor() || @@ -2097,10 +2098,11 @@ void swift::diagnoseUnavailableOverride(ValueDecl *override, /// Emit a diagnostic for references to declarations that have been /// marked as unavailable, either through "unavailable" or "obsoleted:". bool swift::diagnoseExplicitUnavailability(const ValueDecl *D, - SourceRange R, - const DeclContext *DC, - const ApplyExpr *call) { - return diagnoseExplicitUnavailability(D, R, DC, + SourceRange R, + const DeclContext *DC, + const ApplyExpr *call, + DeclAvailabilityFlags Flags) { + return diagnoseExplicitUnavailability(D, R, DC, Flags, [=](InFlightDiagnostic &diag) { fixItAvailableAttrRename(diag, R, D, AvailableAttr::isUnavailable(D), call); @@ -2172,6 +2174,7 @@ bool swift::diagnoseExplicitUnavailability( const ValueDecl *D, SourceRange R, const DeclContext *DC, + DeclAvailabilityFlags Flags, llvm::function_ref attachRenameFixIts) { auto *Attr = AvailableAttr::isUnavailable(D); if (!Attr) @@ -2229,6 +2232,14 @@ bool swift::diagnoseExplicitUnavailability( break; } + // TODO: Consider removing this. + // ObjC keypaths components weren't checked previously, so errors are demoted + // to warnings to avoid source breakage. In some cases unavailable or + // obsolete decls still map to valid ObjC runtime names, so behave correctly + // at runtime, even though their use would produce an error outside of a + // #keyPath expression. + bool warnInObjCKeyPath = Flags.contains(DeclAvailabilityFlag::ForObjCKeyPath); + if (!Attr->Rename.empty()) { SmallString<32> newNameBuf; Optional replaceKind = @@ -2238,7 +2249,9 @@ bool swift::diagnoseExplicitUnavailability( StringRef newName = replaceKind ? newNameBuf.str() : Attr->Rename; EncodedDiagnosticMessage EncodedMessage(Attr->Message); auto diag = - diags.diagnose(Loc, diag::availability_decl_unavailable_rename, + diags.diagnose(Loc, warnInObjCKeyPath + ? diag::availability_decl_unavailable_rename_warn + : diag::availability_decl_unavailable_rename, RawAccessorKind, Name, replaceKind.hasValue(), rawReplaceKind, newName, EncodedMessage.Message); attachRenameFixIts(diag); @@ -2253,7 +2266,9 @@ bool swift::diagnoseExplicitUnavailability( } else { EncodedDiagnosticMessage EncodedMessage(Attr->Message); diags - .diagnose(Loc, diag::availability_decl_unavailable, RawAccessorKind, + .diagnose(Loc, warnInObjCKeyPath + ? diag::availability_decl_unavailable_warn + : diag::availability_decl_unavailable, RawAccessorKind, Name, platform.empty(), platform, EncodedMessage.Message) .highlight(R); } @@ -2501,6 +2516,10 @@ class AvailabilityWalker : public ASTWalker { /// Walk a keypath expression, checking all of its components for /// availability. void maybeDiagKeyPath(KeyPathExpr *KP) { + auto flags = DeclAvailabilityFlags(); + if (KP->isObjC()) + flags = DeclAvailabilityFlag::ForObjCKeyPath; + for (auto &component : KP->getComponents()) { switch (component.getKind()) { case KeyPathExpr::Component::Kind::Property: @@ -2508,7 +2527,7 @@ class AvailabilityWalker : public ASTWalker { auto *decl = component.getDeclRef().getDecl(); auto loc = component.getLoc(); SourceRange range(loc, loc); - diagAvailability(decl, range, nullptr); + diagAvailability(decl, range, nullptr, flags); break; } @@ -2628,7 +2647,7 @@ AvailabilityWalker::diagAvailability(ConcreteDeclRef declRef, SourceRange R, if (TypeChecker::diagnoseInlinableDeclRef(R.Start, declRef, DC, FragileKind)) return true; - if (diagnoseExplicitUnavailability(D, R, DC, call)) + if (diagnoseExplicitUnavailability(D, R, DC, call, Flags)) return true; // Make sure not to diagnose an accessor's deprecation if we already diff --git a/lib/Sema/TypeCheckAvailability.h b/lib/Sema/TypeCheckAvailability.h index 29d3f385abfc8..526db08e892a8 100644 --- a/lib/Sema/TypeCheckAvailability.h +++ b/lib/Sema/TypeCheckAvailability.h @@ -50,6 +50,10 @@ enum class DeclAvailabilityFlag : uint8_t { /// Do not diagnose uses of declarations in versions before they were /// introduced. Used to work around availability-checker bugs. AllowPotentiallyUnavailable = 1 << 3, + + /// If an error diagnostic would normally be emitted, demote the error to a + /// warning. Used for ObjC key path components. + ForObjCKeyPath = 1 << 4 }; using DeclAvailabilityFlags = OptionSet; @@ -70,7 +74,8 @@ void diagnoseUnavailableOverride(ValueDecl *override, bool diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R, const DeclContext *DC, - const ApplyExpr *call); + const ApplyExpr *call, + DeclAvailabilityFlags Flags = None); /// Emit a diagnostic for references to declarations that have been /// marked as unavailable, either through "unavailable" or "obsoleted:". @@ -78,6 +83,7 @@ bool diagnoseExplicitUnavailability( const ValueDecl *D, SourceRange R, const DeclContext *DC, + DeclAvailabilityFlags Flags, llvm::function_ref attachRenameFixIts); /// Check if \p decl has a introduction version required by -require-explicit-availability diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index 37fb5b6e24d9d..59f88017ae467 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -9232,11 +9232,21 @@ %select{getter for |setter for |}0%1 is unavailable%select{ in %3|}2%select{|: %4}4 +- id: availability_decl_unavailable_warn + msg: >- + %select{getter for |setter for |}0%1 is unavailable%select{ in + %3|}2%select{|: %4}4 + - id: availability_decl_unavailable_rename msg: >- %select{getter for |setter for |}0%1 has been %select{renamed to|replaced by}2%select{| instance method| property}3 '%4'%select{|: %5}5 +- id: availability_decl_unavailable_rename_warn + msg: >- + %select{getter for |setter for |}0%1 has been %select{renamed to|replaced + by}2%select{| instance method| property}3 '%4'%select{|: %5}5 + - id: availability_marked_unavailable msg: >- %select{getter for |setter for |}0%1 has been explicitly marked diff --git a/test/expr/primary/keypath/keypath-objc.swift b/test/expr/primary/keypath/keypath-objc.swift index 2a4fa881403b7..94c015ac2d8d3 100644 --- a/test/expr/primary/keypath/keypath-objc.swift +++ b/test/expr/primary/keypath/keypath-objc.swift @@ -57,7 +57,7 @@ func testKeyPath(a: A, b: B) { let _: String = #keyPath(A.propString) // Property of String property (which looks on NSString) - let _: String = #keyPath(A.propString.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} + let _: String = #keyPath(A.propString.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // String property with a suffix let _: String = #keyPath(A.propString).description @@ -72,7 +72,7 @@ func testKeyPath(a: A, b: B) { // Array property (make sure we look at the array element). let _: String = #keyPath(A.propArray) - let _: String = #keyPath(A.propArray.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} + let _: String = #keyPath(A.propArray.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // Dictionary property (make sure we look at the value type). let _: String = #keyPath(A.propDict.anyKeyName) @@ -80,20 +80,20 @@ func testKeyPath(a: A, b: B) { // Set property (make sure we look at the set element). let _: String = #keyPath(A.propSet) - let _: String = #keyPath(A.propSet.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} + let _: String = #keyPath(A.propSet.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // AnyObject property - let _: String = #keyPath(A.propAnyObject.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} + let _: String = #keyPath(A.propAnyObject.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} let _: String = #keyPath(A.propAnyObject.propA) let _: String = #keyPath(A.propAnyObject.propB) let _: String = #keyPath(A.propAnyObject.description) // NSString property - let _: String = #keyPath(A.propNSString.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} + let _: String = #keyPath(A.propNSString.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // NSArray property (AnyObject array element). let _: String = #keyPath(A.propNSArray) - let _: String = #keyPath(A.propNSArray.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} + let _: String = #keyPath(A.propNSArray.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // NSDictionary property (AnyObject value type). let _: String = #keyPath(A.propNSDict.anyKeyName) @@ -101,7 +101,7 @@ func testKeyPath(a: A, b: B) { // NSSet property (AnyObject set element). let _: String = #keyPath(A.propNSSet) - let _: String = #keyPath(A.propNSSet.URLsInText) // expected-error{{'URLsInText' has been renamed to 'urlsInText'}} + let _: String = #keyPath(A.propNSSet.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // Property with keyword name. let _: String = #keyPath(A.repeat) From 8da019c019135dbc4816f4d934079a4ba757d9bb Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 6 Aug 2020 10:36:35 -0700 Subject: [PATCH 039/123] [Syntax] Fix grammar and parsing for 'async'. I had used the wrong kind of token for the contextual 'async' keyword (consistently), as well as flipping the order of async/throws when creating syntax nodes in the parser. Add a `-verify-syntax-tree` test with valid syntax to ensure that we don't make this mistake again. Problem found by Nate Chandler, thanks! --- lib/Parse/ParseType.cpp | 4 ++-- test/Parse/async-syntax.swift | 12 ++++++++++++ utils/gyb_syntax_support/DeclNodes.py | 3 ++- utils/gyb_syntax_support/ExprNodes.py | 3 ++- utils/gyb_syntax_support/TypeNodes.py | 5 +++-- 5 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 test/Parse/async-syntax.swift diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 443f572c04acb..aefea2401c15a 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -465,10 +465,10 @@ ParserResult Parser::parseType(Diag<> MessageID, ParsedFunctionTypeSyntaxBuilder Builder(*SyntaxContext); Builder.useReturnType(std::move(*SyntaxContext->popIf())); Builder.useArrow(SyntaxContext->popToken()); - if (asyncLoc.isValid()) - Builder.useAsyncKeyword(SyntaxContext->popToken()); if (throwsLoc.isValid()) Builder.useThrowsOrRethrowsKeyword(SyntaxContext->popToken()); + if (asyncLoc.isValid()) + Builder.useAsyncKeyword(SyntaxContext->popToken()); auto InputNode(std::move(*SyntaxContext->popIf())); if (auto TupleTypeNode = InputNode.getAs()) { diff --git a/test/Parse/async-syntax.swift b/test/Parse/async-syntax.swift new file mode 100644 index 0000000000000..d0e5c837b2f4e --- /dev/null +++ b/test/Parse/async-syntax.swift @@ -0,0 +1,12 @@ +// RUN: %target-typecheck-verify-swift -enable-experimental-concurrency -verify-syntax-tree + +func asyncGlobal1() async { } +func asyncGlobal2() async throws { } + +typealias AsyncFunc1 = () async -> () +typealias AsyncFunc2 = () async throws -> () + +func testTypeExprs() { + let _ = [() async -> ()]() + let _ = [() async throws -> ()]() +} diff --git a/utils/gyb_syntax_support/DeclNodes.py b/utils/gyb_syntax_support/DeclNodes.py index a6455574654ce..515ea4fe02723 100644 --- a/utils/gyb_syntax_support/DeclNodes.py +++ b/utils/gyb_syntax_support/DeclNodes.py @@ -76,7 +76,8 @@ Node('FunctionSignature', kind='Syntax', children=[ Child('Input', kind='ParameterClause'), - Child('AsyncKeyword', kind='ContextualKeywordToken', + Child('AsyncKeyword', kind='IdentifierToken', + classification='Keyword', text_choices=['async'], is_optional=True), Child('ThrowsOrRethrowsKeyword', kind='Token', is_optional=True, diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py index 730c9bf0d92cb..8b442d8c307a1 100644 --- a/utils/gyb_syntax_support/ExprNodes.py +++ b/utils/gyb_syntax_support/ExprNodes.py @@ -191,7 +191,8 @@ # NOTE: This appears only in SequenceExpr. Node('ArrowExpr', kind='Expr', children=[ - Child('AsyncKeyword', kind='ContextualKeywordToken', + Child('AsyncKeyword', kind='IdentifierToken', + classification='Keyword', text_choices=['async'], is_optional=True), Child('ThrowsToken', kind='ThrowsToken', is_optional=True), diff --git a/utils/gyb_syntax_support/TypeNodes.py b/utils/gyb_syntax_support/TypeNodes.py index 87dbed52dfd16..527dc4d3ccd40 100644 --- a/utils/gyb_syntax_support/TypeNodes.py +++ b/utils/gyb_syntax_support/TypeNodes.py @@ -167,8 +167,9 @@ Child('Arguments', kind='TupleTypeElementList', collection_element_name='Argument'), Child('RightParen', kind='RightParenToken'), - Child('AsyncKeyword', kind='Token', text_choices=['async'], - is_optional=True), + Child('AsyncKeyword', kind='IdentifierToken', + classification='Keyword', + text_choices=['async'], is_optional=True), Child('ThrowsOrRethrowsKeyword', kind='Token', is_optional=True, token_choices=[ From d82c6cb718639552b745d6bb968df5a1f01ecafb Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 6 Aug 2020 10:43:24 -0700 Subject: [PATCH 040/123] [Syntax] Fix syntax tree creation for __await expressions. --- lib/Parse/ParseExpr.cpp | 2 +- test/Parse/async-syntax.swift | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 1009646c1c40e..d7f77869d6723 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -397,7 +397,7 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, SourceLoc awaitLoc = consumeToken(tok::kw___await); ParserResult sub = parseExprUnary(message, isExprBasic); if (!sub.hasCodeCompletion() && !sub.isNull()) { - ElementContext.setCreateSyntax(SyntaxKind::TryExpr); + ElementContext.setCreateSyntax(SyntaxKind::AwaitExpr); sub = makeParserResult(new (Context) AwaitExpr(awaitLoc, sub.get())); } diff --git a/test/Parse/async-syntax.swift b/test/Parse/async-syntax.swift index d0e5c837b2f4e..54c1bac839969 100644 --- a/test/Parse/async-syntax.swift +++ b/test/Parse/async-syntax.swift @@ -10,3 +10,7 @@ func testTypeExprs() { let _ = [() async -> ()]() let _ = [() async throws -> ()]() } + +func testAwaitOperator() async { + let _ = __await asyncGlobal1() +} From 6ff46ae2da48ad99794872fc215a1fca13913b91 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 6 Aug 2020 10:43:53 -0700 Subject: [PATCH 041/123] [Concurrency] Add serialization test for `async` --- test/Serialization/Inputs/def_async.swift | 1 + test/Serialization/async.swift | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 test/Serialization/Inputs/def_async.swift create mode 100644 test/Serialization/async.swift diff --git a/test/Serialization/Inputs/def_async.swift b/test/Serialization/Inputs/def_async.swift new file mode 100644 index 0000000000000..e74faed0ab5b7 --- /dev/null +++ b/test/Serialization/Inputs/def_async.swift @@ -0,0 +1 @@ +public func doSomethingBig() async -> Int { return 0 } diff --git a/test/Serialization/async.swift b/test/Serialization/async.swift new file mode 100644 index 0000000000000..cbf1019a3cdc8 --- /dev/null +++ b/test/Serialization/async.swift @@ -0,0 +1,11 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t-scratch) +// RUN: %target-swift-frontend -emit-module -o %t-scratch/def_async~partial.swiftmodule -primary-file %S/Inputs/def_async.swift -module-name def_async -enable-experimental-concurrency +// RUN: %target-swift-frontend -merge-modules -emit-module -parse-as-library -enable-testing %t-scratch/def_async~partial.swiftmodule -module-name def_async -o %t/def_async.swiftmodule -enable-experimental-concurrency +// RUN: %target-swift-frontend -typecheck -I%t -verify %s -verify-ignore-unknown -enable-experimental-concurrency + +import def_async + +func testDoSomethingBig() { + let _: () -> Int = doSomethingBig // expected-error{{cannot convert value of type '() async -> Int' to specified type '() -> Int'}} +} From 3aa4f74981c759dd77cb8c475d2520f664a2a9f8 Mon Sep 17 00:00:00 2001 From: Nathan Hawes Date: Thu, 6 Aug 2020 11:30:23 -0700 Subject: [PATCH 042/123] Add missing include to fix build issues on master-next and master-rebranch --- include/swift/AST/DiagnosticEngine.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 682cb8e34246b..ee3c776cd9db6 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -24,6 +24,7 @@ #include "swift/AST/TypeLoc.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/VersionTuple.h" From ebb714d6078c805e1ced56bedc034ef5f17f16fa Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 6 Aug 2020 10:39:42 -0700 Subject: [PATCH 043/123] IRGen: ObjC method lists are not const. Put them in __objc_data instead of __objc_const. rdar://problem/66630432 --- lib/IRGen/GenClass.cpp | 22 +++++++++++------ ...lass_update_callback_with_fixed_layout.sil | 2 +- ...s_update_callback_without_fixed_layout.sil | 2 +- test/IRGen/objc_bridge.swift | 2 +- test/IRGen/objc_class_export.swift | 4 ++-- test/IRGen/objc_extensions.swift | 16 ++++++------- test/IRGen/objc_methods.swift | 4 ++-- test/IRGen/objc_properties.swift | 24 +++++++++---------- test/IRGen/objc_protocols.swift | 10 ++++---- test/IRGen/objc_subclass.swift | 18 +++++++------- test/IRGen/objc_type_encoding.swift | 2 +- 11 files changed, 57 insertions(+), 49 deletions(-) diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 912f0e3ad6131..94ab37632feba 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -1284,7 +1284,7 @@ namespace { // }; assert(fields.getNextOffsetFromGlobal() == size); - return buildGlobalVariable(fields, "_CATEGORY_"); + return buildGlobalVariable(fields, "_CATEGORY_", /*const*/ true); } llvm::Constant *emitProtocol() { @@ -1336,7 +1336,7 @@ namespace { // }; assert(fields.getNextOffsetFromGlobal() == size); - return buildGlobalVariable(fields, "_PROTOCOL_"); + return buildGlobalVariable(fields, "_PROTOCOL_", /*const*/ true); } void emitRODataFields(ConstantStructBuilder &b, @@ -1439,7 +1439,7 @@ namespace { emitRODataFields(fields, forMeta, hasUpdater); auto dataSuffix = forMeta ? "_METACLASS_DATA_" : "_DATA_"; - return buildGlobalVariable(fields, dataSuffix); + return buildGlobalVariable(fields, dataSuffix, /*const*/ true); } private: @@ -1673,7 +1673,8 @@ namespace { return null(); } - return buildGlobalVariable(array, "_PROTOCOL_METHOD_TYPES_"); + return buildGlobalVariable(array, "_PROTOCOL_METHOD_TYPES_", + /*const*/ true); } void buildExtMethodTypes(ConstantArrayBuilder &array, @@ -1698,6 +1699,7 @@ namespace { llvm::Constant *buildMethodList(ArrayRef methods, StringRef name) { return buildOptionalList(methods, 3 * IGM.getPointerSize(), name, + /*isConst*/ false, [&](ConstantArrayBuilder &descriptors, MethodDescriptor descriptor) { buildMethod(descriptors, descriptor); @@ -1723,6 +1725,7 @@ namespace { chooseNamePrefix("_PROTOCOLS_", "_CATEGORY_PROTOCOLS_", "_PROTOCOL_PROTOCOLS_"), + /*isConst*/ true, [&](ConstantArrayBuilder &descriptors, ProtocolDecl *protocol) { buildProtocol(descriptors, protocol); @@ -1836,6 +1839,7 @@ namespace { llvm::Constant *buildIvarList() { Size eltSize = 3 * IGM.getPointerSize() + Size(8); return buildOptionalList(Ivars, eltSize, "_IVARS_", + /*constant*/ true, [&](ConstantArrayBuilder &descriptors, VarDecl *ivar) { buildIvar(descriptors, ivar); @@ -1971,6 +1975,7 @@ namespace { StringRef namePrefix) { Size eltSize = 2 * IGM.getPointerSize(); return buildOptionalList(properties, eltSize, namePrefix, + /*constant*/ true, [&](ConstantArrayBuilder &descriptors, VarDecl *property) { buildProperty(descriptors, property); @@ -1989,6 +1994,7 @@ namespace { llvm::Constant *buildOptionalList(const C &objects, Size optionalEltSize, StringRef nameBase, + bool isConst, Fn &&buildElement) { if (objects.empty()) return null(); @@ -2027,7 +2033,7 @@ namespace { fields.fillPlaceholderWithInt(countPosition, countType, count); - return buildGlobalVariable(fields, nameBase); + return buildGlobalVariable(fields, nameBase, isConst); } /// Get the name of the class or protocol to mangle into the ObjC symbol @@ -2047,7 +2053,8 @@ namespace { /// Build a private global variable as a structure containing the /// given fields. template - llvm::Constant *buildGlobalVariable(B &fields, StringRef nameBase) { + llvm::Constant *buildGlobalVariable(B &fields, StringRef nameBase, + bool isConst) { llvm::SmallString<64> nameBuffer; auto var = fields.finishAndCreateGlobal(Twine(nameBase) @@ -2061,7 +2068,8 @@ namespace { switch (IGM.TargetInfo.OutputObjectFormat) { case llvm::Triple::MachO: - var->setSection("__DATA, __objc_const"); + var->setSection(isConst ? "__DATA, __objc_const" + : "__DATA, __objc_data"); break; case llvm::Triple::XCOFF: case llvm::Triple::COFF: diff --git a/test/IRGen/class_update_callback_with_fixed_layout.sil b/test/IRGen/class_update_callback_with_fixed_layout.sil index c7d5629e5d716..ad1f1a4df28d3 100644 --- a/test/IRGen/class_update_callback_with_fixed_layout.sil +++ b/test/IRGen/class_update_callback_with_fixed_layout.sil @@ -51,7 +51,7 @@ sil_vtable SubclassOfClassWithResilientField {} // -- the update callback // CHECK-SAME: @"$s39class_update_callback_with_fixed_layout23ClassWithResilientFieldCMU" -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 // Class has static metadata: // CHECK-LABEL: @"$s39class_update_callback_with_fixed_layout23ClassWithResilientFieldCMf" diff --git a/test/IRGen/class_update_callback_without_fixed_layout.sil b/test/IRGen/class_update_callback_without_fixed_layout.sil index 1a06330329bd2..ce15b98e2279f 100644 --- a/test/IRGen/class_update_callback_without_fixed_layout.sil +++ b/test/IRGen/class_update_callback_without_fixed_layout.sil @@ -63,7 +63,7 @@ sil_vtable SubclassOfClassWithResilientField {} // -- the update callback // CHECK-NEW-SAME: @"$s42class_update_callback_without_fixed_layout23ClassWithResilientFieldCMU{{(\.ptrauth)?}}" -// CHECK-SAME: }, section "__DATA, __objc_const" +// CHECK-SAME: }, section "__DATA, {{.*}}" // Class has static metadata: // CHECK-LABEL: @"$s42class_update_callback_without_fixed_layout23ClassWithResilientFieldCMf" diff --git a/test/IRGen/objc_bridge.swift b/test/IRGen/objc_bridge.swift index 89b60f9b0e017..7843ed5054a0d 100644 --- a/test/IRGen/objc_bridge.swift +++ b/test/IRGen/objc_bridge.swift @@ -96,7 +96,7 @@ import Foundation // CHECK: i8* bitcast (void ([[OPAQUE:.*]]*, i8*)* @"$s11objc_bridge3BasCfETo" to i8*) // CHECK: } // CHECK: ] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: @_PROPERTIES__TtC11objc_bridge3Bas = internal constant { i32, i32, [5 x { i8*, i8* }] } { diff --git a/test/IRGen/objc_class_export.swift b/test/IRGen/objc_class_export.swift index 7dc4848a16a1e..07c5a10c8d895 100644 --- a/test/IRGen/objc_class_export.swift +++ b/test/IRGen/objc_class_export.swift @@ -34,7 +34,7 @@ // CHECK-SAME: i8* null, // CHECK-SAME: i8* null, // CHECK-SAME: i8* null -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 // CHECK: @_DATA__TtC17objc_class_export3Foo = internal constant {{.*\*}} } { // CHECK-SAME: i32 128, // CHECK-SAME: i32 16, @@ -47,7 +47,7 @@ // CHECK-SAME: @_IVARS__TtC17objc_class_export3Foo, // CHECK-SAME: i8* null, // CHECK-SAME: _PROPERTIES__TtC17objc_class_export3Foo -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 // CHECK: @"$s17objc_class_export3FooCMf" = internal global <{{.*}} }> <{ // CHECK-SAME: void ([[FOO]]*)* @"$s17objc_class_export3FooCfD", // CHECK-SAME: i8** @"$sBOWV", diff --git a/test/IRGen/objc_extensions.swift b/test/IRGen/objc_extensions.swift index e275e9fbf9276..6d4df434ae06f 100644 --- a/test/IRGen/objc_extensions.swift +++ b/test/IRGen/objc_extensions.swift @@ -27,7 +27,7 @@ import objc_extension_base // CHECK-SAME: @"_CATEGORY_CLASS_METHODS_Gizmo_$_objc_extensions", // CHECK-SAME: @"_CATEGORY_PROTOCOLS_Gizmo_$_objc_extensions", // CHECK-SAME: i8* null -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 @objc protocol NewProtocol { func brandNewInstanceMethod() @@ -67,7 +67,7 @@ extension Gizmo: NewProtocol { // CHECK: {{.*}} @"_CATEGORY_CLASS_METHODS_Gizmo_$_objc_extensions1", // CHECK: i8* null, // CHECK: i8* null -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 extension Gizmo { @objc func brandSpankingNewInstanceMethod() { @@ -92,7 +92,7 @@ class Hoozit : NSObject { // CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[STR:@.*]], i64 0, i64 0), // CHECK: i8* bitcast (void ([[OPAQUE:%.*]]*, i8*)* @"$s15objc_extensions6HoozitC7blibbleyyFTo" to i8*) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK-LABEL: @"_CATEGORY_CLASS_METHODS__TtC15objc_extensions6Hoozit_$_objc_extensions" = internal constant // CHECK: i32 24, @@ -102,7 +102,7 @@ class Hoozit : NSObject { // CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[STR]], i64 0, i64 0), // CHECK: i8* bitcast (void (i8*, i8*)* @"$s15objc_extensions6HoozitC7blobbleyyFZTo" to i8*) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK-LABEL: @"_CATEGORY__TtC15objc_extensions6Hoozit_$_objc_extensions" = internal constant // CHECK: i8* getelementptr inbounds ([16 x i8], [16 x i8]* [[CATEGORY_NAME]], i64 0, i64 0), @@ -111,7 +111,7 @@ class Hoozit : NSObject { // CHECK: {{.*}} @"_CATEGORY_CLASS_METHODS__TtC15objc_extensions6Hoozit_$_objc_extensions", // CHECK: i8* null, // CHECK: i8* null -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 extension Hoozit { @objc func blibble() { } @@ -127,7 +127,7 @@ class SwiftOnly { } // CHECK: i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_selector_data(wibble)", i64 0, i64 0), // CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[STR]], i64 0, i64 0), // CHECK: i8* bitcast (void (i8*, i8*)* @"$s15objc_extensions9SwiftOnlyC6wibbleyyFTo" to i8*) -// CHECK: }] }, section "__DATA, __objc_const", align 8 +// CHECK: }] }, section "__DATA, {{.*}}", align 8 extension SwiftOnly { @objc func wibble() { } } @@ -157,7 +157,7 @@ extension NSObject { // CHECK-SAME: i8* getelementptr inbounds ([16 x i8], [16 x i8]* [[CATEGORY_NAME]], i64 0, i64 0), // CHECK-SAME: @"_CATEGORY_INSTANCE_METHODS__TtCC15objc_extensions5Outer5Inner_$_objc_extensions", // CHECK-SAME: i8* null -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 class Outer : NSObject { class Inner : NSObject {} @@ -175,7 +175,7 @@ class NSDogcow : NSObject {} // CHECK: [[NAME:@.*]] = private unnamed_addr constant [5 x i8] c"woof\00" // CHECK: [[ATTR:@.*]] = private unnamed_addr constant [7 x i8] c"Tq,N,D\00" -// CHECK: @"_CATEGORY_PROPERTIES__TtC15objc_extensions8NSDogcow_$_objc_extensions" = internal constant {{.*}} [[NAME]], {{.*}} [[ATTR]], {{.*}}, section "__DATA, __objc_const", align 8 +// CHECK: @"_CATEGORY_PROPERTIES__TtC15objc_extensions8NSDogcow_$_objc_extensions" = internal constant {{.*}} [[NAME]], {{.*}} [[ATTR]], {{.*}}, section "__DATA, {{.*}}", align 8 extension NSDogcow { @NSManaged var woof: Int } diff --git a/test/IRGen/objc_methods.swift b/test/IRGen/objc_methods.swift index 0179649e064d3..4f517c9608339 100644 --- a/test/IRGen/objc_methods.swift +++ b/test/IRGen/objc_methods.swift @@ -79,7 +79,7 @@ class ObjcDestructible: NSObject { // CHECK-macosx: i8* bitcast (i8 (i8*, i8*, %4**)* @"$s12objc_methods3FooC4failyyKFTo" to i8*) // CHECK-ios: i8* bitcast (i1 (i8*, i8*, %4**)* @"$s12objc_methods3FooC4failyyKFTo" to i8*) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: @_INSTANCE_METHODS__TtC12objc_methods16ObjcDestructible = internal constant { {{.*}}] } { // CHECK: i32 24, // CHECK: i32 2, @@ -88,7 +88,7 @@ class ObjcDestructible: NSObject { // CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[NO_ARGS_SIGNATURE]], i64 0, i64 0), // CHECK: i8* bitcast (void (%6*, i8*)* @"$s12objc_methods16ObjcDestructibleCfETo" to i8*) }] // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: [[BLOCK_SIGNATURE_EXT_1:@.*]] = private unnamed_addr constant [18 x i8] c"v24@0:8@?16\00" // CHECK: [[BLOCK_SIGNATURE_EXT_2:@.*]] = private unnamed_addr constant [19 x i8] c"v24@0:8@?16\00" // CHECK: [[STRING_SIGNATURE_EXT:@.*]] = private unnamed_addr constant [31 x i8] c"@\22NSString\2224@0:8@\22NSString\2216\00" diff --git a/test/IRGen/objc_properties.swift b/test/IRGen/objc_properties.swift index d126722124edd..d8f4273216ecf 100644 --- a/test/IRGen/objc_properties.swift +++ b/test/IRGen/objc_properties.swift @@ -112,7 +112,7 @@ class SomeWrapperTests { // CHECK-NEW: i8* getelementptr inbounds ([11 x i8], [11 x i8]* [[SHARED_NAME]], i64 0, i64 0), // CHECK-NEW: i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[SHARED_ATTRS]], i64 0, i64 0) // CHECK-NEW: }] -// CHECK-NEW: }, section "__DATA, __objc_const", align 8 +// CHECK-NEW: }, section "__DATA, {{.*}}", align 8 // CHECK: @_METACLASS_DATA__TtC15objc_properties10SomeObject = internal constant { {{.*}} } { // CHECK-SAME: i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 {{[0-9]+}}, @@ -122,7 +122,7 @@ class SomeWrapperTests { // CHECK-SAME: i8* null, i8* null, i8* null, // CHECK-NEW-SAME: { {{.+}} }* @_CLASS_PROPERTIES__TtC15objc_properties10SomeObject // CHECK-OLD-SAME: i8* null -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 // CHECK: [[GETTER_SIGNATURE:@.*]] = private unnamed_addr constant [8 x i8] c"@16@0:8\00" // CHECK: [[SETTER_SIGNATURE:@.*]] = private unnamed_addr constant [11 x i8] c"v24@0:8@16\00" @@ -163,7 +163,7 @@ class SomeWrapperTests { // CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[GETTER_SIGNATURE]], i64 0, i64 0), // CHECK: @"$s15objc_properties10SomeObjectCACycfcTo{{(.ptrauth)?}}" // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // This appears earlier because it's also used in an ivar description. // CHECK: [[BAREIVAR_NAME:@.*]] = private unnamed_addr constant [9 x i8] c"bareIvar\00" @@ -195,7 +195,7 @@ class SomeWrapperTests { // CHECK: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[WIBBLE_NAME]], i64 0, i64 0), // CHECK: i8* getelementptr inbounds ([50 x i8], [50 x i8]* [[WIBBLE_ATTRS]], i64 0, i64 0) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: @_DATA__TtC15objc_properties10SomeObject = internal constant { {{.+}} } { // CHECK: i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 {{[0-9]+}}, @@ -206,7 +206,7 @@ class SomeWrapperTests { // CHECK: { {{.+}} }* @_IVARS__TtC15objc_properties10SomeObject, // CHECK: i8* null, // CHECK: { {{.+}} }* @_PROPERTIES__TtC15objc_properties10SomeObject -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: @"_CATEGORY_INSTANCE_METHODS__TtC15objc_properties10SomeObject_$_objc_properties" = internal constant { {{.*}}] } { // CHECK: i32 24, @@ -220,7 +220,7 @@ class SomeWrapperTests { // CHECK: i8* getelementptr inbounds ([11 x i8], [11 x i8]* [[SETTER_SIGNATURE]], i64 0, i64 0), // CHECK: @"$s15objc_properties10SomeObjectC17extensionPropertyACvsTo{{(.ptrauth)?}}" // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: [[EXTENSIONPROPERTY_NAME:@.*]] = private unnamed_addr constant [18 x i8] c"extensionProperty\00" @@ -231,7 +231,7 @@ class SomeWrapperTests { // CHECK: i8* getelementptr inbounds ([18 x i8], [18 x i8]* [[EXTENSIONPROPERTY_NAME]], i64 0, i64 0), // CHECK: i8* getelementptr inbounds ([42 x i8], [42 x i8]* [[READWRITE_ATTRS]], i64 0, i64 0) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK-NEW: [[EXTENSIONCLASSPROPERTY_NAME:@.*]] = private unnamed_addr constant [19 x i8] c"extensionClassProp\00" // CHECK-NEW: [[EXTENSIONCLASSPROPERTY_ATTRS:@.*]] = private unnamed_addr constant [7 x i8] c"T#,N,R\00" @@ -246,7 +246,7 @@ class SomeWrapperTests { // CHECK-NEW: }, { // CHECK-NEW: i8* getelementptr inbounds ([26 x i8], [26 x i8]* [[EXTENSIONSTATICPROPERTY_NAME]], i64 0, i64 0), // CHECK-NEW: i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[SHARED_ATTRS]], i64 0, i64 0) }] -// CHECK-NEW: }, section "__DATA, __objc_const", align 8 +// CHECK-NEW: }, section "__DATA, {{.*}}", align 8 // CHECK: @"_CATEGORY__TtC15objc_properties10SomeObject_$_objc_properties" = internal constant { {{.+}} } { // CHECK: i8* getelementptr inbounds ([{{.+}} x i8], [{{.+}} x i8]* {{@.+}}, i64 0, i64 0), @@ -258,7 +258,7 @@ class SomeWrapperTests { // CHECK-NEW: { {{.+}} }* @"_CATEGORY_CLASS_PROPERTIES__TtC15objc_properties10SomeObject_$_objc_properties", // CHECK-OLD: i8* null, // CHECK: i32 60 -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: @_INSTANCE_METHODS__TtC15objc_properties4Tree = @@ -283,7 +283,7 @@ class SomeWrapperTests { // CHECK: i8* null, // CHECK-NEW: { {{.+}} }* @_PROTOCOL_CLASS_PROPERTIES__TtP15objc_properties5Proto_ // CHECK-OLD: i8* null -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: [[PROTOCOLPROPERTY_NAME:@.+]] = private unnamed_addr constant [6 x i8] c"value\00" @@ -296,7 +296,7 @@ class SomeWrapperTests { // CHECK: i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[PROTOCOLPROPERTY_NAME]], i64 0, i64 0), // CHECK: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[PROTOCOLPROPERTY_ATTRS]], i64 0, i64 0) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK-NEW: [[PROTOCOLCLASSPROPERTY_NAME:@.+]] = private unnamed_addr constant [15 x i8] c"sharedInstance\00" // CHECK-NEW: [[PROTOCOLCLASSPROPERTY_ATTRS:@.+]] = private unnamed_addr constant [7 x i8] c"T@,N,&\00" @@ -308,4 +308,4 @@ class SomeWrapperTests { // CHECK-NEW: i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[PROTOCOLCLASSPROPERTY_NAME]], i64 0, i64 0), // CHECK-NEW: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[PROTOCOLCLASSPROPERTY_ATTRS]], i64 0, i64 0) // CHECK-NEW: }] -// CHECK-NEW: }, section "__DATA, __objc_const", align 8 +// CHECK-NEW: }, section "__DATA, {{.*}}", align 8 diff --git a/test/IRGen/objc_protocols.swift b/test/IRGen/objc_protocols.swift index 8a7a237bd37da..60dec14632ed5 100644 --- a/test/IRGen/objc_protocols.swift +++ b/test/IRGen/objc_protocols.swift @@ -32,7 +32,7 @@ class Foo : NSRuncing, NSFunging, Ansible { // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_selector_data(funge)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3FooC5fungeyyFTo" to i8*) }, // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(foo)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3FooC3fooyyFTo" to i8*) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 class Bar { func bar() {} @@ -57,7 +57,7 @@ extension Bar : NSRuncing, NSFunging { // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_selector_data(funge)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3BarC5fungeyyFTo" to i8*) }, // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(foo)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3BarC3fooyyFTo" to i8*) } // CHECK: ] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // class Bas from objc_protocols_Bas module extension Bas : NSRuncing { @@ -71,7 +71,7 @@ extension Bas : NSRuncing { // CHECK: [1 x { i8*, i8*, i8* }] [ // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(foo)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s18objc_protocols_Bas0C0C0a1_B0E3fooyyFTo" to i8*) } // CHECK: ] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // -- Swift protocol refinement of ObjC protocols. protocol Frungible : NSRuncing, NSFunging { @@ -93,7 +93,7 @@ class Zim : Frungible { // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_selector_data(funge)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3ZimC5fungeyyFTo" to i8*) }, // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(foo)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3ZimC3fooyyFTo" to i8*) } // CHECK: ] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // class Zang from objc_protocols_Bas module extension Zang : Frungible { @@ -112,7 +112,7 @@ extension Zang : Frungible { // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_selector_data(runce)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s18objc_protocols_Bas4ZangC0a1_B0E5runceyyFTo" to i8*) }, // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(foo)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s18objc_protocols_Bas4ZangC0a1_B0E3fooyyFTo" to i8*) } // CHECK: ] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 @objc protocol BaseProtocol { } protocol InheritingProtocol : BaseProtocol { } diff --git a/test/IRGen/objc_subclass.swift b/test/IRGen/objc_subclass.swift index 3fa2541722ef3..f2fa4d2395be3 100644 --- a/test/IRGen/objc_subclass.swift +++ b/test/IRGen/objc_subclass.swift @@ -35,7 +35,7 @@ // CHECK-32: i8* null, // CHECK-32: i8* null, // CHECK-32: i8* null -// CHECK-32: }, section "__DATA, __objc_const", align 4 +// CHECK-32: }, section "__DATA, {{.*}}", align 4 // CHECK-64: @_METACLASS_DATA__TtC13objc_subclass10SwiftGizmo = internal constant { {{.*}}* } { // CHECK-64: i32 129, @@ -49,7 +49,7 @@ // CHECK-64: i8* null, // CHECK-64: i8* null, // CHECK-64: i8* null -// CHECK-64: }, section "__DATA, __objc_const", align 8 +// CHECK-64: }, section "__DATA, {{.*}}", align 8 // CHECK-32: [[METHOD_TYPE_ENCODING1:@.*]] = private unnamed_addr constant [7 x i8] c"l8@0:4\00" // CHECK-64: [[METHOD_TYPE_ENCODING1:@.*]] = private unnamed_addr constant [8 x i8] c"q16@0:8\00" @@ -110,7 +110,7 @@ // CHECK-32: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* {{@[0-9]+}}, i32 0, i32 0), // CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoCfeTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }] -// CHECK-32: }, section "__DATA, __objc_const", align 4 +// CHECK-32: }, section "__DATA, {{.*}}", align 4 // CHECK-64: @_INSTANCE_METHODS__TtC13objc_subclass10SwiftGizmo = internal constant { {{.*}}] } { // CHECK-64: i32 24, @@ -160,7 +160,7 @@ // CHECK-64: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* {{@[0-9]+}}, i64 0, i64 0), // CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoCfeTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }] -// CHECK-64: }, section "__DATA, __objc_const", align 8 +// CHECK-64: }, section "__DATA, {{.*}}", align 8 // CHECK: [[STRING_X:@.*]] = private unnamed_addr constant [2 x i8] c"x\00" // CHECK-64: [[STRING_EMPTY:@.*]] = private unnamed_addr constant [1 x i8] zeroinitializer @@ -174,7 +174,7 @@ // CHECK-32: i8* getelementptr inbounds ([1 x i8], [1 x i8]* {{.*}}, i32 0, i32 0), // CHECK-32: i32 2, // CHECK-32: i32 4 }] -// CHECK-32: }, section "__DATA, __objc_const", align 4 +// CHECK-32: }, section "__DATA, {{.*}}", align 4 // CHECK-64: @_IVARS__TtC13objc_subclass10SwiftGizmo = internal constant { {{.*}}] } { // CHECK-64: i32 32, @@ -185,7 +185,7 @@ // CHECK-64: i8* getelementptr inbounds ([1 x i8], [1 x i8]* [[STRING_EMPTY]], i64 0, i64 0), // CHECK-64: i32 3, // CHECK-64: i32 8 }] -// CHECK-64: }, section "__DATA, __objc_const", align 8 +// CHECK-64: }, section "__DATA, {{.*}}", align 8 // CHECK-32: @_DATA__TtC13objc_subclass10SwiftGizmo = internal constant { {{.*}}* } { // CHECK-32: i32 132, @@ -198,7 +198,7 @@ // CHECK-32: @_IVARS__TtC13objc_subclass10SwiftGizmo, // CHECK-32: i8* null, // CHECK-32: @_PROPERTIES__TtC13objc_subclass10SwiftGizmo -// CHECK-32: }, section "__DATA, __objc_const", align 4 +// CHECK-32: }, section "__DATA, {{.*}}", align 4 // CHECK-64: @_DATA__TtC13objc_subclass10SwiftGizmo = internal constant { {{.*}}* } { // CHECK-64: i32 132, @@ -212,7 +212,7 @@ // CHECK-64: @_IVARS__TtC13objc_subclass10SwiftGizmo, // CHECK-64: i8* null, // CHECK-64: @_PROPERTIES__TtC13objc_subclass10SwiftGizmo -// CHECK-64: }, section "__DATA, __objc_const", align 8 +// CHECK-64: }, section "__DATA, {{.*}}", align 8 // CHECK-NOT: @_TMCSo13SwiftGizmo = {{.*NSObject}} @@ -247,7 +247,7 @@ // CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2CfETo{{(\.ptrauth)?}}" to i8*) // CHECK-32: } // CHECK-32: ] -// CHECK-32: }, section "__DATA, __objc_const", align 4 +// CHECK-32: }, section "__DATA, {{.*}}", align 4 // CHECK-64: @_INSTANCE_METHODS__TtC13objc_subclass11SwiftGizmo2 = internal constant { i32, {{.*}}] } { // CHECK-64: i32 24, diff --git a/test/IRGen/objc_type_encoding.swift b/test/IRGen/objc_type_encoding.swift index 571aedaa01f3c..8a685138398fe 100644 --- a/test/IRGen/objc_type_encoding.swift +++ b/test/IRGen/objc_type_encoding.swift @@ -188,4 +188,4 @@ class C: P { } // CHECK-macosx: [[ENC5:@.*]] = private unnamed_addr constant [9 x i8] c"Vv16@0:8\00" -// CHECK-macosx: @_PROTOCOL_INSTANCE_METHODS_P = {{.*}}@"\01L_selector_data(stuff)"{{.*}}[[ENC5]]{{.*}}, section "__DATA, __objc_const", align 8 +// CHECK-macosx: @_PROTOCOL_INSTANCE_METHODS_P = {{.*}}@"\01L_selector_data(stuff)"{{.*}}[[ENC5]]{{.*}} From 989a4328982aea38a372185d3889e277595cae58 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Thu, 6 Aug 2020 12:30:45 -0700 Subject: [PATCH 044/123] [NFC] Update array literal type checking performance validation tests. --- validation-test/SILOptimizer/large_string_array.swift.gyb | 3 --- .../type_checker_perf/{slow => fast}/rdar30596744_2.swift.gyb | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) rename validation-test/Sema/type_checker_perf/{slow => fast}/rdar30596744_2.swift.gyb (68%) diff --git a/validation-test/SILOptimizer/large_string_array.swift.gyb b/validation-test/SILOptimizer/large_string_array.swift.gyb index 7a0169748ead0..6285e4b97c75b 100644 --- a/validation-test/SILOptimizer/large_string_array.swift.gyb +++ b/validation-test/SILOptimizer/large_string_array.swift.gyb @@ -1,9 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %gyb %s > %t/main.swift -// FIXME: Re-enable SILOptimizer/large_string_array.swift.gyb -// REQUIRES: rdar66219627 - // The compiler should finish in less than 1 minute. To give some slack, // specify a timeout of 5 minutes. // If the compiler needs more than 5 minutes, there is probably a real problem. diff --git a/validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar30596744_2.swift.gyb similarity index 68% rename from validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb rename to validation-test/Sema/type_checker_perf/fast/rdar30596744_2.swift.gyb index cfd18b2c7006e..1dd787e01ee08 100644 --- a/validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar30596744_2.swift.gyb @@ -1,4 +1,4 @@ -// RUN: %scale-test --invert-result --begin 1 --end 5 --step 1 --select NumLeafScopes %s --expected-exit-code 1 +// RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s --expected-exit-code 1 // REQUIRES: asserts,no_asan % enum_cases = 3 From e26aeca7eb03a2801ddb490ec89d9b9c945d14bc Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Thu, 6 Aug 2020 16:33:59 -0400 Subject: [PATCH 045/123] [Runtime] Fix the isa mask assert for ARM64e. Swift's isa mask includes the signature bits. objc_debug_isa_class_mask does not. Switch to objc_absolute_packed_isa_class_mask instead, which does. While we're at it, get rid of the now-unnecessary guards for back-deployment. rdar://problem/60148213 --- include/swift/Runtime/ObjCBridge.h | 3 +++ stdlib/public/runtime/SwiftObject.mm | 15 +++------------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/include/swift/Runtime/ObjCBridge.h b/include/swift/Runtime/ObjCBridge.h index 33e5022463434..a24fb03feeb9d 100644 --- a/include/swift/Runtime/ObjCBridge.h +++ b/include/swift/Runtime/ObjCBridge.h @@ -68,6 +68,9 @@ OBJC_EXPORT Class objc_readClassPair(Class cls, const struct objc_image_info *info) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); +// Magic symbol whose _address_ is the runtime's isa mask. +OBJC_EXPORT const struct { char c; } objc_absolute_packed_isa_class_mask; + namespace swift { diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm index af7489d33cb11..d0022f0399085 100644 --- a/stdlib/public/runtime/SwiftObject.mm +++ b/stdlib/public/runtime/SwiftObject.mm @@ -198,18 +198,9 @@ static id _getClassDescription(Class cls) { @implementation SwiftObject + (void)initialize { -#if SWIFT_HAS_ISA_MASKING && !NDEBUG - // Older OSes may not have this variable, or it may not match. This code only - // runs on older OSes in certain testing scenarios, so that doesn't matter. - // Only perform the check on newer OSes where the value should definitely - // match. -# if SWIFT_BUILD_HAS_BACK_DEPLOYMENT - if (!_swift_isBackDeploying()) -# endif - { - assert(&objc_debug_isa_class_mask); - assert(objc_debug_isa_class_mask == SWIFT_ISA_MASK); - } +#if SWIFT_HAS_ISA_MASKING && !TARGET_OS_SIMULATOR && !NDEBUG + assert(&objc_absolute_packed_isa_class_mask); + assert((uintptr_t)&objc_absolute_packed_isa_class_mask == SWIFT_ISA_MASK); #endif } From 6a5522f09a1d209b7cc08b39a38d076d2aaaaecc Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 6 Aug 2020 14:04:25 -0700 Subject: [PATCH 046/123] [Syntax] Fix type syntax tests for 'async'. --- unittests/Syntax/TypeSyntaxTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/Syntax/TypeSyntaxTests.cpp b/unittests/Syntax/TypeSyntaxTests.cpp index 22711ccc0d92f..267d8787335cb 100644 --- a/unittests/Syntax/TypeSyntaxTests.cpp +++ b/unittests/Syntax/TypeSyntaxTests.cpp @@ -471,7 +471,7 @@ TEST(TypeSyntaxTests, FunctionTypeMakeAPIs) { auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, {}); auto IntArg = SyntaxFactory::makeBlankTupleTypeElement() .withType(Int); - auto Async = SyntaxFactory::makeContextualKeyword( + auto Async = SyntaxFactory::makeIdentifier( "async", { }, { Trivia::spaces(1) }); auto Throws = SyntaxFactory::makeThrowsKeyword({}, { Trivia::spaces(1) }); auto Rethrows = SyntaxFactory::makeRethrowsKeyword({}, From 094aa8f0f311213de1f26ddf390d4d16129ce21f Mon Sep 17 00:00:00 2001 From: Puyan Lotfi Date: Thu, 6 Aug 2020 15:04:18 -0700 Subject: [PATCH 047/123] Fix build error due to missing include of llvm/Support/FileSystem.h DiagnosticEngine.h uses llvm::sys::fs:exists but doesn't directly include the header that provides it, which results in a build error due to upstream llvm changes. This patch includes that header. --- include/swift/AST/DiagnosticEngine.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 682cb8e34246b..ee3c776cd9db6 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -24,6 +24,7 @@ #include "swift/AST/TypeLoc.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/VersionTuple.h" From aa229c26101cc9ee0cbee92597a5b2314e98c19c Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 6 Aug 2020 15:33:14 -0700 Subject: [PATCH 048/123] [Localization] Fully qualify `swift-serialize-diagnostics` tool --- localization/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localization/CMakeLists.txt b/localization/CMakeLists.txt index 8f0d3f6b9c29a..764b378f97b44 100644 --- a/localization/CMakeLists.txt +++ b/localization/CMakeLists.txt @@ -4,7 +4,7 @@ add_custom_command(TARGET diagnostic-database COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/diagnostics/ ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ COMMAND - swift-serialize-diagnostics + $ --input-file-path ${CMAKE_BINARY_DIR}/share/swift/diagnostics/en.yaml --output-directory ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ ) From d064241599e76f87e8d5e5a6ff4d9ed1a4eab6bf Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 3 Aug 2020 19:17:31 -0700 Subject: [PATCH 049/123] [ssa-updater] Modernize style before adding support for guaranteed parameters. Specifically: 1. I made methods, variables camelCase. 2. I expanded out variable names (e.x.: bb -> block, predBB -> predBlocks, U -> wrappedUse). 3. I changed typedef -> using. 4. I changed a few c style for loops into for each loops using llvm::enumerate. NOTE: I left the parts needed for syncing to LLVM in the old style since LLVM needs these to exist for CRTP to work correctly for the SILSSAUpdater. --- .../swift/SILOptimizer/Utils/SILSSAUpdater.h | 57 +- .../LoopTransforms/ArrayPropertyOpt.cpp | 8 +- lib/SILOptimizer/LoopTransforms/LICM.cpp | 12 +- .../LoopTransforms/LoopRotate.cpp | 8 +- .../LoopTransforms/LoopUnroll.cpp | 8 +- .../Mandatory/ClosureLifetimeFixup.cpp | 24 +- .../Mandatory/PredictableMemOpt.cpp | 12 +- .../Transforms/DeadObjectElimination.cpp | 6 +- .../Transforms/RedundantLoadElimination.cpp | 6 +- lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp | 8 +- lib/SILOptimizer/Utils/SILSSAUpdater.cpp | 571 +++++++++--------- 11 files changed, 370 insertions(+), 350 deletions(-) diff --git a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h index f222f2309cc79..6cac152cd8ce4 100644 --- a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h +++ b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h @@ -18,9 +18,14 @@ #include "swift/SIL/SILValue.h" namespace llvm { - template class SSAUpdaterTraits; - template class SmallVectorImpl; -} + +template +class SSAUpdaterTraits; + +template +class SmallVectorImpl; + +} // namespace llvm namespace swift { @@ -31,7 +36,7 @@ class SILUndef; /// Independent utility that canonicalizes BB arguments by reusing structurally /// equivalent arguments and replacing the original arguments with casts. -SILValue replaceBBArgWithCast(SILPhiArgument *Arg); +SILValue replaceBBArgWithCast(SILPhiArgument *arg); /// This class updates SSA for a set of SIL instructions defined in multiple /// blocks. @@ -40,16 +45,16 @@ class SILSSAUpdater { // A map of basic block to available phi value. using AvailableValsTy = llvm::DenseMap; - std::unique_ptr AV; + std::unique_ptr blockToAvailableValueMap; - SILType ValType; + SILType type; // The SSAUpdaterTraits specialization uses this sentinel to mark 'new' phi // nodes (all the incoming edge arguments have this sentinel set). - std::unique_ptr PHISentinel; + std::unique_ptr phiSentinel; // If not null updated with inserted 'phi' nodes (SILArgument). - SmallVectorImpl *InsertedPHIs; + SmallVectorImpl *insertedPhis; // Not copyable. void operator=(const SILSSAUpdater &) = delete; @@ -57,21 +62,21 @@ class SILSSAUpdater { public: explicit SILSSAUpdater( - SmallVectorImpl *InsertedPHIs = nullptr); + SmallVectorImpl *insertedPhis = nullptr); ~SILSSAUpdater(); - void setInsertedPhis(SmallVectorImpl *insertedPhis) { - InsertedPHIs = insertedPhis; + void setInsertedPhis(SmallVectorImpl *inputInsertedPhis) { + insertedPhis = inputInsertedPhis; } /// Initialize for a use of a value of type. - void Initialize(SILType T); + void initialize(SILType type); - bool HasValueForBlock(SILBasicBlock *BB) const; - void AddAvailableValue(SILBasicBlock *BB, SILValue V); + bool hasValueForBlock(SILBasicBlock *block) const; + void addAvailableValue(SILBasicBlock *block, SILValue value); /// Construct SSA for a value that is live at the *end* of a basic block. - SILValue GetValueAtEndOfBlock(SILBasicBlock *BB); + SILValue getValueAtEndOfBlock(SILBasicBlock *block); /// Construct SSA for a value that is live in the middle of a block. /// This handles the case where the use is before a definition of the value. @@ -85,15 +90,15 @@ class SILSSAUpdater { /// /// In this case we need to insert a 'PHI' node at the beginning of BB2 /// merging val_1 and val_2. - SILValue GetValueInMiddleOfBlock(SILBasicBlock *BB); + SILValue getValueInMiddleOfBlock(SILBasicBlock *block); - void RewriteUse(Operand &Op); + void rewriteUse(Operand &operand); - void *allocate(unsigned Size, unsigned Align) const; - static void deallocateSentinel(SILUndef *U); -private: + void *allocate(unsigned size, unsigned align) const; + static void deallocateSentinel(SILUndef *undef); - SILValue GetValueAtEndOfBlockInternal(SILBasicBlock *BB); +private: + SILValue getValueAtEndOfBlockInternal(SILBasicBlock *block); }; /// Utility to wrap 'Operand's to deal with invalidation of @@ -112,15 +117,15 @@ class SILSSAUpdater { /// identify the use allowing us to reconstruct the use after the branch has /// been changed. class UseWrapper { - Operand *U; - SILBasicBlock *Parent; + Operand *wrappedUse; + SILBasicBlock *parent; enum { kRegularUse, kBranchUse, kCondBranchUseTrue, kCondBranchUseFalse - } Type; - unsigned Idx; + } type; + unsigned index; public: @@ -131,7 +136,7 @@ class UseWrapper { /// (ValueUseIterator) become invalid as they point to freed operands. /// Instead we store the branch's parent and the idx so that we can /// reconstruct the use. - UseWrapper(Operand *Use); + UseWrapper(Operand *use); Operand *getOperand(); diff --git a/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp b/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp index b734d134cf29e..76a30bfaca3d2 100644 --- a/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp +++ b/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp @@ -519,13 +519,13 @@ class RegionCloner : public SILCloner { return; // Update SSA form. - SSAUp.Initialize(V->getType()); - SSAUp.AddAvailableValue(OrigBB, V); + SSAUp.initialize(V->getType()); + SSAUp.addAvailableValue(OrigBB, V); SILValue NewVal = getMappedValue(V); - SSAUp.AddAvailableValue(getOpBasicBlock(OrigBB), NewVal); + SSAUp.addAvailableValue(getOpBasicBlock(OrigBB), NewVal); for (auto U : UseList) { Operand *Use = U; - SSAUp.RewriteUse(*Use); + SSAUp.rewriteUse(*Use); } } diff --git a/lib/SILOptimizer/LoopTransforms/LICM.cpp b/lib/SILOptimizer/LoopTransforms/LICM.cpp index 79e5bd6d96b8e..e4be5ac35f5fa 100644 --- a/lib/SILOptimizer/LoopTransforms/LICM.cpp +++ b/lib/SILOptimizer/LoopTransforms/LICM.cpp @@ -1062,8 +1062,8 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins LLVM_DEBUG(llvm::dbgs() << "Creating preload " << *initialLoad); SILSSAUpdater ssaUpdater; - ssaUpdater.Initialize(initialLoad->getType()); - ssaUpdater.AddAvailableValue(preheader, initialLoad); + ssaUpdater.initialize(initialLoad->getType()); + ssaUpdater.addAvailableValue(preheader, initialLoad); // Set all stored values as available values in the ssaUpdater. // If there are multiple stores in a block, only the last one counts. @@ -1078,7 +1078,7 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins if (isLoadFromAddr(dyn_cast(SI->getSrc()), addr)) return; - ssaUpdater.AddAvailableValue(SI->getParent(), SI->getSrc()); + ssaUpdater.addAvailableValue(SI->getParent(), SI->getSrc()); } } @@ -1099,7 +1099,7 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins // If we didn't see a store in this block yet, get the current value from // the ssaUpdater. if (!currentVal) - currentVal = ssaUpdater.GetValueInMiddleOfBlock(block); + currentVal = ssaUpdater.getValueInMiddleOfBlock(block); SILValue projectedValue = projectLoadValue(LI->getOperand(), addr, currentVal, LI); LLVM_DEBUG(llvm::dbgs() << "Replacing stored load " << *LI << " with " @@ -1117,8 +1117,8 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins "should have split critical edges"); SILBuilder B(succ->begin()); auto *SI = B.createStore(loc.getValue(), - ssaUpdater.GetValueInMiddleOfBlock(succ), - addr, StoreOwnershipQualifier::Unqualified); + ssaUpdater.getValueInMiddleOfBlock(succ), addr, + StoreOwnershipQualifier::Unqualified); (void)SI; LLVM_DEBUG(llvm::dbgs() << "Creating loop-exit store " << *SI); } diff --git a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp index ea9521f061b2f..fff3b201dc415 100644 --- a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp +++ b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp @@ -131,9 +131,9 @@ static void updateSSAForUseOfValue( assert(Res->getType() == MappedValue->getType() && "The types must match"); insertedPhis.clear(); - updater.Initialize(Res->getType()); - updater.AddAvailableValue(Header, Res); - updater.AddAvailableValue(EntryCheckBlock, MappedValue); + updater.initialize(Res->getType()); + updater.addAvailableValue(Header, Res); + updater.addAvailableValue(EntryCheckBlock, MappedValue); // Because of the way that phi nodes are represented we have to collect all // uses before we update SSA. Modifying one phi node can invalidate another @@ -155,7 +155,7 @@ static void updateSSAForUseOfValue( assert(user->getParent() != EntryCheckBlock && "The entry check block should dominate the header"); - updater.RewriteUse(*use); + updater.rewriteUse(*use); } // Canonicalize inserted phis to avoid extra BB Args. for (SILPhiArgument *arg : insertedPhis) { diff --git a/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp b/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp index 752e74ecc7001..967bfdbf4d468 100644 --- a/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp +++ b/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp @@ -334,13 +334,13 @@ updateSSA(SILModule &M, SILLoop *Loop, if (!Loop->contains(Use->getUser()->getParent())) UseList.push_back(UseWrapper(Use)); // Update SSA of use with the available values. - SSAUp.Initialize(OrigValue->getType()); - SSAUp.AddAvailableValue(OrigValue->getParentBlock(), OrigValue); + SSAUp.initialize(OrigValue->getType()); + SSAUp.addAvailableValue(OrigValue->getParentBlock(), OrigValue); for (auto NewValue : MapEntry.second) - SSAUp.AddAvailableValue(NewValue->getParentBlock(), NewValue); + SSAUp.addAvailableValue(NewValue->getParentBlock(), NewValue); for (auto U : UseList) { Operand *Use = U; - SSAUp.RewriteUse(*Use); + SSAUp.rewriteUse(*Use); } } } diff --git a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp index 093cb4482e6b1..ff14e4a0f05ea 100644 --- a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp +++ b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp @@ -244,7 +244,7 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn, // lifetime respecting loops. SmallVector insertedPhis; SILSSAUpdater updater(&insertedPhis); - updater.Initialize(optionalEscapingClosureTy); + updater.initialize(optionalEscapingClosureTy); // Create an Optional<() -> ()>.none in the entry block of the function and // add it as an available value to the SSAUpdater. @@ -256,7 +256,7 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn, SILBuilderWithScope b(fn.getEntryBlock()->begin()); return b.createOptionalNone(loc, optionalEscapingClosureTy); }(); - updater.AddAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone); + updater.addAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone); // Create a copy of the convert_escape_to_no_escape and add it as an available // value to the SSA updater. @@ -270,7 +270,7 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn, cvt->setLifetimeGuaranteed(); cvt->setOperand(innerCVI); SILBuilderWithScope b(std::next(cvt->getIterator())); - updater.AddAvailableValue( + updater.addAvailableValue( cvt->getParent(), b.createOptionalSome(loc, innerCVI, optionalEscapingClosureTy)); return innerCVI; @@ -284,13 +284,13 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn, { // Before the copy value, insert an extra destroy_value to handle // loops. Since we used our enum value this is safe. - SILValue v = updater.GetValueInMiddleOfBlock(cvi->getParent()); + SILValue v = updater.getValueInMiddleOfBlock(cvi->getParent()); SILBuilderWithScope(cvi).createDestroyValue(loc, v); } for (auto *block : exitingBlocks) { auto *safeDestructionPt = getDeinitSafeClosureDestructionPoint(block); - SILValue v = updater.GetValueAtEndOfBlock(block); + SILValue v = updater.getValueAtEndOfBlock(block); SILBuilderWithScope(safeDestructionPt).createDestroyValue(loc, v); } @@ -849,7 +849,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, SmallVector insertedPhis; SILSSAUpdater updater(&insertedPhis); - updater.Initialize(optionalEscapingClosureTy); + updater.initialize(optionalEscapingClosureTy); // Create the Optional.none as the beginning available value. SILValue entryBlockOptionalNone; @@ -857,7 +857,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, SILBuilderWithScope b(fn.getEntryBlock()->begin()); entryBlockOptionalNone = b.createOptionalNone(autoGenLoc, optionalEscapingClosureTy); - updater.AddAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone); + updater.addAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone); } assert(entryBlockOptionalNone); @@ -872,7 +872,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, // operand consumed at +1, so we don't need a copy) to it. auto *result = b.createOptionalSome(autoGenLoc, sentinelClosure, optionalEscapingClosureTy); - updater.AddAvailableValue(result->getParent(), result); + updater.addAvailableValue(result->getParent(), result); return result; }(); @@ -881,14 +881,14 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, if (singleDestroy) { SILBuilderWithScope b(std::next(singleDestroy->getIterator())); auto *result = b.createOptionalNone(autoGenLoc, optionalEscapingClosureTy); - updater.AddAvailableValue(result->getParent(), result); + updater.addAvailableValue(result->getParent(), result); } // Now that we have all of our available values, insert a destroy_value before // the initial Optional.some value using the SSA updater to ensure that we // handle loops correctly. { - SILValue v = updater.GetValueInMiddleOfBlock(initialValue->getParent()); + SILValue v = updater.getValueInMiddleOfBlock(initialValue->getParent()); SILBuilderWithScope(initialValue).createDestroyValue(autoGenLoc, v); } @@ -896,7 +896,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, // lifetime end points. This ensures we do not expand our lifetime too much. if (singleDestroy) { SILBuilderWithScope b(std::next(singleDestroy->getIterator())); - SILValue v = updater.GetValueInMiddleOfBlock(singleDestroy->getParent()); + SILValue v = updater.getValueInMiddleOfBlock(singleDestroy->getParent()); SILValue isEscaping = b.createIsEscapingClosure(loc, v, IsEscapingClosureInst::ObjCEscaping); b.createCondFail(loc, isEscaping, "non-escaping closure has escaped"); @@ -911,7 +911,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, for (auto *block : exitingBlocks) { auto *safeDestructionPt = getDeinitSafeClosureDestructionPoint(block); - SILValue v = updater.GetValueAtEndOfBlock(block); + SILValue v = updater.getValueAtEndOfBlock(block); SILBuilderWithScope(safeDestructionPt).createDestroyValue(autoGenLoc, v); } } diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp index 5d4d4f889cb6c..1b7a6c384fc80 100644 --- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp +++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp @@ -686,7 +686,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy, // have multiple insertion points if we are storing exactly the same value // implying that we can just copy firstVal at each insertion point. SILSSAUpdater updater(&insertedPhiNodes); - updater.Initialize(loadTy); + updater.initialize(loadTy); Optional singularValue; for (auto *insertPt : insertPts) { @@ -707,7 +707,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy, } // And then put the value into the SSA updater. - updater.AddAvailableValue(insertPt->getParent(), eltVal); + updater.addAvailableValue(insertPt->getParent(), eltVal); } // If we only are tracking a singular value, we do not need to construct @@ -727,7 +727,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy, } // Finally, grab the value from the SSA updater. - SILValue result = updater.GetValueInMiddleOfBlock(B.getInsertionBB()); + SILValue result = updater.getValueInMiddleOfBlock(B.getInsertionBB()); assert(result.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Owned)); if (isTake() || !B.hasOwnership()) { return result; @@ -863,7 +863,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy, // never have the same value along all paths unless we have a trivial value // meaning the SSA updater given a non-trivial value must /always/ be used. SILSSAUpdater updater(&insertedPhiNodes); - updater.Initialize(loadTy); + updater.initialize(loadTy); Optional singularValue; for (auto *i : insertPts) { @@ -881,7 +881,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy, singularValue = SILValue(); } - updater.AddAvailableValue(i->getParent(), eltVal); + updater.addAvailableValue(i->getParent(), eltVal); } SILBasicBlock *insertBlock = B.getInsertionBB(); @@ -902,7 +902,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy, } // Finally, grab the value from the SSA updater. - SILValue eltVal = updater.GetValueInMiddleOfBlock(insertBlock); + SILValue eltVal = updater.getValueInMiddleOfBlock(insertBlock); assert(!B.hasOwnership() || eltVal.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Owned)); assert(eltVal->getType() == loadTy && "Subelement types mismatch"); diff --git a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp index fff5fafdde1f7..a040d1166d176 100644 --- a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp @@ -535,10 +535,10 @@ static void insertReleases(ArrayRef Stores, assert(!Stores.empty()); SILValue StVal = Stores.front()->getSrc(); - SSAUp.Initialize(StVal->getType()); + SSAUp.initialize(StVal->getType()); for (auto *Store : Stores) - SSAUp.AddAvailableValue(Store->getParent(), Store->getSrc()); + SSAUp.addAvailableValue(Store->getParent(), Store->getSrc()); SILLocation Loc = Stores[0]->getLoc(); for (auto *RelPoint : ReleasePoints) { @@ -547,7 +547,7 @@ static void insertReleases(ArrayRef Stores, // the right thing for local uses. We have already ensured a single store // per block, and all release points occur after all stores. Therefore we // can simply ask SSAUpdater for the reaching store. - SILValue RelVal = SSAUp.GetValueAtEndOfBlock(RelPoint->getParent()); + SILValue RelVal = SSAUp.getValueAtEndOfBlock(RelPoint->getParent()); if (StVal->getType().isReferenceCounted(RelPoint->getModule())) B.createStrongRelease(Loc, RelVal, B.getDefaultAtomicity()); else diff --git a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp index 06968a86b32a5..373d62d92c976 100644 --- a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp +++ b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp @@ -1337,14 +1337,14 @@ SILValue RLEContext::computePredecessorLocationValue(SILBasicBlock *BB, // Finally, collect all the values for the SILArgument, materialize it using // the SSAUpdater. - Updater.Initialize( + Updater.initialize( L.getType(&BB->getModule(), TypeExpansionContext(*BB->getParent())) .getObjectType()); for (auto V : Values) { - Updater.AddAvailableValue(V.first, V.second); + Updater.addAvailableValue(V.first, V.second); } - return Updater.GetValueInMiddleOfBlock(BB); + return Updater.getValueInMiddleOfBlock(BB); } bool RLEContext::collectLocationValues(SILBasicBlock *BB, LSLocation &L, diff --git a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp index a70372768b507..6b5a52240da00 100644 --- a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp +++ b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp @@ -107,9 +107,9 @@ void BasicBlockCloner::updateSSAAfterCloning() { for (auto *use : inst->getUses()) useList.push_back(UseWrapper(use)); - ssaUpdater.Initialize(inst->getType()); - ssaUpdater.AddAvailableValue(origBB, inst); - ssaUpdater.AddAvailableValue(getNewBB(), newResult); + ssaUpdater.initialize(inst->getType()); + ssaUpdater.addAvailableValue(origBB, inst); + ssaUpdater.addAvailableValue(getNewBB(), newResult); if (useList.empty()) continue; @@ -124,7 +124,7 @@ void BasicBlockCloner::updateSSAAfterCloning() { if (user->getParent() == origBB) continue; - ssaUpdater.RewriteUse(*use); + ssaUpdater.rewriteUse(*use); } } } diff --git a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp index ba37d210559d3..92dec29e38461 100644 --- a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp +++ b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp @@ -25,71 +25,75 @@ using namespace swift; -void *SILSSAUpdater::allocate(unsigned Size, unsigned Align) const { - return AlignedAlloc(Size, Align); +void *SILSSAUpdater::allocate(unsigned size, unsigned align) const { + return AlignedAlloc(size, align); } -void SILSSAUpdater::deallocateSentinel(SILUndef *D) { - AlignedFree(D); +void SILSSAUpdater::deallocateSentinel(SILUndef *undef) { + AlignedFree(undef); } -SILSSAUpdater::SILSSAUpdater(SmallVectorImpl *PHIs) - : AV(nullptr), PHISentinel(nullptr, deallocateSentinel), - InsertedPHIs(PHIs) {} +SILSSAUpdater::SILSSAUpdater(SmallVectorImpl *phis) + : blockToAvailableValueMap(nullptr), + phiSentinel(nullptr, deallocateSentinel), insertedPhis(phis) {} SILSSAUpdater::~SILSSAUpdater() = default; -void SILSSAUpdater::Initialize(SILType Ty) { - ValType = Ty; +void SILSSAUpdater::initialize(SILType inputType) { + type = inputType; - PHISentinel = std::unique_ptr( - SILUndef::getSentinelValue(Ty, this), SILSSAUpdater::deallocateSentinel); + phiSentinel = std::unique_ptr( + SILUndef::getSentinelValue(inputType, this), + SILSSAUpdater::deallocateSentinel); - if (!AV) - AV.reset(new AvailableValsTy()); + if (!blockToAvailableValueMap) + blockToAvailableValueMap.reset(new AvailableValsTy()); else - AV->clear(); + blockToAvailableValueMap->clear(); } -bool SILSSAUpdater::HasValueForBlock(SILBasicBlock *BB) const { - return AV->count(BB); +bool SILSSAUpdater::hasValueForBlock(SILBasicBlock *block) const { + return blockToAvailableValueMap->count(block); } /// Indicate that a rewritten value is available in the specified block with the /// specified value. -void SILSSAUpdater::AddAvailableValue(SILBasicBlock *BB, SILValue V) { - (*AV)[BB] = V; +void SILSSAUpdater::addAvailableValue(SILBasicBlock *block, SILValue value) { + (*blockToAvailableValueMap)[block] = value; } /// Construct SSA form, materializing a value that is live at the end of the /// specified block. -SILValue SILSSAUpdater::GetValueAtEndOfBlock(SILBasicBlock *BB) { - return GetValueAtEndOfBlockInternal(BB); +SILValue SILSSAUpdater::getValueAtEndOfBlock(SILBasicBlock *block) { + return getValueAtEndOfBlockInternal(block); } /// Are all available values identicalTo each other. -static bool areIdentical(llvm::DenseMap &Avails) { - if (auto *First = dyn_cast(Avails.begin()->second)) { - for (auto Avail : Avails) { - auto *Inst = dyn_cast(Avail.second); - if (!Inst) +static bool +areIdentical(llvm::DenseMap &availableValues) { + if (auto *firstInst = + dyn_cast(availableValues.begin()->second)) { + for (auto value : availableValues) { + auto *svi = dyn_cast(value.second); + if (!svi) return false; - if (!Inst->isIdenticalTo(First)) + if (!svi->isIdenticalTo(firstInst)) return false; } return true; } - auto *MVIR = dyn_cast(Avails.begin()->second); - if (!MVIR) + auto *mvir = + dyn_cast(availableValues.begin()->second); + if (!mvir) return false; - for (auto Avail : Avails) { - auto *Result = dyn_cast(Avail.second); - if (!Result) + for (auto value : availableValues) { + auto *result = dyn_cast(value.second); + if (!result) return false; - if (!Result->getParent()->isIdenticalTo(MVIR->getParent()) || - Result->getIndex() != MVIR->getIndex()) { + if (!result->getParent()->isIdenticalTo(mvir->getParent()) || + result->getIndex() != mvir->getIndex()) { return false; } } @@ -98,65 +102,61 @@ static bool areIdentical(llvm::DenseMap &Avails) { /// This should be called in top-down order of each def that needs its uses /// rewrited. The order that we visit uses for a given def is irrelevant. -void SILSSAUpdater::RewriteUse(Operand &Op) { +void SILSSAUpdater::rewriteUse(Operand &use) { // Replicate function_refs to their uses. SILGen can't build phi nodes for // them and it would not make much sense anyways. - if (auto *FR = dyn_cast(Op.get())) { - assert(areIdentical(*AV) && + if (auto *fri = dyn_cast(use.get())) { + assert(areIdentical(*blockToAvailableValueMap) && "The function_refs need to have the same value"); - SILInstruction *User = Op.getUser(); - auto *NewFR = cast(FR->clone(User)); - Op.set(NewFR); + SILInstruction *user = use.getUser(); + use.set(cast(fri->clone(user))); return; - } else if (auto *FR = dyn_cast(Op.get())) { - assert(areIdentical(*AV) && + } else if (auto *pdfri = + dyn_cast(use.get())) { + assert(areIdentical(*blockToAvailableValueMap) && "The function_refs need to have the same value"); - SILInstruction *User = Op.getUser(); - auto *NewFR = cast(FR->clone(User)); - Op.set(NewFR); + SILInstruction *user = use.getUser(); + use.set(cast(pdfri->clone(user))); return; - } else if (auto *FR = dyn_cast(Op.get())) { - assert(areIdentical(*AV) && + } else if (auto *dfri = dyn_cast(use.get())) { + assert(areIdentical(*blockToAvailableValueMap) && "The function_refs need to have the same value"); - SILInstruction *User = Op.getUser(); - auto *NewFR = cast(FR->clone(User)); - Op.set(NewFR); + SILInstruction *user = use.getUser(); + use.set(cast(dfri->clone(user))); return; - } else if (auto *IL = dyn_cast(Op.get())) - if (areIdentical(*AV)) { + } else if (auto *ili = dyn_cast(use.get())) + if (areIdentical(*blockToAvailableValueMap)) { // Some llvm intrinsics don't like phi nodes as their constant inputs (e.g // ctlz). - SILInstruction *User = Op.getUser(); - auto *NewIL = cast(IL->clone(User)); - Op.set(NewIL); + SILInstruction *user = use.getUser(); + use.set(cast(ili->clone(user))); return; } // Again we need to be careful here, because ssa construction (with the // existing representation) can change the operand from under us. - UseWrapper UW(&Op); + UseWrapper useWrapper(&use); - SILInstruction *User = Op.getUser(); - SILValue NewVal = GetValueInMiddleOfBlock(User->getParent()); - assert(NewVal && "Need a valid value"); - ((Operand *)UW)->set((SILValue)NewVal); + SILInstruction *user = use.getUser(); + SILValue newVal = getValueInMiddleOfBlock(user->getParent()); + assert(newVal && "Need a valid value"); + static_cast(useWrapper)->set(newVal); } - /// Get the edge values from the terminator to the destination basic block. -static OperandValueArrayRef getEdgeValuesForTerminator(TermInst *TI, - SILBasicBlock *ToBB) { - if (auto *BrInst = dyn_cast(TI)) { - assert(BrInst->getDestBB() == ToBB && +static OperandValueArrayRef getEdgeValuesForTerminator(TermInst *ti, + SILBasicBlock *toBlock) { + if (auto *br = dyn_cast(ti)) { + assert(br->getDestBB() == toBlock && "Incoming edge block and phi block mismatch"); - return BrInst->getArgs(); + return br->getArgs(); } - if (auto *CondBrInst = dyn_cast(TI)) { - bool IsTrueEdge = CondBrInst->getTrueBB() == ToBB; - assert(((IsTrueEdge && CondBrInst->getTrueBB() == ToBB) || - CondBrInst->getFalseBB() == ToBB) && + if (auto *cbi = dyn_cast(ti)) { + bool isTrueEdge = cbi->getTrueBB() == toBlock; + assert(((isTrueEdge && cbi->getTrueBB() == toBlock) || + cbi->getFalseBB() == toBlock) && "Incoming edge block and phi block mismatch"); - return IsTrueEdge ? CondBrInst->getTrueArgs() : CondBrInst->getFalseArgs(); + return isTrueEdge ? cbi->getTrueArgs() : cbi->getFalseArgs(); } // We need a predecessor who is capable of holding outgoing branch @@ -167,211 +167,219 @@ static OperandValueArrayRef getEdgeValuesForTerminator(TermInst *TI, /// Check that the argument has the same incoming edge values as the value /// map. static bool -isEquivalentPHI(SILPhiArgument *PHI, - llvm::SmallDenseMap &ValueMap) { - SILBasicBlock *PhiBB = PHI->getParent(); - size_t Idx = PHI->getIndex(); - for (auto *PredBB : PhiBB->getPredecessorBlocks()) { - auto DesiredVal = ValueMap[PredBB]; - OperandValueArrayRef EdgeValues = - getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB); - if (EdgeValues[Idx] != DesiredVal) +isEquivalentPHI(SILPhiArgument *phi, + llvm::SmallDenseMap &valueMap) { + SILBasicBlock *phiBlock = phi->getParent(); + size_t phiArgEdgeIndex = phi->getIndex(); + for (auto *predBlock : phiBlock->getPredecessorBlocks()) { + auto desiredVal = valueMap[predBlock]; + OperandValueArrayRef edgeValues = + getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock); + if (edgeValues[phiArgEdgeIndex] != desiredVal) return false; } return true; } -SILValue SILSSAUpdater::GetValueInMiddleOfBlock(SILBasicBlock *BB) { +SILValue SILSSAUpdater::getValueInMiddleOfBlock(SILBasicBlock *block) { // If this basic block does not define a value we can just use the value // live at the end of the block. - if (!HasValueForBlock(BB)) - return GetValueAtEndOfBlock(BB); + if (!hasValueForBlock(block)) + return getValueAtEndOfBlock(block); /// Otherwise, we have to build SSA for the value defined in this block and /// this block's predecessors. - SILValue SingularValue; - SmallVector, 4> PredVals; - bool FirstPred = true; + SILValue singularValue; + SmallVector, 4> predVals; + bool firstPred = true; // SSAUpdater can modify TerminatorInst and therefore invalidate the // predecessor iterator. Find all the predecessors before the SSA update. - SmallVector Preds; - for (auto *PredBB : BB->getPredecessorBlocks()) { - Preds.push_back(PredBB); + SmallVector preds; + for (auto *predBlock : block->getPredecessorBlocks()) { + preds.push_back(predBlock); } - for (auto *PredBB : Preds) { - SILValue PredVal = GetValueAtEndOfBlock(PredBB); - PredVals.push_back(std::make_pair(PredBB, PredVal)); - if (FirstPred) { - SingularValue = PredVal; - FirstPred = false; - } else if (SingularValue != PredVal) - SingularValue = SILValue(); + for (auto *predBlock : preds) { + SILValue predVal = getValueAtEndOfBlock(predBlock); + predVals.push_back(std::make_pair(predBlock, predVal)); + if (firstPred) { + singularValue = predVal; + firstPred = false; + } else if (singularValue != predVal) + singularValue = SILValue(); } // Return undef for blocks without predecessor. - if (PredVals.empty()) - return SILUndef::get(ValType, *BB->getParent()); + if (predVals.empty()) + return SILUndef::get(type, *block->getParent()); - if (SingularValue) - return SingularValue; + if (singularValue) + return singularValue; // Check if we already have an equivalent phi. - if (!BB->getArguments().empty()) { - llvm::SmallDenseMap ValueMap(PredVals.begin(), - PredVals.end()); - for (auto *Arg : BB->getSILPhiArguments()) - if (isEquivalentPHI(Arg, ValueMap)) - return Arg; - + if (!block->getArguments().empty()) { + llvm::SmallDenseMap valueMap(predVals.begin(), + predVals.end()); + for (auto *arg : block->getSILPhiArguments()) + if (isEquivalentPHI(arg, valueMap)) + return arg; } // Create a new phi node. - SILPhiArgument *PHI = - BB->createPhiArgument(ValType, ValueOwnershipKind::Owned); - for (auto &EV : PredVals) - addNewEdgeValueToBranch(EV.first->getTerminator(), BB, EV.second); + SILPhiArgument *phiArg = + block->createPhiArgument(type, ValueOwnershipKind::Owned); + for (auto &pair : predVals) + addNewEdgeValueToBranch(pair.first->getTerminator(), block, pair.second); - if (InsertedPHIs) - InsertedPHIs->push_back(PHI); + if (insertedPhis) + insertedPhis->push_back(phiArg); - return PHI; + return phiArg; } -/// SSAUpdaterTraits - Traits for the SSAUpdaterImpl -/// template, specialized for MachineSSAUpdater. namespace llvm { -template<> + +/// Traits for the SSAUpdaterImpl specialized for SIL and the SILSSAUpdater. +template <> class SSAUpdaterTraits { public: - typedef SILBasicBlock BlkT; - typedef SILValue ValT; - typedef SILPhiArgument PhiT; + using BlkT = SILBasicBlock; + using ValT = SILValue; + using PhiT = SILPhiArgument; - typedef SILBasicBlock::succ_iterator BlkSucc_iterator; - static BlkSucc_iterator BlkSucc_begin(BlkT *BB) { return BB->succ_begin(); } - static BlkSucc_iterator BlkSucc_end(BlkT *BB) { return BB->succ_end(); } + using BlkSucc_iterator = SILBasicBlock::succ_iterator; + static BlkSucc_iterator BlkSucc_begin(BlkT *block) { + return block->succ_begin(); + } + static BlkSucc_iterator BlkSucc_end(BlkT *block) { return block->succ_end(); } /// Iterator for PHI operands. class PHI_iterator { private: - SILBasicBlock::pred_iterator PredIt; - SILBasicBlock *BB; - size_t Idx; + SILBasicBlock::pred_iterator predBlockIter; + SILBasicBlock *phiBlock; + size_t phiArgEdgeIndex; public: - explicit PHI_iterator(SILPhiArgument *P) // begin iterator - : PredIt(P->getParent()->pred_begin()), - BB(P->getParent()), - Idx(P->getIndex()) {} - PHI_iterator(SILPhiArgument *P, bool) // end iterator - : PredIt(P->getParent()->pred_end()), - BB(P->getParent()), - Idx(P->getIndex()) {} - - PHI_iterator &operator++() { ++PredIt; return *this; } - bool operator==(const PHI_iterator& x) const { return PredIt == x.PredIt; } + explicit PHI_iterator(SILPhiArgument *phiArg) // begin iterator + : predBlockIter(phiArg->getParent()->pred_begin()), + phiBlock(phiArg->getParent()), phiArgEdgeIndex(phiArg->getIndex()) {} + PHI_iterator(SILPhiArgument *phiArg, bool) // end iterator + : predBlockIter(phiArg->getParent()->pred_end()), + phiBlock(phiArg->getParent()), phiArgEdgeIndex(phiArg->getIndex()) {} + + PHI_iterator &operator++() { + ++predBlockIter; + return *this; + } + + bool operator==(const PHI_iterator &x) const { + return predBlockIter == x.predBlockIter; + } + bool operator!=(const PHI_iterator& x) const { return !operator==(x); } - SILValue getValueForBlock(size_t Idx, SILBasicBlock *BB, TermInst *TI) { - OperandValueArrayRef Args = getEdgeValuesForTerminator(TI, BB); - assert(Idx < Args.size() && "Not enough values on incoming edge"); - return Args[Idx]; + SILValue getValueForBlock(size_t inputArgIndex, SILBasicBlock *block, + TermInst *ti) { + OperandValueArrayRef args = getEdgeValuesForTerminator(ti, block); + assert(inputArgIndex < args.size() && + "Not enough values on incoming edge"); + return args[inputArgIndex]; } SILValue getIncomingValue() { - return getValueForBlock(Idx, BB, (*PredIt)->getTerminator()); + return getValueForBlock(phiArgEdgeIndex, phiBlock, + (*predBlockIter)->getTerminator()); } - SILBasicBlock *getIncomingBlock() { - return *PredIt; - } + SILBasicBlock *getIncomingBlock() { return *predBlockIter; } }; - static inline PHI_iterator PHI_begin(PhiT *PHI) { return PHI_iterator(PHI); } - static inline PHI_iterator PHI_end(PhiT *PHI) { - return PHI_iterator(PHI, true); + static inline PHI_iterator PHI_begin(PhiT *phi) { return PHI_iterator(phi); } + static inline PHI_iterator PHI_end(PhiT *phi) { + return PHI_iterator(phi, true); } /// Put the predecessors of BB into the Preds vector. - static void FindPredecessorBlocks(SILBasicBlock *BB, - SmallVectorImpl *Preds){ - for (SILBasicBlock::pred_iterator PI = BB->pred_begin(), E = BB->pred_end(); - PI != E; ++PI) - Preds->push_back(*PI); + static void + FindPredecessorBlocks(SILBasicBlock *block, + SmallVectorImpl *predBlocks) { + llvm::copy(block->getPredecessorBlocks(), std::back_inserter(*predBlocks)); } - static SILValue GetUndefVal(SILBasicBlock *BB, - SILSSAUpdater *Updater) { - return SILUndef::get(Updater->ValType, *BB->getParent()); + static SILValue GetUndefVal(SILBasicBlock *block, SILSSAUpdater *ssaUpdater) { + return SILUndef::get(ssaUpdater->type, *block->getParent()); } /// Add an Argument to the basic block. - static SILValue CreateEmptyPHI(SILBasicBlock *BB, unsigned NumPreds, - SILSSAUpdater *Updater) { + static SILValue CreateEmptyPHI(SILBasicBlock *block, unsigned numPreds, + SILSSAUpdater *ssaUpdater) { // Add the argument to the block. - SILValue PHI( - BB->createPhiArgument(Updater->ValType, ValueOwnershipKind::Owned)); + SILValue phi( + block->createPhiArgument(ssaUpdater->type, ValueOwnershipKind::Owned)); // Mark all predecessor blocks with the sentinel undef value. - SmallVector Preds(BB->pred_begin(), BB->pred_end()); - for (auto *PredBB: Preds) { - TermInst *TI = PredBB->getTerminator(); - addNewEdgeValueToBranch(TI, BB, Updater->PHISentinel.get()); + SmallVector predBlockList( + block->getPredecessorBlocks()); + + for (auto *predBlock : predBlockList) { + TermInst *ti = predBlock->getTerminator(); + addNewEdgeValueToBranch(ti, block, ssaUpdater->phiSentinel.get()); } - return PHI; + + return phi; } - /// Add the specified value as an operand of the PHI for the specified - /// predecessor block. - static void AddPHIOperand(SILPhiArgument *PHI, SILValue Val, - SILBasicBlock *Pred) { - auto *PHIBB = PHI->getParent(); - size_t PhiIdx = PHI->getIndex(); - auto *TI = Pred->getTerminator(); - changeEdgeValue(TI, PHIBB, PhiIdx, Val); + /// Add \p value as an operand of the phi argument \p phi for the specified + /// predecessor block \p predBlock. + static void AddPHIOperand(SILPhiArgument *phi, SILValue value, + SILBasicBlock *predBlock) { + auto *phiBlock = phi->getParent(); + size_t phiArgIndex = phi->getIndex(); + auto *ti = predBlock->getTerminator(); + changeEdgeValue(ti, phiBlock, phiArgIndex, value); } - /// InstrIsPHI - Check if an instruction is a PHI. - /// - static SILPhiArgument *InstrIsPHI(ValueBase *I) { - auto *Res = dyn_cast(I); - return Res; + /// Check if an instruction is a PHI. + static SILPhiArgument *InstrIsPHI(ValueBase *valueBase) { + return dyn_cast(valueBase); } - /// ValueIsPHI - Check if the instruction that defines the specified register - /// is a PHI instruction. - static SILPhiArgument *ValueIsPHI(SILValue V, SILSSAUpdater *Updater) { - return InstrIsPHI(V); + /// Check if the instruction that defines the specified SILValue is a PHI + /// instruction. + static SILPhiArgument *ValueIsPHI(SILValue value, SILSSAUpdater *) { + return InstrIsPHI(value); } /// Like ValueIsPHI but also check if the PHI has no source /// operands, i.e., it was just added. - static SILPhiArgument *ValueIsNewPHI(SILValue Val, SILSSAUpdater *Updater) { - SILPhiArgument *PHI = ValueIsPHI(Val, Updater); - if (PHI) { - auto *PhiBB = PHI->getParent(); - size_t PhiIdx = PHI->getIndex(); - - // If all predecessor edges are 'not set' this is a new phi. - for (auto *PredBB : PhiBB->getPredecessorBlocks()) { - OperandValueArrayRef Edges = - getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB); - - assert(PhiIdx < Edges.size() && "Not enough edges!"); - - SILValue V = Edges[PhiIdx]; - // Check for the 'not set' sentinel. - if (V != Updater->PHISentinel.get()) - return nullptr; - } - return PHI; + static SILPhiArgument *ValueIsNewPHI(SILValue value, + SILSSAUpdater *ssaUpdater) { + SILPhiArgument *phiArg = ValueIsPHI(value, ssaUpdater); + if (!phiArg) { + return nullptr; } - return nullptr; + + auto *phiBlock = phiArg->getParent(); + size_t phiArgEdgeIndex = phiArg->getIndex(); + + // If all predecessor edges are 'not set' this is a new phi. + for (auto *predBlock : phiBlock->getPredecessorBlocks()) { + OperandValueArrayRef edgeValues = + getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock); + + assert(phiArgEdgeIndex < edgeValues.size() && "Not enough edges!"); + + SILValue edgeValue = edgeValues[phiArgEdgeIndex]; + // Check for the 'not set' sentinel. + if (edgeValue != ssaUpdater->phiSentinel.get()) + return nullptr; + } + return phiArg; } - static SILValue GetPHIValue(SILPhiArgument *PHI) { return PHI; } + static SILValue GetPHIValue(SILPhiArgument *phi) { return phi; } }; } // namespace llvm @@ -379,14 +387,15 @@ class SSAUpdaterTraits { /// Check to see if AvailableVals has an entry for the specified BB and if so, /// return it. If not, construct SSA form by first calculating the required /// placement of PHIs and then inserting new PHIs where needed. -SILValue SILSSAUpdater::GetValueAtEndOfBlockInternal(SILBasicBlock *BB){ - AvailableValsTy &AvailableVals = *AV; - auto AI = AvailableVals.find(BB); - if (AI != AvailableVals.end()) - return AI->second; - - llvm::SSAUpdaterImpl Impl(this, &AvailableVals, InsertedPHIs); - return Impl.GetValue(BB); +SILValue SILSSAUpdater::getValueAtEndOfBlockInternal(SILBasicBlock *block) { + AvailableValsTy &availableValues = *blockToAvailableValueMap; + auto iter = availableValues.find(block); + if (iter != availableValues.end()) + return iter->second; + + llvm::SSAUpdaterImpl impl(this, &availableValues, + insertedPhis); + return impl.GetValue(block); } /// Construct a use wrapper. For branches we store information so that we @@ -395,67 +404,70 @@ SILValue SILSSAUpdater::GetValueAtEndOfBlockInternal(SILBasicBlock *BB){ /// When a branch is modified existing pointers to the operand /// (ValueUseIterator) become invalid as they point to freed operands. Instead /// we store the branch's parent and the idx so that we can reconstruct the use. -UseWrapper::UseWrapper(Operand *Use) { - U = nullptr; - Type = kRegularUse; +UseWrapper::UseWrapper(Operand *inputUse) { + wrappedUse = nullptr; + type = kRegularUse; - SILInstruction *User = Use->getUser(); + SILInstruction *user = inputUse->getUser(); // Direct branch user. - if (auto *Br = dyn_cast(User)) { - auto Opds = User->getAllOperands(); - for (unsigned i = 0, e = Opds.size(); i != e; ++i) { - if (Use == &Opds[i]) { - Idx = i; - Type = kBranchUse; - Parent = Br->getParent(); + if (auto *br = dyn_cast(user)) { + for (auto pair : llvm::enumerate(user->getAllOperands())) { + if (inputUse == &pair.value()) { + index = pair.index(); + type = kBranchUse; + parent = br->getParent(); return; } } } // Conditional branch user. - if (auto *Br = dyn_cast(User)) { - auto Opds = User->getAllOperands(); - auto NumTrueArgs = Br->getTrueArgs().size(); - for (unsigned i = 0, e = Opds.size(); i != e; ++i) { - if (Use == &Opds[i]) { + if (auto *cbi = dyn_cast(user)) { + auto operands = user->getAllOperands(); + auto numTrueArgs = cbi->getTrueArgs().size(); + for (auto pair : llvm::enumerate(operands)) { + if (inputUse == &pair.value()) { + unsigned i = pair.index(); // We treat the condition as part of the true args. - if (i < NumTrueArgs + 1) { - Idx = i; - Type = kCondBranchUseTrue; + if (i < numTrueArgs + 1) { + index = i; + type = kCondBranchUseTrue; } else { - Idx = i - NumTrueArgs - 1; - Type = kCondBranchUseFalse; + index = i - numTrueArgs - 1; + type = kCondBranchUseFalse; } - Parent = Br->getParent(); + parent = cbi->getParent(); return; } } } - U = Use; + wrappedUse = inputUse; } /// Return the operand we wrap. Reconstructing branch operands. Operand *UseWrapper::getOperand() { - switch (Type) { + switch (type) { case kRegularUse: - return U; + return wrappedUse; case kBranchUse: { - auto *Br = cast(Parent->getTerminator()); - assert(Idx < Br->getNumArgs()); - return &Br->getAllOperands()[Idx]; + auto *br = cast(parent->getTerminator()); + assert(index < br->getNumArgs()); + return &br->getAllOperands()[index]; } case kCondBranchUseTrue: case kCondBranchUseFalse: { - auto *Br = cast(Parent->getTerminator()); - unsigned IdxToUse = - Type == kCondBranchUseTrue ? Idx : Br->getTrueArgs().size() + 1 + Idx; - assert(IdxToUse < Br->getAllOperands().size()); - return &Br->getAllOperands()[IdxToUse]; + auto *cbi = cast(parent->getTerminator()); + auto indexToUse = [&]() -> unsigned { + if (type == kCondBranchUseTrue) + return index; + return cbi->getTrueArgs().size() + 1 + index; + }(); + assert(indexToUse < cbi->getAllOperands().size()); + return &cbi->getAllOperands()[indexToUse]; } } @@ -470,12 +482,12 @@ Operand *UseWrapper::getOperand() { /// ArgValues are the values feeding the specified Argument from each /// predecessor. They must be listed in order of Arg->getParent()->getPreds(). static StructInst * -replaceBBArgWithStruct(SILPhiArgument *Arg, - SmallVectorImpl &ArgValues) { +replaceBBArgWithStruct(SILPhiArgument *phiArg, + SmallVectorImpl &argValues) { - SILBasicBlock *PhiBB = Arg->getParent(); - auto *FirstSI = dyn_cast(ArgValues[0]); - if (!FirstSI) + SILBasicBlock *phiBlock = phiArg->getParent(); + auto *firstSI = dyn_cast(argValues[0]); + if (!firstSI) return nullptr; // Collect the BBArg index of each struct oper. @@ -483,42 +495,45 @@ replaceBBArgWithStruct(SILPhiArgument *Arg, // struct(A, B) // br (B, A) // : ArgIdxForOper => {1, 0} - SmallVector ArgIdxForOper; - for (unsigned OperIdx : indices(FirstSI->getElements())) { - bool FoundMatchingArgIdx = false; - for (unsigned ArgIdx : indices(PhiBB->getArguments())) { - SmallVectorImpl::const_iterator AVIter = ArgValues.begin(); - bool TryNextArgIdx = false; - for (SILBasicBlock *PredBB : PhiBB->getPredecessorBlocks()) { + SmallVector argIdxForOper; + for (unsigned operIdx : indices(firstSI->getElements())) { + bool foundMatchingArgIdx = false; + for (unsigned argIdx : indices(phiBlock->getArguments())) { + auto avIter = argValues.begin(); + bool tryNextArgIdx = false; + for (SILBasicBlock *predBlock : phiBlock->getPredecessorBlocks()) { // All argument values must be StructInst. - auto *PredSI = dyn_cast(*AVIter++); - if (!PredSI) + auto *predSI = dyn_cast(*avIter++); + if (!predSI) return nullptr; - OperandValueArrayRef EdgeValues = - getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB); - if (EdgeValues[ArgIdx] != PredSI->getElements()[OperIdx]) { - TryNextArgIdx = true; + OperandValueArrayRef edgeValues = + getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock); + if (edgeValues[argIdx] != predSI->getElements()[operIdx]) { + tryNextArgIdx = true; break; } } - if (!TryNextArgIdx) { - assert(AVIter == ArgValues.end() && "# ArgValues does not match # BB preds"); - FoundMatchingArgIdx = true; - ArgIdxForOper.push_back(ArgIdx); + if (!tryNextArgIdx) { + assert(avIter == argValues.end() && + "# ArgValues does not match # BB preds"); + foundMatchingArgIdx = true; + argIdxForOper.push_back(argIdx); break; } } - if (!FoundMatchingArgIdx) + if (!foundMatchingArgIdx) return nullptr; } - SmallVector StructArgs; - for (auto ArgIdx : ArgIdxForOper) - StructArgs.push_back(PhiBB->getArgument(ArgIdx)); + SmallVector structArgs; + for (auto argIdx : argIdxForOper) + structArgs.push_back(phiBlock->getArgument(argIdx)); - SILBuilder Builder(PhiBB, PhiBB->begin()); - return Builder.createStruct(cast(ArgValues[0])->getLoc(), - Arg->getType(), StructArgs); + // TODO: We probably want to use a SILBuilderWithScope here. What should we + // use? + SILBuilder builder(phiBlock, phiBlock->begin()); + return builder.createStruct(cast(argValues[0])->getLoc(), + phiArg->getType(), structArgs); } /// Canonicalize BB arguments, replacing argument-of-casts with @@ -527,10 +542,10 @@ replaceBBArgWithStruct(SILPhiArgument *Arg, /// detection like induction variable analysis to succeed. /// /// If Arg is replaced, return the cast instruction. Otherwise return nullptr. -SILValue swift::replaceBBArgWithCast(SILPhiArgument *Arg) { - SmallVector ArgValues; - Arg->getIncomingPhiValues(ArgValues); - if (isa(ArgValues[0])) - return replaceBBArgWithStruct(Arg, ArgValues); +SILValue swift::replaceBBArgWithCast(SILPhiArgument *arg) { + SmallVector argValues; + arg->getIncomingPhiValues(argValues); + if (isa(argValues[0])) + return replaceBBArgWithStruct(arg, argValues); return nullptr; } From d3f0de804dd3b58c836efe24d9ab73b574c46215 Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Thu, 6 Aug 2020 23:44:55 +0100 Subject: [PATCH 050/123] [SE-0163] Migrate from deprecated Unicode APIs (part 3) (#33175) --- stdlib/public/core/StaticString.swift | 15 +-------------- test/IRGen/objc_super.swift | 2 +- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/stdlib/public/core/StaticString.swift b/stdlib/public/core/StaticString.swift index 2f5c1ce03e549..d314b4c990431 100644 --- a/stdlib/public/core/StaticString.swift +++ b/stdlib/public/core/StaticString.swift @@ -172,20 +172,7 @@ public struct StaticString { return body(UnsafeBufferPointer( start: utf8Start, count: utf8CodeUnitCount)) } else { - var buffer: UInt64 = 0 - var i = 0 - let sink: (UInt8) -> Void = { -#if _endian(little) - buffer = buffer | (UInt64($0) << (UInt64(i) * 8)) -#else - buffer = buffer | (UInt64($0) << (UInt64(7-i) * 8)) -#endif - i += 1 - } - UTF8.encode(unicodeScalar, into: sink) - return body(UnsafeBufferPointer( - start: UnsafePointer(Builtin.addressof(&buffer)), - count: i)) + return unicodeScalar.withUTF8CodeUnits { body($0) } } } diff --git a/test/IRGen/objc_super.swift b/test/IRGen/objc_super.swift index 72b045bd7ea2f..645e75c53cc53 100644 --- a/test/IRGen/objc_super.swift +++ b/test/IRGen/objc_super.swift @@ -136,5 +136,5 @@ class GenericRuncer : Gizmo { } // CHECK: define internal swiftcc void [[PARTIAL_FORWARDING_THUNK]](%swift.refcounted* swiftself %0) {{.*}} { -// CHECK: @"$ss12StaticStringV14withUTF8BufferyxxSRys5UInt8VGXElFyAEcfU_" +// CHECK: @"$ss12StaticStringV14withUTF8BufferyxxSRys5UInt8VGXElFxAFXEfU_" // CHECK: } From ad83b21b1df7d08a10186e8507b70c6ef2fff140 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 6 Aug 2020 19:22:05 -0400 Subject: [PATCH 051/123] Add another test case to test/Constraints/sr12365.swift This one was reduced from , which we have decided is an acceptable source break because the old behavior was incorrect. --- test/Constraints/sr12365.swift | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/Constraints/sr12365.swift b/test/Constraints/sr12365.swift index 368985a4ac7eb..09a97afb320d8 100644 --- a/test/Constraints/sr12365.swift +++ b/test/Constraints/sr12365.swift @@ -16,8 +16,22 @@ func check(a: Double, b: Int64) -> Bool { return a != 0 && b != 0 // Okay } -func check() { +func check1() { let x: Int = 1 let _ = UInt(1) << x - 1 // Okay let _ = UInt(1) << (x + 1) - 1 // Okay } + +func check2() { + let a: UInt32 = 0 + let b: UInt32 = 1 << (a + 16) + let _ = a & b // Okay +} + +func check3() { + let a: UInt32 = 0 + let b = 1 << (a + 16) + let _ = a & b // Not okay, because 'b: Int'! + // expected-error@-1 {{binary operator '&' cannot be applied to operands of type 'UInt32' and 'Int'}} + // expected-note@-2 {{overloads for '&' exist with these partially matching parameter lists: (Int, Int), (UInt32, UInt32)}} +} From adbbc0018155121292e954665a9f5c5c1dba168c Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 6 Aug 2020 16:55:37 -0700 Subject: [PATCH 052/123] [CSFix] Add a warning fix for situations when trailing closure is matched via backward scan --- lib/Sema/CSFix.cpp | 12 ++++++++++++ lib/Sema/CSFix.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index db3aadcaf1311..af42c6408a32d 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1526,3 +1526,15 @@ UnwrapOptionalBaseKeyPathApplication::attempt(ConstraintSystem &cs, Type baseTy, return new (cs.getAllocator()) UnwrapOptionalBaseKeyPathApplication(cs, baseTy, rootTy, locator); } + +bool SpecifyLabelToAssociateTrailingClosure::diagnose(const Solution &solution, + bool asNote) const { + return false; +} + +SpecifyLabelToAssociateTrailingClosure * +SpecifyLabelToAssociateTrailingClosure::create(ConstraintSystem &cs, + ConstraintLocator *locator) { + return new (cs.getAllocator()) + SpecifyLabelToAssociateTrailingClosure(cs, locator); +} diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 662779f26e0da..ae232f33ff187 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -269,6 +269,10 @@ enum class FixKind : uint8_t { /// Unwrap optional base on key path application. UnwrapOptionalBaseKeyPathApplication, + + /// Explicitly specify a label to match trailing closure to a certain + /// parameter in the call. + SpecifyLabelToAssociateTrailingClosure, }; class ConstraintFix { @@ -1926,6 +1930,34 @@ class UnwrapOptionalBaseKeyPathApplication final : public ContextualMismatch { ConstraintLocator *locator); }; +/// Diagnose situations when solver used old (backward scan) rule +/// to match trailing closure to a parameter. +/// +/// \code +/// func multiple_trailing_with_defaults( +/// duration: Int, +/// animations: (() -> Void)? = nil, +/// completion: (() -> Void)? = nil) {} +/// +/// multiple_trailing_with_defaults(duration: 42) {} // picks `completion:` +/// \endcode +class SpecifyLabelToAssociateTrailingClosure final : public ConstraintFix { + SpecifyLabelToAssociateTrailingClosure(ConstraintSystem &cs, + ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::SpecifyLabelToAssociateTrailingClosure, + locator, /*isWarning=*/true) {} + +public: + std::string getName() const override { + return "specify a label to associate trailing closure with parameter"; + } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + static SpecifyLabelToAssociateTrailingClosure * + create(ConstraintSystem &cs, ConstraintLocator *locator); +}; + } // end namespace constraints } // end namespace swift From 19fce323c5d2829d06c076aab8a27810a4ce24c9 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Thu, 6 Aug 2020 17:58:00 -0700 Subject: [PATCH 053/123] [Diagnostics] For array element conversion failures, emit an error message for each element whose type variable was merged in addJoinConstraint --- lib/Sema/CSDiagnostics.cpp | 27 +++++++++++++++++++++++++ lib/Sema/CSDiagnostics.h | 2 ++ test/Constraints/diagnostics.swift | 2 +- test/Parse/pointer_conversion.swift.gyb | 2 +- test/expr/cast/as_coerce.swift | 4 ++-- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index e57e64680558f..1ea4617af879f 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -4942,6 +4942,9 @@ bool CollectionElementContextualFailure::diagnoseAsError() { Optional diagnostic; if (isExpr(anchor)) { + if (diagnoseMergedLiteralElements()) + return true; + diagnostic.emplace(emitDiagnostic(diag::cannot_convert_array_element, eltType, contextualType)); } @@ -4992,6 +4995,30 @@ bool CollectionElementContextualFailure::diagnoseAsError() { return true; } +bool CollectionElementContextualFailure::diagnoseMergedLiteralElements() { + auto elementAnchor = simplifyLocatorToAnchor(getLocator()); + if (!elementAnchor) + return false; + + auto *typeVar = getRawType(elementAnchor)->getAs(); + if (!typeVar || !typeVar->getImpl().getAtomicLiteralKind()) + return false; + + // This element is a literal whose type variable could have been merged with others, + // but the conversion constraint to the array element type was only placed on one + // of them. So, we want to emit the error for each element whose type variable is in + // this equivalence class. + auto &cs = getConstraintSystem(); + auto node = cs.getRepresentative(typeVar)->getImpl().getGraphNode(); + for (const auto *typeVar : node->getEquivalenceClass()) { + auto anchor = typeVar->getImpl().getLocator()->getAnchor(); + emitDiagnosticAt(constraints::getLoc(anchor), diag::cannot_convert_array_element, + getFromType(), getToType()); + } + + return true; +} + bool MissingContextualConformanceFailure::diagnoseAsError() { auto anchor = getAnchor(); auto path = getLocator()->getPath(); diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index e6134c200cdb3..17ca225d66c0d 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -1637,6 +1637,8 @@ class CollectionElementContextualFailure final : public ContextualFailure { : ContextualFailure(solution, eltType, contextualType, locator) {} bool diagnoseAsError() override; + + bool diagnoseMergedLiteralElements(); }; class MissingContextualConformanceFailure final : public ContextualFailure { diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index e961b108bda48..bff33fe7caa73 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -338,7 +338,7 @@ variadic(arrayWithOtherEltType) // expected-error {{cannot convert value of type variadic(1, arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Int'}} // FIXME: SR-11104 -variadic(["hello", "world"]) // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} +variadic(["hello", "world"]) // expected-error 2 {{cannot convert value of type 'String' to expected element type 'Int'}} // expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} // expected-note@-2 {{remove brackets to pass array elements directly}} diff --git a/test/Parse/pointer_conversion.swift.gyb b/test/Parse/pointer_conversion.swift.gyb index 4c9af4a6a5568..616285d4fbda6 100644 --- a/test/Parse/pointer_conversion.swift.gyb +++ b/test/Parse/pointer_conversion.swift.gyb @@ -164,7 +164,7 @@ func constPointerArguments(_ p: UnsafeMutablePointer, takesConstPointer([0, 1, 2]) // QoI: CSDiags doesn't handle array -> pointer impl conversions well takesConstPointer([0.0, 1.0, 2.0]) - // expected-error@-1 {{cannot convert value of type 'Double' to expected element type 'Int'}} + // expected-error@-1 3 {{cannot convert value of type 'Double' to expected element type 'Int'}} // We don't allow these conversions outside of function arguments. var x: UnsafePointer = &i // expected-error {{use of extraneous '&'}} diff --git a/test/expr/cast/as_coerce.swift b/test/expr/cast/as_coerce.swift index 3821104d339e1..962c656322ca1 100644 --- a/test/expr/cast/as_coerce.swift +++ b/test/expr/cast/as_coerce.swift @@ -84,13 +84,13 @@ c3 as C4 // expected-error {{'C3' is not convertible to 'C4'; did you mean to us Double(1) as Double as String // expected-error{{cannot convert value of type 'Double' to type 'String' in coercion}} ["awd"] as [Int] // expected-error{{cannot convert value of type 'String' to expected element type 'Int'}} ([1, 2, 1.0], 1) as ([String], Int) -// expected-error@-1 {{cannot convert value of type 'Int' to expected element type 'String'}} +// expected-error@-1 2 {{cannot convert value of type 'Int' to expected element type 'String'}} // expected-error@-2 {{cannot convert value of type 'Double' to expected element type 'String'}} [[1]] as [[String]] // expected-error{{cannot convert value of type 'Int' to expected element type 'String'}} (1, 1.0) as (Int, Int) // expected-error{{cannot convert value of type '(Int, Double)' to type '(Int, Int)' in coercion}} (1.0, 1, "asd") as (String, Int, Float) // expected-error{{cannot convert value of type '(Double, Int, String)' to type '(String, Int, Float)' in coercion}} (1, 1.0, "a", [1, 23]) as (Int, Double, String, [String]) -// expected-error@-1 {{cannot convert value of type 'Int' to expected element type 'String'}} +// expected-error@-1 2 {{cannot convert value of type 'Int' to expected element type 'String'}} _ = [1] as! [String] // OK _ = [(1, (1, 1))] as! [(Int, (String, Int))] // OK From b98085d69e491118949ce7e37c7b6bdfd1e5332a Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Thu, 6 Aug 2020 23:44:28 -0700 Subject: [PATCH 054/123] [Doc] Update CI trigger for CentOS and Ubuntu --- docs/ContinuousIntegration.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/ContinuousIntegration.md b/docs/ContinuousIntegration.md index c6c381d7d4d7a..545b08a5e5006 100644 --- a/docs/ContinuousIntegration.md +++ b/docs/ContinuousIntegration.md @@ -92,9 +92,11 @@ macOS platform | @swift-ci Please smoke benchmark | S Linux platform | @swift-ci Please test Linux platform | Swift Test Linux Platform (smoke test)
Swift Test Linux Platform Linux platform | @swift-ci Please clean test Linux platform | Swift Test Linux Platform (smoke test)
Swift Test Linux Platform macOS platform | @swift-ci Please ASAN test | Swift ASAN Test OS X Platform -Ubuntu 20.04 | @swift-ci Please test Ubuntu 20.04 platform | Swift Test Ubuntu 20.04 Platform -CentOS 8 | @swift-ci Please test CentOS 8 platform | Swift Test CentOS 8 Platform -Amazon Linux 2 | @swift-ci Please test Amazon Linux 2 platform | Swift Test Amazon Linux 2 Platform +Ubuntu 18.04 | @swift-ci Please test Ubuntu 18.04 platform | Swift Test Ubuntu 18.04 Platform +Ubuntu 20.04 | @swift-ci Please test Ubuntu 20.04 platform | Swift Test Ubuntu 20.04 Platform +CentOS 7 | @swift-ci Please test CentOS 7 platform | Swift Test CentOS 7 Platform +CentOS 8 | @swift-ci Please test CentOS 8 platform | Swift Test CentOS 8 Platform +Amazon Linux 2 | @swift-ci Please test Amazon Linux 2 platform | Swift Test Amazon Linux 2 Platform The core principles of validation testing is that: From a3cd8bc9e92b52d752a0171b6c865171c7cb6b2a Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Fri, 7 Aug 2020 00:26:07 -0700 Subject: [PATCH 055/123] [Tests] Codesign the binary before executing the test --- test/AutoDiff/stdlib/differential_operators.swift.gyb | 1 + test/ClangImporter/enum-error-execute.swift | 1 + .../Driver/SourceRanges/range-incremental-no-build-record.swift | 1 + test/Interpreter/SDK/objc_block_consumed.swift | 1 + test/Interpreter/SDK/objc_factory_method.swift | 1 + .../Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift | 1 + test/Interpreter/SDK/object_literals.swift | 1 + test/Interpreter/conditional_conformances_modules.swift | 1 + test/Interpreter/generic_casts.swift | 1 + test/Interpreter/generic_casts_objc.swift | 1 + test/Interpreter/multi_payload_extra_inhabitant.swift | 1 + test/Interpreter/objc_class_properties_runtime.swift | 1 + test/Interpreter/struct_extra_inhabitants.swift | 1 + test/Interpreter/testable_key_path.swift | 1 + test/Parse/strange_interpolation.swift | 1 + test/Profiler/coverage_smoke.swift | 1 + test/Profiler/pgo_checked_cast.swift | 1 + test/Profiler/pgo_foreach.swift | 1 + test/Profiler/pgo_guard.swift | 1 + test/Profiler/pgo_if.swift | 1 + test/Profiler/pgo_repeatwhile.swift | 1 + test/Profiler/pgo_switchenum.swift | 1 + test/Profiler/pgo_while.swift | 1 + test/Runtime/stable-bit-backward-deployment.swift | 1 + test/SILGen/property_wrapper_autoclosure.swift | 1 + test/SILOptimizer/array_element_propagation_crash.swift | 1 + test/SILOptimizer/cowarray_opt_crash.swift | 1 + test/SILOptimizer/cross-module-optimization-objc.swift | 2 ++ test/SILOptimizer/cross-module-optimization.swift | 2 ++ test/SILOptimizer/devirtualize_class_method.swift | 1 + test/SILOptimizer/di_property_wrappers.swift | 1 + test/SILOptimizer/dse_with_union.swift | 1 + test/SILOptimizer/existential_box_elimination.swift | 1 + test/SILOptimizer/global_hoisting_crash.swift | 1 + test/SILOptimizer/lazy_property_getters.swift | 1 + test/SILOptimizer/licm_and_global_addr.swift | 1 + test/SILOptimizer/pgo_si_inlinelarge.swift | 1 + test/SILOptimizer/pgo_si_reduce.swift | 1 + test/SILOptimizer/property_wrappers_and_tuples.swift | 1 + test/SILOptimizer/sil_combine_alloc_stack.swift | 1 + test/SILOptimizer/silcombine_aebox_miscompile.swift | 1 + test/SILOptimizer/silcombine_runtime_crash.swift | 1 + test/SILOptimizer/stack_promotion_crash.swift | 1 + .../attr/attr_originally_definedin_backward_compatibility.swift | 2 ++ test/stdlib/Compatibility50Linking.c | 1 + test/stdlib/Error.swift | 1 + test/stdlib/ErrorBridged.swift | 1 + test/stdlib/Integers.swift.gyb | 1 + test/stdlib/OSLogExecutionTest.swift | 2 ++ test/stdlib/StringBridge.swift | 1 + test/stdlib/TestCalendar.swift | 2 ++ test/stdlib/dlopen_race.swift | 1 + validation-test/Reflection/reflect_nested.swift | 1 + validation-test/execution/arc_36509461.swift | 1 + validation-test/stdlib/NewArray.swift.gyb | 1 + 55 files changed, 60 insertions(+) diff --git a/test/AutoDiff/stdlib/differential_operators.swift.gyb b/test/AutoDiff/stdlib/differential_operators.swift.gyb index 5376a5d9adb87..36378874e36cf 100644 --- a/test/AutoDiff/stdlib/differential_operators.swift.gyb +++ b/test/AutoDiff/stdlib/differential_operators.swift.gyb @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %gyb %s -o %t/differential_operators.swift // RUN: %target-build-swift %t/differential_operators.swift -o %t/differential_operators +// RUN: %target-codesign %t/differential_operators // RUN: %target-run %t/differential_operators // REQUIRES: executable_test diff --git a/test/ClangImporter/enum-error-execute.swift b/test/ClangImporter/enum-error-execute.swift index 263571febb3fd..c7038c00037ad 100644 --- a/test/ClangImporter/enum-error-execute.swift +++ b/test/ClangImporter/enum-error-execute.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-clang %S/Inputs/enum-error.m -c -o %t/enum-error.o // RUN: %target-build-swift -import-objc-header %S/Inputs/enum-error.h -Xlinker %t/enum-error.o %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/Driver/SourceRanges/range-incremental-no-build-record.swift b/test/Driver/SourceRanges/range-incremental-no-build-record.swift index 3fb929a7a6cb0..9aa0897be8f00 100644 --- a/test/Driver/SourceRanges/range-incremental-no-build-record.swift +++ b/test/Driver/SourceRanges/range-incremental-no-build-record.swift @@ -51,4 +51,5 @@ // RUN: %FileCheck -match-full-lines -check-prefix=CHECK-COMPARE-DISABLED-NO-BUILD-RECORD %s < %t/output1 // CHECK-COMPARE-DISABLED-NO-BUILD-RECORD: *** Incremental build disabled because could not read build record, cannot compare *** +// RUN: %target-codesign %t/main // RUN: %target-run %t/main | tee run1 | grep Any > /dev/null && rm %t/main diff --git a/test/Interpreter/SDK/objc_block_consumed.swift b/test/Interpreter/SDK/objc_block_consumed.swift index bee0890a639d6..5c591976d3d88 100644 --- a/test/Interpreter/SDK/objc_block_consumed.swift +++ b/test/Interpreter/SDK/objc_block_consumed.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -import-objc-header %S/Inputs/objc_block_consumed.h -o %t/main +// RUN: %target-codesign %t/main // RUN: %target-run %t/main // REQUIRES: executable_test diff --git a/test/Interpreter/SDK/objc_factory_method.swift b/test/Interpreter/SDK/objc_factory_method.swift index 712bfe950c464..bd768a04a7020 100644 --- a/test/Interpreter/SDK/objc_factory_method.swift +++ b/test/Interpreter/SDK/objc_factory_method.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -module-name FactoryTest %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test // REQUIRES: OS=macosx diff --git a/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift b/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift index 8853000397703..e3680337eab73 100644 --- a/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift +++ b/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -swift-version 4 -Xfrontend -enable-swift3-objc-inference %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out 2>&1 | %FileCheck %s -check-prefix=CHECK_WARNINGS // RUN: env %env-SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT=0 %target-run %t/a.out 2>&1 | %FileCheck %s -check-prefix=CHECK_NOTHING diff --git a/test/Interpreter/SDK/object_literals.swift b/test/Interpreter/SDK/object_literals.swift index 6a14ac895c247..85167094671ab 100644 --- a/test/Interpreter/SDK/object_literals.swift +++ b/test/Interpreter/SDK/object_literals.swift @@ -2,6 +2,7 @@ // RUN: %empty-directory(%t/Test.app/Contents/MacOS) // RUN: cp -r %S/Inputs/object_literals-Resources %t/Test.app/Contents/Resources // RUN: %target-build-swift %s -o %t/Test.app/Contents/MacOS/main +// RUN: %target-codesign %t/Test.app/Contents/MacOS/main // RUN: %target-run %t/Test.app/Contents/MacOS/main %t/Test.app/Contents/Resources/* // REQUIRES: executable_test diff --git a/test/Interpreter/conditional_conformances_modules.swift b/test/Interpreter/conditional_conformances_modules.swift index d485c50974895..1fca8aae5113a 100644 --- a/test/Interpreter/conditional_conformances_modules.swift +++ b/test/Interpreter/conditional_conformances_modules.swift @@ -3,6 +3,7 @@ // RUN: %target-build-swift-dylib(%t/%target-library-name(WithAssoc)) %S/../Inputs/conditional_conformance_with_assoc.swift -module-name WithAssoc -emit-module -emit-module-path %t/WithAssoc.swiftmodule // RUN: %target-build-swift-dylib(%t/%target-library-name(Subclass)) %S/../Inputs/conditional_conformance_subclass.swift -module-name Subclass -emit-module -emit-module-path %t/Subclass.swiftmodule // RUN: %target-build-swift -I%t -L%t -lBasic -lWithAssoc -lSubclass %s -o %t/conditional_conformances_modules %target-rpath(%t) +// RUN: %target-codesign %t/conditional_conformances_modules // RUN: %target-run %t/conditional_conformances_modules %t/%target-library-name(Basic) %t/%target-library-name(WithAssoc) %t/%target-library-name(Subclass) // REQUIRES: executable_test diff --git a/test/Interpreter/generic_casts.swift b/test/Interpreter/generic_casts.swift index 73f1837d20ab9..0993c2d5e0810 100644 --- a/test/Interpreter/generic_casts.swift +++ b/test/Interpreter/generic_casts.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -Onone %s -o %t/a.out // RUN: %target-build-swift -O %s -o %t/a.out.optimized +// RUN: %target-codesign %t/a.out // RUN: %target-codesign %t/a.out.optimized // // RUN: %target-run %t/a.out | %FileCheck --check-prefix CHECK %s diff --git a/test/Interpreter/generic_casts_objc.swift b/test/Interpreter/generic_casts_objc.swift index e9561d2e2e047..275711a2655bf 100644 --- a/test/Interpreter/generic_casts_objc.swift +++ b/test/Interpreter/generic_casts_objc.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -Onone %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck --check-prefix CHECK --check-prefix CHECK-ONONE %s // RUN: %target-build-swift -O %s -o %t/a.out.optimized // RUN: %target-codesign %t/a.out.optimized diff --git a/test/Interpreter/multi_payload_extra_inhabitant.swift b/test/Interpreter/multi_payload_extra_inhabitant.swift index 21aee2d92439a..03c1be8806c06 100644 --- a/test/Interpreter/multi_payload_extra_inhabitant.swift +++ b/test/Interpreter/multi_payload_extra_inhabitant.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -parse-stdlib -Xfrontend -verify-type-layout -Xfrontend SpareBitExtraInhabitants -Xfrontend -verify-type-layout -Xfrontend SpareBitSingleExtraInhabitant -Xfrontend -verify-type-layout -Xfrontend SpareBitNoExtraInhabitant -Xfrontend -verify-type-layout -Xfrontend SpareBitNoExtraInhabitant2 -Xfrontend -verify-type-layout -Xfrontend TwoTagExtraInhabitants -Xfrontend -verify-type-layout -Xfrontend ThreeTagExtraInhabitants -Xfrontend -verify-type-layout -Xfrontend NoTagExtraInhabitants -Xfrontend -verify-type-layout -Xfrontend DynamicExtraInhabitantsNever -Xfrontend -verify-type-layout -Xfrontend DynamicExtraInhabitantsZeroBytes -Xfrontend -verify-type-layout -Xfrontend DynamicExtraInhabitantsOneByte -Xfrontend -verify-type-layout -Xfrontend DynamicExtraInhabitantsTwoBytes -Xfrontend -verify-type-layout -Xfrontend MoreSpareBitsThanTagsExtraInhabitants -Xfrontend -verify-type-layout -Xfrontend OptOptMoreSpareBitsThanTagsExtraInhabitants -O -o %t/a.out %s +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out 2>&1 // Type layout verifier is only compiled into the runtime in asserts builds. diff --git a/test/Interpreter/objc_class_properties_runtime.swift b/test/Interpreter/objc_class_properties_runtime.swift index 1d1cf21348c45..e2b848d798663 100644 --- a/test/Interpreter/objc_class_properties_runtime.swift +++ b/test/Interpreter/objc_class_properties_runtime.swift @@ -3,6 +3,7 @@ // RUN: %clang -arch %target-cpu -mmacosx-version-min=10.11 -isysroot %sdk -fobjc-arc %S/Inputs/ObjCClasses/ObjCClasses.m -c -o %t/ObjCClasses.o // RUN: %swiftc_driver -target $(echo '%target-triple' | sed -E -e 's/macosx10.(9|10).*/macosx10.11/') -sdk %sdk -I %S/Inputs/ObjCClasses/ %t/ObjCClasses.o %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out // REQUIRES: OS=macosx diff --git a/test/Interpreter/struct_extra_inhabitants.swift b/test/Interpreter/struct_extra_inhabitants.swift index b86568911fce6..38a4393c94fb9 100644 --- a/test/Interpreter/struct_extra_inhabitants.swift +++ b/test/Interpreter/struct_extra_inhabitants.swift @@ -5,6 +5,7 @@ // -- run tests // RUN: %target-build-swift -parse-stdlib -Xfrontend -verify-type-layout -Xfrontend PairWithPointerFirst -Xfrontend -verify-type-layout -Xfrontend PairWithPointerSecond -Xfrontend -verify-type-layout -Xfrontend PairWithPointerSecondAndPhantomParam_Int -Xfrontend -verify-type-layout -Xfrontend GenericPairWithPointerFirst_Int -Xfrontend -verify-type-layout -Xfrontend GenericPairWithPointerFirst_AnyObject -Xfrontend -verify-type-layout -Xfrontend GenericPairWithPointerSecond_Int -Xfrontend -verify-type-layout -Xfrontend GenericPairWithPointerSecond_AnyObject -Xfrontend -verify-type-layout -Xfrontend StringAlike32 -Xfrontend -verify-type-layout -Xfrontend StringAlike64 -I %t -o %t/a.out.tests %s %t/ExtraInhabitantResilientTypes.o +// RUN: %target-codesign %t/a.out.tests // RUN: %target-run %t/a.out.tests 2>&1 // Type layout verifier is only compiled into the runtime in asserts builds. diff --git a/test/Interpreter/testable_key_path.swift b/test/Interpreter/testable_key_path.swift index de7c3f1ef79d2..7bcb16dceb178 100644 --- a/test/Interpreter/testable_key_path.swift +++ b/test/Interpreter/testable_key_path.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -whole-module-optimization -c -o %t/Module.o -enable-testing -parse-as-library -emit-module -emit-module-path %t/Module.swiftmodule -module-name Module %S/Inputs/testable_key_path_2.swift // RUN: %target-build-swift -o %t/a.out -I %t %s %t/Module.o +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/Parse/strange_interpolation.swift b/test/Parse/strange_interpolation.swift index ef2062ff43bfd..023ed7f4f0e32 100644 --- a/test/Parse/strange_interpolation.swift +++ b/test/Parse/strange_interpolation.swift @@ -2,6 +2,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -swift-version 4.2 %s -o %t/main +// RUN: %target-codesign %t/main // RUN: %target-run %t/main | %FileCheck %s // REQUIRES: executable_test diff --git a/test/Profiler/coverage_smoke.swift b/test/Profiler/coverage_smoke.swift index 9c60045ceaa97..b059962a17e8a 100644 --- a/test/Profiler/coverage_smoke.swift +++ b/test/Profiler/coverage_smoke.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_checked_cast.swift b/test/Profiler/pgo_checked_cast.swift index 0ad48c1d33310..f62ac58a42cdf 100644 --- a/test/Profiler/pgo_checked_cast.swift +++ b/test/Profiler/pgo_checked_cast.swift @@ -4,6 +4,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_foreach.swift b/test/Profiler/pgo_foreach.swift index 9f046099d3ae3..81ceb69222f2d 100644 --- a/test/Profiler/pgo_foreach.swift +++ b/test/Profiler/pgo_foreach.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_guard.swift b/test/Profiler/pgo_guard.swift index 5b77cc98daead..2a336ed1be702 100644 --- a/test/Profiler/pgo_guard.swift +++ b/test/Profiler/pgo_guard.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_if.swift b/test/Profiler/pgo_if.swift index 02a76dd65a9ca..c8a514210220f 100644 --- a/test/Profiler/pgo_if.swift +++ b/test/Profiler/pgo_if.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_repeatwhile.swift b/test/Profiler/pgo_repeatwhile.swift index 7671287a0a582..abf3053070884 100644 --- a/test/Profiler/pgo_repeatwhile.swift +++ b/test/Profiler/pgo_repeatwhile.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_switchenum.swift b/test/Profiler/pgo_switchenum.swift index 4357e84de3a6a..5f4aad55d01ac 100644 --- a/test/Profiler/pgo_switchenum.swift +++ b/test/Profiler/pgo_switchenum.swift @@ -4,6 +4,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_while.swift b/test/Profiler/pgo_while.swift index 9ce8c0a6cec31..3e73af5c66023 100644 --- a/test/Profiler/pgo_while.swift +++ b/test/Profiler/pgo_while.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Runtime/stable-bit-backward-deployment.swift b/test/Runtime/stable-bit-backward-deployment.swift index 09e18a7432c15..f478976dcee50 100644 --- a/test/Runtime/stable-bit-backward-deployment.swift +++ b/test/Runtime/stable-bit-backward-deployment.swift @@ -2,6 +2,7 @@ // -- Deployment target is set to pre-10.14.4 so that we use the "old" // Swift runtime bit in compiler-emitted classes // RUN: %target-build-swift -target %target-cpu-apple-macosx10.9 %s -module-name main -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILGen/property_wrapper_autoclosure.swift b/test/SILGen/property_wrapper_autoclosure.swift index b86098a692fcf..585cb5725ce6c 100644 --- a/test/SILGen/property_wrapper_autoclosure.swift +++ b/test/SILGen/property_wrapper_autoclosure.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/array_element_propagation_crash.swift b/test/SILOptimizer/array_element_propagation_crash.swift index 4eb809835790c..77dd187803f4a 100644 --- a/test/SILOptimizer/array_element_propagation_crash.swift +++ b/test/SILOptimizer/array_element_propagation_crash.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/cowarray_opt_crash.swift b/test/SILOptimizer/cowarray_opt_crash.swift index e9d2f860a7408..d047fb881d5e6 100644 --- a/test/SILOptimizer/cowarray_opt_crash.swift +++ b/test/SILOptimizer/cowarray_opt_crash.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/cross-module-optimization-objc.swift b/test/SILOptimizer/cross-module-optimization-objc.swift index 76465746f2f14..8d3129a3c1735 100644 --- a/test/SILOptimizer/cross-module-optimization-objc.swift +++ b/test/SILOptimizer/cross-module-optimization-objc.swift @@ -4,12 +4,14 @@ // RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/Test.swiftmodule -module-name=Test -I%t %S/Inputs/cross-module-objc.swift -c -o %t/test.o // RUN: %target-build-swift -O -wmo -module-name=Main -I%t %s -c -o %t/main.o // RUN: %target-swiftc_driver %t/main.o %t/test.o -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // Check if it also works if the main module is compiled with -Onone: // RUN: %target-build-swift -Onone -wmo -module-name=Main -I%t %s -c -o %t/main-onone.o // RUN: %target-swiftc_driver %t/main-onone.o %t/test.o -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // REQUIRES: executable_test diff --git a/test/SILOptimizer/cross-module-optimization.swift b/test/SILOptimizer/cross-module-optimization.swift index df1689c391719..31a298de82ae5 100644 --- a/test/SILOptimizer/cross-module-optimization.swift +++ b/test/SILOptimizer/cross-module-optimization.swift @@ -5,12 +5,14 @@ // RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/Test.swiftmodule -module-name=Test -I%t %S/Inputs/cross-module.swift -c -o %t/test.o // RUN: %target-build-swift -O -wmo -module-name=Main -I%t %s -c -o %t/main.o // RUN: %target-swiftc_driver %t/main.o %t/test.o %t/submodule.o -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // Check if it also works if the main module is compiled with -Onone: // RUN: %target-build-swift -Onone -wmo -module-name=Main -I%t %s -c -o %t/main-onone.o // RUN: %target-swiftc_driver %t/main-onone.o %t/test.o %t/submodule.o -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // REQUIRES: executable_test diff --git a/test/SILOptimizer/devirtualize_class_method.swift b/test/SILOptimizer/devirtualize_class_method.swift index 97a819da0bc66..095734354c072 100644 --- a/test/SILOptimizer/devirtualize_class_method.swift +++ b/test/SILOptimizer/devirtualize_class_method.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O -module-name=test %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/di_property_wrappers.swift b/test/SILOptimizer/di_property_wrappers.swift index 39b23d2b37c3c..c4db338ab2975 100644 --- a/test/SILOptimizer/di_property_wrappers.swift +++ b/test/SILOptimizer/di_property_wrappers.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/dse_with_union.swift b/test/SILOptimizer/dse_with_union.swift index 2d90d1937028d..9e36836ddfb8e 100644 --- a/test/SILOptimizer/dse_with_union.swift +++ b/test/SILOptimizer/dse_with_union.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -import-objc-header %S/Inputs/dse_with_union.h -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/existential_box_elimination.swift b/test/SILOptimizer/existential_box_elimination.swift index c2f838f3d5d25..4ddc7a6659d98 100644 --- a/test/SILOptimizer/existential_box_elimination.swift +++ b/test/SILOptimizer/existential_box_elimination.swift @@ -2,6 +2,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O -wmo -module-name=test %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out // REQUIRES: executable_test diff --git a/test/SILOptimizer/global_hoisting_crash.swift b/test/SILOptimizer/global_hoisting_crash.swift index b640f656e9bbb..44a49926773de 100644 --- a/test/SILOptimizer/global_hoisting_crash.swift +++ b/test/SILOptimizer/global_hoisting_crash.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/lazy_property_getters.swift b/test/SILOptimizer/lazy_property_getters.swift index f2282c9f1bcfc..e3e8b9d1eb7b1 100644 --- a/test/SILOptimizer/lazy_property_getters.swift +++ b/test/SILOptimizer/lazy_property_getters.swift @@ -3,6 +3,7 @@ // Also do an end-to-end test to check if the generated code is correct. // RUN: %empty-directory(%t) // RUN: %target-build-swift -O -Xllvm -module-name=test %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // REQUIRES: executable_test diff --git a/test/SILOptimizer/licm_and_global_addr.swift b/test/SILOptimizer/licm_and_global_addr.swift index d3b8fd73594ae..af332272c2f50 100644 --- a/test/SILOptimizer/licm_and_global_addr.swift +++ b/test/SILOptimizer/licm_and_global_addr.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %S/Inputs/licm_and_global_addr/test.swift -parse-as-library -wmo -enable-library-evolution -module-name=Test -emit-module -emit-module-path=%t/Test.swiftmodule -c -o %t/test.o // RUN: %target-build-swift -O %S/Inputs/licm_and_global_addr/main.swift %s -I%t %t/test.o -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/pgo_si_inlinelarge.swift b/test/SILOptimizer/pgo_si_inlinelarge.swift index 2947658b746a5..b90fcd0fb4864 100644 --- a/test/SILOptimizer/pgo_si_inlinelarge.swift +++ b/test/SILOptimizer/pgo_si_inlinelarge.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/SILOptimizer/pgo_si_reduce.swift b/test/SILOptimizer/pgo_si_reduce.swift index 3f5059b5a8e30..6e4e14b31ece6 100644 --- a/test/SILOptimizer/pgo_si_reduce.swift +++ b/test/SILOptimizer/pgo_si_reduce.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/SILOptimizer/property_wrappers_and_tuples.swift b/test/SILOptimizer/property_wrappers_and_tuples.swift index b45118f495257..783a36473384d 100644 --- a/test/SILOptimizer/property_wrappers_and_tuples.swift +++ b/test/SILOptimizer/property_wrappers_and_tuples.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -module-name=a -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/sil_combine_alloc_stack.swift b/test/SILOptimizer/sil_combine_alloc_stack.swift index 5a18f65738dbf..7da9e6302d651 100644 --- a/test/SILOptimizer/sil_combine_alloc_stack.swift +++ b/test/SILOptimizer/sil_combine_alloc_stack.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/silcombine_aebox_miscompile.swift b/test/SILOptimizer/silcombine_aebox_miscompile.swift index 587611be2e4b9..f392235ed8938 100644 --- a/test/SILOptimizer/silcombine_aebox_miscompile.swift +++ b/test/SILOptimizer/silcombine_aebox_miscompile.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O -module-name=a %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/silcombine_runtime_crash.swift b/test/SILOptimizer/silcombine_runtime_crash.swift index 63f298709e0d3..88b2a022a206a 100644 --- a/test/SILOptimizer/silcombine_runtime_crash.swift +++ b/test/SILOptimizer/silcombine_runtime_crash.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/stack_promotion_crash.swift b/test/SILOptimizer/stack_promotion_crash.swift index c08d7a29810bc..86f1de0b0d137 100644 --- a/test/SILOptimizer/stack_promotion_crash.swift +++ b/test/SILOptimizer/stack_promotion_crash.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/attr/attr_originally_definedin_backward_compatibility.swift b/test/attr/attr_originally_definedin_backward_compatibility.swift index a7abe24616ce6..07dea103cd0b3 100644 --- a/test/attr/attr_originally_definedin_backward_compatibility.swift +++ b/test/attr/attr_originally_definedin_backward_compatibility.swift @@ -24,6 +24,7 @@ // RUN: %target-rpath(@executable_path/SDK/Frameworks) // --- Run the executable +// RUN: %target-codesign %t/HighlevelRunner // RUN: %target-run %t/HighlevelRunner %t/SDK/Frameworks/HighLevel.framework/HighLevel | %FileCheck %s -check-prefix=BEFORE_MOVE // --- Build low level framework. @@ -39,6 +40,7 @@ // RUN: %S/Inputs/SymbolMove/HighLevel.swift -F %t/SDK/Frameworks -Xlinker -reexport_framework -Xlinker LowLevel -enable-library-evolution // --- Run the executable +// RUN: %target-codesign %t/HighlevelRunner // RUN: %target-run %t/HighlevelRunner %t/SDK/Frameworks/HighLevel.framework/HighLevel %t/SDK/Frameworks/LowLevel.framework/LowLevel | %FileCheck %s -check-prefix=AFTER_MOVE import HighLevel diff --git a/test/stdlib/Compatibility50Linking.c b/test/stdlib/Compatibility50Linking.c index b931461ccfbdc..deb98344323b7 100644 --- a/test/stdlib/Compatibility50Linking.c +++ b/test/stdlib/Compatibility50Linking.c @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-clang %s -all_load %test-resource-dir/%target-sdk-name/libswiftCompatibility50.a %test-resource-dir/%target-sdk-name/libswiftCompatibility51.a -lobjc -o %t/main +// RUN: %target-codesign %t/main // RUN: %target-run %t/main // REQUIRES: objc_interop // REQUIRES: executable_test diff --git a/test/stdlib/Error.swift b/test/stdlib/Error.swift index e235d6d296b98..898bdcef0cc57 100644 --- a/test/stdlib/Error.swift +++ b/test/stdlib/Error.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -o %t/Error -DPTR_SIZE_%target-ptrsize -module-name main %/s +// RUN: %target-codesign %t/Error // RUN: %target-run %t/Error // REQUIRES: executable_test diff --git a/test/stdlib/ErrorBridged.swift b/test/stdlib/ErrorBridged.swift index cc45b487fc0a8..b996dad5d213f 100644 --- a/test/stdlib/ErrorBridged.swift +++ b/test/stdlib/ErrorBridged.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -o %t/ErrorBridged -DPTR_SIZE_%target-ptrsize -module-name main %s +// RUN: %target-codesign %t/ErrorBridged // RUN: %target-run %t/ErrorBridged // REQUIRES: executable_test // REQUIRES: objc_interop diff --git a/test/stdlib/Integers.swift.gyb b/test/stdlib/Integers.swift.gyb index 5fe082d520239..01e664334a77b 100644 --- a/test/stdlib/Integers.swift.gyb +++ b/test/stdlib/Integers.swift.gyb @@ -12,6 +12,7 @@ // RUN: %empty-directory(%t) // RUN: %gyb -DWORD_BITS=%target-ptrsize %s -o %t/Integers.swift // RUN: %line-directive %t/Integers.swift -- %target-build-swift %t/Integers.swift -swift-version 4 -Onone -o %t/a.out +// RUN: %line-directive %t/Integers.swift -- %target-codesign %t/a.out // RUN: %line-directive %t/Integers.swift -- %target-run %t/a.out // REQUIRES: executable_test diff --git a/test/stdlib/OSLogExecutionTest.swift b/test/stdlib/OSLogExecutionTest.swift index 041de11b41ff2..5e1eda880ac7c 100644 --- a/test/stdlib/OSLogExecutionTest.swift +++ b/test/stdlib/OSLogExecutionTest.swift @@ -1,8 +1,10 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -swift-version 5 -DPTR_SIZE_%target-ptrsize -o %t/OSLogExecutionTest +// RUN: %target-codesign %t/OSLogExecutionTest // RUN: %target-run %t/OSLogExecutionTest // // RUN: %target-build-swift %s -O -swift-version 5 -DPTR_SIZE_%target-ptrsize -o %t/OSLogExecutionTest +// RUN: %target-codesign %t/OSLogExecutionTest // RUN: %target-run %t/OSLogExecutionTest // REQUIRES: executable_test // diff --git a/test/stdlib/StringBridge.swift b/test/stdlib/StringBridge.swift index ade117064deaf..f9ab61c19b930 100644 --- a/test/stdlib/StringBridge.swift +++ b/test/stdlib/StringBridge.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: cp %s %t/main.swift // RUN: %target-build-swift -Xfrontend -disable-access-control -module-name a %t/main.swift %S/../Inputs/SmallStringTestUtilities.swift -o %t.out -O +// RUN: %target-codesign %t.out // RUN: %target-run %t.out // REQUIRES: executable_test diff --git a/test/stdlib/TestCalendar.swift b/test/stdlib/TestCalendar.swift index df339391578f5..d6512605c3fd0 100644 --- a/test/stdlib/TestCalendar.swift +++ b/test/stdlib/TestCalendar.swift @@ -11,6 +11,8 @@ // RUN: %target-clang %S/Inputs/FoundationBridge/FoundationBridge.m -c -o %t/FoundationBridgeObjC.o -g // RUN: %target-build-swift %s -I %S/Inputs/FoundationBridge/ -Xlinker %t/FoundationBridgeObjC.o -o %t/TestCalendar +// RUN: %target-codesign %t/TestCalendar + // RUN: %target-run %t/TestCalendar > %t.txt // REQUIRES: executable_test // REQUIRES: objc_interop diff --git a/test/stdlib/dlopen_race.swift b/test/stdlib/dlopen_race.swift index 43d12118eca16..ce8c8a43df5a0 100644 --- a/test/stdlib/dlopen_race.swift +++ b/test/stdlib/dlopen_race.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -emit-library -o %t/dlopen_race.dylib %S/Inputs/dlopen_race_dylib.swift // RUN: %target-build-swift -o %t/dlopen_race %s +// RUN: %target-codesign %t/dlopen_race %t/dlopen_race.dylib // RUN: %target-run %t/dlopen_race %t/dlopen_race.dylib // REQUIRES: executable_test // REQUIRES: objc_interop diff --git a/validation-test/Reflection/reflect_nested.swift b/validation-test/Reflection/reflect_nested.swift index 41173d58fe41d..90cbc1a3c331d 100644 --- a/validation-test/Reflection/reflect_nested.swift +++ b/validation-test/Reflection/reflect_nested.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_nested +// RUN: %target-codesign %t/reflect_nested // RUN: %target-run %target-swift-reflection-test %t/reflect_nested 2>&1 | %FileCheck %s --check-prefix=CHECK-%target-ptrsize // REQUIRES: reflection_test_support // REQUIRES: executable_test diff --git a/validation-test/execution/arc_36509461.swift b/validation-test/execution/arc_36509461.swift index 5c730e33220f2..0d42cc5c1f1b4 100644 --- a/validation-test/execution/arc_36509461.swift +++ b/validation-test/execution/arc_36509461.swift @@ -2,6 +2,7 @@ // RUN: %target-clang -x objective-c -c %S/Inputs/arc_36509461.m -o %t/arc_36509461.m.o // RUN: %target-swift-frontend -c -O -import-objc-header %S/Inputs/arc_36509461.h -sanitize=address %s -o %t/arc_36509461.swift.o // RUN: %target-build-swift %t/arc_36509461.m.o %t/arc_36509461.swift.o -sanitize=address -o %t/arc_36509461 +// RUN: %target-codesign %t/arc_36509461 // RUN: %target-run %t/arc_36509461 // REQUIRES: executable_test diff --git a/validation-test/stdlib/NewArray.swift.gyb b/validation-test/stdlib/NewArray.swift.gyb index 4bfb174b34905..764cd5ec8d295 100644 --- a/validation-test/stdlib/NewArray.swift.gyb +++ b/validation-test/stdlib/NewArray.swift.gyb @@ -13,6 +13,7 @@ // RUN: %empty-directory(%t) // RUN: %gyb %s -o %t/NewArray.swift // RUN: %line-directive %t/NewArray.swift -- %target-build-swift %t/NewArray.swift -o %t/a.out -Xfrontend -disable-access-control +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out 2>&1 | %line-directive %t/NewArray.swift -- %FileCheck %t/NewArray.swift --check-prefix=CHECK --check-prefix=CHECK-%target-runtime // REQUIRES: executable_test From f292eb6b6a7afd6d6460f711bae4f00c4631bbe1 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 7 Aug 2020 00:30:32 -0700 Subject: [PATCH 056/123] [Diagnostics] Introduce a warning diagnostic for backward trailing closure matches Diagnose situations when trailing closure has been matched to a specific parameter via a deprecated backward scan. ```swift func multiple_trailing_with_defaults( duration: Int, animations: (() -> Void)? = nil, completion: (() -> Void)? = nil) {} multiple_trailing_with_defaults(duration: 42) {} // picks `completion:` ``` --- lib/Sema/CSDiagnostics.cpp | 92 +++++++++++++++++++++++++++++++++++++ lib/Sema/CSDiagnostics.h | 24 ++++++++++ lib/Sema/ConstraintSystem.h | 8 ++++ 3 files changed, 124 insertions(+) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 2003f09d6de94..b5c275ca6f883 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -6571,3 +6571,95 @@ SourceLoc MissingOptionalUnwrapKeyPathFailure::getLoc() const { auto *SE = castToExpr(getAnchor()); return SE->getBase()->getEndLoc(); } + +bool TrailingClosureRequiresExplicitLabel::diagnoseAsError() { + auto argInfo = *getFunctionArgApplyInfo(getLocator()); + + { + auto diagnostic = emitDiagnostic( + diag::unlabeled_trailing_closure_deprecated, argInfo.getParamLabel()); + fixIt(diagnostic, argInfo); + } + + if (auto *callee = argInfo.getCallee()) { + emitDiagnosticAt(callee, diag::decl_declared_here, callee->getName()); + } + + return true; +} + +void TrailingClosureRequiresExplicitLabel::fixIt( + InFlightDiagnostic &diagnostic, const FunctionArgApplyInfo &info) const { + auto &ctx = getASTContext(); + + // Dig out source locations. + SourceLoc existingRParenLoc; + SourceLoc leadingCommaLoc; + + auto anchor = getRawAnchor(); + auto *arg = info.getArgListExpr(); + Expr *fn = nullptr; + + if (auto *applyExpr = getAsExpr(anchor)) { + fn = applyExpr->getFn(); + } else { + // Covers subscripts, unresolved members etc. + fn = getAsExpr(anchor); + } + + if (!fn) + return; + + auto *trailingClosure = info.getArgExpr(); + + if (auto tupleExpr = dyn_cast(arg)) { + existingRParenLoc = tupleExpr->getRParenLoc(); + assert(tupleExpr->getNumElements() >= 2 && "Should be a ParenExpr?"); + leadingCommaLoc = Lexer::getLocForEndOfToken( + ctx.SourceMgr, + tupleExpr->getElements()[tupleExpr->getNumElements() - 2]->getEndLoc()); + } else { + auto parenExpr = cast(arg); + existingRParenLoc = parenExpr->getRParenLoc(); + } + + // Figure out the text to be inserted before the trailing closure. + SmallString<16> insertionText; + SourceLoc insertionLoc; + if (leadingCommaLoc.isValid()) { + insertionText += ", "; + assert(existingRParenLoc.isValid()); + insertionLoc = leadingCommaLoc; + } else if (existingRParenLoc.isInvalid()) { + insertionText += "("; + insertionLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, fn->getEndLoc()); + } else { + insertionLoc = existingRParenLoc; + } + + // Add the label, if there is one. + auto paramName = info.getParamLabel(); + if (!paramName.empty()) { + insertionText += paramName.str(); + insertionText += ": "; + } + + // If there is an existing right parentheses/brace, remove it while we + // insert the new text. + if (existingRParenLoc.isValid()) { + SourceLoc afterExistingRParenLoc = + Lexer::getLocForEndOfToken(ctx.SourceMgr, existingRParenLoc); + diagnostic.fixItReplaceChars(insertionLoc, afterExistingRParenLoc, + insertionText); + } else { + // Insert the appropriate prefix. + diagnostic.fixItInsert(insertionLoc, insertionText); + } + + // Insert a right parenthesis/brace after the closing '}' of the trailing + // closure; + SourceLoc newRParenLoc = + Lexer::getLocForEndOfToken(ctx.SourceMgr, trailingClosure->getEndLoc()); + diagnostic.fixItInsert(newRParenLoc, + isExpr(anchor) ? "]" : ")"); +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 2bbaebd30ec39..4d199c1f544f2 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -2214,6 +2214,30 @@ class MissingOptionalUnwrapKeyPathFailure final : public ContextualFailure { SourceLoc getLoc() const override; }; +/// Diagnose situations when trailing closure has been matched to a specific +/// parameter via deprecated backward scan. +/// +/// \code +/// func multiple_trailing_with_defaults( +/// duration: Int, +/// animations: (() -> Void)? = nil, +/// completion: (() -> Void)? = nil) {} +/// +/// multiple_trailing_with_defaults(duration: 42) {} // picks `completion:` +/// \endcode +class TrailingClosureRequiresExplicitLabel final : public FailureDiagnostic { +public: + TrailingClosureRequiresExplicitLabel(const Solution &solution, + ConstraintLocator *locator) + : FailureDiagnostic(solution, locator) {} + + bool diagnoseAsError() override; + +private: + void fixIt(InFlightDiagnostic &diagnostic, + const FunctionArgApplyInfo &info) const; +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 884357bbe5070..4a1ffaaf78dcd 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -554,6 +554,9 @@ class FunctionArgApplyInfo { ArgType(argType), ParamIdx(paramIdx), FnInterfaceType(fnInterfaceType), FnType(fnType), Callee(callee) {} + /// \returns The list of the arguments used for this application. + Expr *getArgListExpr() const { return ArgListExpr; } + /// \returns The argument being applied. Expr *getArgExpr() const { return ArgExpr; } @@ -581,6 +584,11 @@ class FunctionArgApplyInfo { return Identifier(); } + Identifier getParamLabel() const { + auto param = FnType->getParams()[ParamIdx]; + return param.getLabel(); + } + /// \returns A textual description of the argument suitable for diagnostics. /// For an argument with an unambiguous label, this will the label. Otherwise /// it will be its position in the argument list. From 50ac9abf9610fa707693a0980d5db03a087a23d8 Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Fri, 7 Aug 2020 09:12:21 -0300 Subject: [PATCH 057/123] [Sema] Adding contextual type purpose for where clause expression in constraint system --- lib/Sema/CSGen.cpp | 3 +++ test/Sema/diag_type_conversion.swift | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 432d1872e09d2..68f43d6cf7ab4 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -4019,6 +4019,9 @@ generateForEachStmtConstraints( if (cs.generateConstraints(whereTarget, FreeTypeVariableBinding::Disallow)) return None; + cs.setContextualType(forEachStmtInfo.whereExpr, + TypeLoc::withoutLoc(boolType), CTP_Condition); + forEachStmtInfo.whereExpr = whereTarget.getAsExpr(); } diff --git a/test/Sema/diag_type_conversion.swift b/test/Sema/diag_type_conversion.swift index 2f32d5886d863..ac7d0fdc02c99 100644 --- a/test/Sema/diag_type_conversion.swift +++ b/test/Sema/diag_type_conversion.swift @@ -72,3 +72,16 @@ _ = p =*= &o func rdar25963182(_ bytes: [UInt8] = nil) {} // expected-error@-1 {{nil default argument value cannot be converted to type}} + +// SR-13262 +struct SR13262_S {} + +func SR13262(_ x: Int) {} +func SR13262_Int(_ x: Int) -> Int { 0 } +func SR13262_SF(_ x: Int) -> SR13262_S { SR13262_S() } + +func testSR13262(_ arr: [Int]) { + for x in arr where SR13262(x) {} // expected-error {{cannot convert value of type '()' to expected condition type 'Bool'}} + for x in arr where SR13262_Int(x) {} // expected-error {{type 'Int' cannot be used as a boolean; test for '!= 0' instead}} {{22-22=(}} {{36-36= != 0)}} + for x in arr where SR13262_SF(x) {} // expected-error {{cannot convert value of type 'SR13262_S' to expected condition type 'Bool'}} +} From bea0238e12c859d78d0de72e8378d73cb2a757c7 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 4 Aug 2020 11:13:57 -0700 Subject: [PATCH 058/123] test: format configuration to be more pythonic Use `in` list comparison rather than equality to make it easy to extend and homogenise. --- test/lit.cfg | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/lit.cfg b/test/lit.cfg index ca4dd438242c8..e8a4a36443fbf 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -702,10 +702,10 @@ config.substitutions.append(('%target-cpu', run_cpu)) target_os_abi = run_os target_os_is_maccatalyst = "FALSE" target_mandates_stable_abi = "FALSE" -if (run_cpu == 'arm64e'): +if run_cpu in ('arm64e',): target_mandates_stable_abi = "TRUE" config.available_features.add('swift_only_stable_abi') -if (run_os == 'maccatalyst'): +if run_os in ('maccatalyst',): # For purposes of ABI, treat maccatalyst as macosx since the maccatalyst ABI # must match the macosx ABI. target_os_abi = 'macosx' @@ -715,7 +715,12 @@ if (run_os == 'maccatalyst'): if run_os in ('macosx',) and run_cpu in ('arm64',): target_mandates_stable_abi = "TRUE" config.available_features.add('swift_only_stable_abi') -if (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'openbsd', 'windows-cygnus', 'windows-gnu', 'windows-msvc', 'linux-android', 'linux-androideabi']): +if run_os in ( + 'linux-android', 'linux-androideabi', # Android + 'freebsd', 'openbsd', # BSD + 'linux-gnu', 'linux-gnueabihf', # Linux + 'windows-cygnus', 'windows-gnu', 'windows-msvc', # Windows + ): target_mandates_stable_abi = "TRUE" config.available_features.add('swift_only_stable_abi') config.substitutions.append(('%target-os-abi', target_os_abi)) From 84ea2a984b4bd59c4eab1e7c5c436be452e6d9bb Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 7 Aug 2020 09:08:43 -0700 Subject: [PATCH 059/123] SR-13362: no baseline is available for the standard library on ASi The standard library on non-Intel targets get compared to the baseline from the Intel targets which is not guaranteed to be identical. Mark the checks as expected failures on non-x86_64 targets. Although this is entirely unsatisfying, it allows progress in the short term. --- test/api-digester/stability-stdlib-abi-with-asserts.test | 7 +++++++ test/api-digester/stability-stdlib-source.swift | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/test/api-digester/stability-stdlib-abi-with-asserts.test b/test/api-digester/stability-stdlib-abi-with-asserts.test index 141d499d154d1..c75b63b7b1a4c 100644 --- a/test/api-digester/stability-stdlib-abi-with-asserts.test +++ b/test/api-digester/stability-stdlib-abi-with-asserts.test @@ -17,6 +17,13 @@ // REQUIRES: OS=macosx // REQUIRES: swift_stdlib_asserts + +// SR-13362 +// This currently fails on non-Intel architectures due to no baseline being +// available and it is not possible to filter across architectures in the +// output. +// XFAIL: CPU=arm64 || CPU=arm64e + // RUN: %empty-directory(%t.tmp) // mkdir %t.tmp/module-cache && mkdir %t.tmp/dummy.sdk // RUN: %api-digester -diagnose-sdk -module Swift -o %t.tmp/changes.txt -module-cache-path %t.tmp/module-cache -sdk %t.tmp/dummy.sdk -abi -avoid-location diff --git a/test/api-digester/stability-stdlib-source.swift b/test/api-digester/stability-stdlib-source.swift index f0e383a5cc2c2..6d5f0120c4457 100644 --- a/test/api-digester/stability-stdlib-source.swift +++ b/test/api-digester/stability-stdlib-source.swift @@ -1,4 +1,11 @@ // REQUIRES: OS=macosx + +// SR-13362 +// This currently fails on non-Intel architectures due to no baseline being +// available and it is not possible to filter across architectures in the +// output. +// XFAIL: CPU=arm64 || CPU=arm64e + // RUN: %empty-directory(%t.tmp) // mkdir %t.tmp/module-cache && mkdir %t.tmp/dummy.sdk // RUN: %api-digester -diagnose-sdk -module Swift -o %t.tmp/changes.txt -module-cache-path %t.tmp/module-cache -sdk %t.tmp/dummy.sdk -avoid-location From d30366f6c4a7561b63f231047b2f450181c0eca1 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 6 Aug 2020 14:17:59 -0700 Subject: [PATCH 060/123] Dispatch: correct `DispatchTimeInterval` calculation on ASi There is no guarantee that Mach ticks and nanoseconds have a 1:1 relationship. Use the `uptimeNanoseconds` field which will convert the raw value (which is in Mach ticks) to the time unit of nanoseconds. This was caught by the Dispatch stridable test in the Swift test suite. rdar://problem/56623421 --- stdlib/public/Darwin/Dispatch/Schedulers+DispatchQueue.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/public/Darwin/Dispatch/Schedulers+DispatchQueue.swift b/stdlib/public/Darwin/Dispatch/Schedulers+DispatchQueue.swift index 11780b57d713b..427ceb44cb4b8 100644 --- a/stdlib/public/Darwin/Dispatch/Schedulers+DispatchQueue.swift +++ b/stdlib/public/Darwin/Dispatch/Schedulers+DispatchQueue.swift @@ -45,8 +45,8 @@ extension DispatchTime /* : Strideable */ { typealias Stride = DispatchTimeInterval public func distance(to other: DispatchTime) -> DispatchTimeInterval { - let lhs = other.rawValue - let rhs = rawValue + let lhs = other.uptimeNanoseconds + let rhs = uptimeNanoseconds if lhs >= rhs { return DispatchTimeInterval.nanoseconds(Int(lhs - rhs)) } else { From 6e62444840fcd8685e80466b080997db97e2fc98 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 7 Aug 2020 09:47:52 -0700 Subject: [PATCH 061/123] test: use the `swift_only_stable_abi` feature instead of adhoc checks Use the proper `swift_only_stable_abi` check to ensure that the tests do not run on targets that do not support the pre-stable ABI. Thanks to @slavapestov for pointing out that there was a better way! --- test/IRGen/class_update_callback_without_fixed_layout.sil | 3 +-- test/IRGen/eager-class-initialization.swift | 3 +-- test/decl/protocol/conforms/nscoding.swift | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/test/IRGen/class_update_callback_without_fixed_layout.sil b/test/IRGen/class_update_callback_without_fixed_layout.sil index 72a1e63775cf0..82a6891e8a511 100644 --- a/test/IRGen/class_update_callback_without_fixed_layout.sil +++ b/test/IRGen/class_update_callback_without_fixed_layout.sil @@ -5,8 +5,7 @@ // RUN: %target-swift-frontend -I %t -emit-ir -enable-library-evolution -O %s -target %target-pre-stable-abi-triple // REQUIRES: objc_interop -// UNSUPPORTED: OS=iosmac -// UNSUPPORTED: CPU=arm64 || CPU=arm64e +// UNSUPPORTED: swift_only_stable_abi // With the old deployment target, these classes use the 'singleton' metadata // initialization pattern. The class is not statically visible to Objective-C, diff --git a/test/IRGen/eager-class-initialization.swift b/test/IRGen/eager-class-initialization.swift index 0f19d2f5cc63e..d1cbaac3b228b 100644 --- a/test/IRGen/eager-class-initialization.swift +++ b/test/IRGen/eager-class-initialization.swift @@ -3,8 +3,7 @@ // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -emit-ir -target %target-pre-stable-abi-triple | %FileCheck %s -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=CHECK-OLD // REQUIRES: objc_interop -// UNSUPPORTED: OS=iosmac -// UNSUPPORTED: CPU=arm64 || CPU=arm64e +// UNSUPPORTED: swift_only_stable_abi // See also eager-class-initialization-stable-abi.swift, for the stable ABI // deployment target test. diff --git a/test/decl/protocol/conforms/nscoding.swift b/test/decl/protocol/conforms/nscoding.swift index 69f839bc0721c..b6a846921caee 100644 --- a/test/decl/protocol/conforms/nscoding.swift +++ b/test/decl/protocol/conforms/nscoding.swift @@ -8,7 +8,7 @@ // RUN: %FileCheck --check-prefix=NEGATIVE %s < %t/old.ast // REQUIRES: objc_interop -// UNSUPPORTED: CPU=arm64e +// UNSUPPORTED: swift_only_stable_abi // See also nscoding_stable_abi.swift, for the stable ABI deployment // target test. From e57961c95f0d436b0e0e7e8ff402cbb527fda81c Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Fri, 7 Aug 2020 14:09:42 -0400 Subject: [PATCH 062/123] [Runtime] Fix the ISA mask assert for ARM64 running on ARM64e hardware. --- stdlib/public/runtime/Private.h | 4 +++- stdlib/public/runtime/SwiftObject.mm | 13 +++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h index 21c8e2906f104..4be3fb6bdb025 100644 --- a/stdlib/public/runtime/Private.h +++ b/stdlib/public/runtime/Private.h @@ -103,9 +103,11 @@ class TypeInfo { // value here. # define SWIFT_ISA_MASK 0xfffffffffffffff8ULL # elif __arm64__ +// The ISA mask used when ptrauth is available. +# define SWIFT_ISA_MASK_PTRAUTH 0x007ffffffffffff8ULL // ARM64 simulators always use the ARM64e mask. # if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR -# define SWIFT_ISA_MASK 0x007ffffffffffff8ULL +# define SWIFT_ISA_MASK SWIFT_ISA_MASK_PTRAUTH # else # if TARGET_OS_OSX # define SWIFT_ISA_MASK 0x00007ffffffffff8ULL diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm index d0022f0399085..f377a77d6f106 100644 --- a/stdlib/public/runtime/SwiftObject.mm +++ b/stdlib/public/runtime/SwiftObject.mm @@ -199,8 +199,17 @@ static id _getClassDescription(Class cls) { @implementation SwiftObject + (void)initialize { #if SWIFT_HAS_ISA_MASKING && !TARGET_OS_SIMULATOR && !NDEBUG - assert(&objc_absolute_packed_isa_class_mask); - assert((uintptr_t)&objc_absolute_packed_isa_class_mask == SWIFT_ISA_MASK); + uintptr_t libObjCMask = (uintptr_t)&objc_absolute_packed_isa_class_mask; + assert(libObjCMask); + +# if __arm64__ && !__has_feature(ptrauth_calls) + // When we're built ARM64 but running on ARM64e hardware, we will get an + // ARM64e libobjc with an ARM64e ISA mask. This mismatch is harmless and we + // shouldn't assert. + assert(libObjCMask == SWIFT_ISA_MASK || libObjCMask == SWIFT_ISA_MASK_PTRAUTH); +# else + assert(libObjCMask == SWIFT_ISA_MASK); +# endif #endif } From 44d686f71d68aac7f83377a1a240844ef0df2a5a Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 7 Aug 2020 11:50:29 -0700 Subject: [PATCH 063/123] [ConstraintSystem] Use new "specify label" fix/diagnostic to warn about backward scan --- lib/Sema/CSDiagnostics.h | 2 +- lib/Sema/CSFix.cpp | 3 +- lib/Sema/CSSimplify.cpp | 21 ++++++++++--- .../forward_trailing_closure_ambiguity.swift | 30 +++++++++++++++++++ 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 4d199c1f544f2..302c2a955935f 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -2215,7 +2215,7 @@ class MissingOptionalUnwrapKeyPathFailure final : public ContextualFailure { }; /// Diagnose situations when trailing closure has been matched to a specific -/// parameter via deprecated backward scan. +/// parameter via a deprecated backward scan. /// /// \code /// func multiple_trailing_with_defaults( diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index af42c6408a32d..96f6a43872284 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1529,7 +1529,8 @@ UnwrapOptionalBaseKeyPathApplication::attempt(ConstraintSystem &cs, Type baseTy, bool SpecifyLabelToAssociateTrailingClosure::diagnose(const Solution &solution, bool asNote) const { - return false; + TrailingClosureRequiresExplicitLabel failure(solution, getLocator()); + return failure.diagnose(asNote); } SpecifyLabelToAssociateTrailingClosure * diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index b85e02d509480..97832a4798175 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1208,6 +1208,9 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments( // Match up the call arguments to the parameters. SmallVector parameterBindings; + TrailingClosureMatching selectedTrailingMatching = + TrailingClosureMatching::Forward; + { ArgumentFailureTracker listener(cs, argsWithLabels, params, locator); auto callArgumentMatch = constraints::matchCallArguments( @@ -1224,10 +1227,10 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments( return cs.getTypeMatchAmbiguous(); } + selectedTrailingMatching = callArgumentMatch->trailingClosureMatching; // Record the direction of matching used for this call. - cs.recordTrailingClosureMatch( - cs.getConstraintLocator(locator), - callArgumentMatch->trailingClosureMatching); + cs.recordTrailingClosureMatch(cs.getConstraintLocator(locator), + selectedTrailingMatching); // If there was a disjunction because both forward and backward were // possible, increase the score for forward matches to bias toward the @@ -1316,6 +1319,15 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments( } } + // In case solver matched trailing based on the backward scan, + // let's produce a warning which would suggest to add a label + // to disambiguate in the future. + if (selectedTrailingMatching == TrailingClosureMatching::Backward && + argIdx == *argInfo->UnlabeledTrailingClosureIndex) { + cs.recordFix(SpecifyLabelToAssociateTrailingClosure::create( + cs, cs.getConstraintLocator(loc))); + } + // If argument comes for declaration it should loose // `@autoclosure` flag, because in context it's used // as a function type represented by autoclosure. @@ -9963,7 +9975,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::AllowKeyPathRootTypeMismatch: case FixKind::UnwrapOptionalBaseKeyPathApplication: case FixKind::AllowCoercionToForceCast: - case FixKind::SpecifyKeyPathRootType: { + case FixKind::SpecifyKeyPathRootType: + case FixKind::SpecifyLabelToAssociateTrailingClosure: { return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; } diff --git a/test/expr/postfix/call/forward_trailing_closure_ambiguity.swift b/test/expr/postfix/call/forward_trailing_closure_ambiguity.swift index 8fb0c6d9a98d8..72e13672ace16 100644 --- a/test/expr/postfix/call/forward_trailing_closure_ambiguity.swift +++ b/test/expr/postfix/call/forward_trailing_closure_ambiguity.swift @@ -92,3 +92,33 @@ func notAmbiguous3( func testNotAmbiguous3() { notAmbiguous3 { $0 } } + +// Ambiguous subscript +struct S { + subscript( // expected-note {{'subscript(a:_:_:)' declared here}} + a a: Int, + fn1: (() -> Void)? = nil, + fn2: (() -> Void)? = nil) -> Bool { + get { return true } + } + + subscript( // expected-note {{'subscript(b:_:fn2:)' declared here}} + b b: Int, + fn1: (() -> Void)? = nil, + fn2 fn2: (() -> Void)? = nil) -> Bool { + get { return true } + } + + static func foo( // expected-note {{'foo(c:fn1:fn2:)' declared here}} + c: Int, + fn1: (() -> Void)? = nil, + fn2: (() -> Void)? = nil) -> S { + return S() + } +} + +func test_ambiguous_subscript_unresolved_member(s: S) { + _ = s[a: 42] {} // expected-warning {{backward matching of the unlabeled trailing closure is deprecated; label the argument with '_' to suppress this warning}} {{14-15=, }} {{18-18=]}} + _ = s[b: 42] {} // expected-warning {{backward matching of the unlabeled trailing closure is deprecated; label the argument with 'fn2' to suppress this warning}} {{14-15=, fn2: }} {{18-18=]}} + let _: S = .foo(c: 42) {} // expected-warning {{backward matching of the unlabeled trailing closure is deprecated; label the argument with 'fn2' to suppress this warning}} {{24-25=, fn2: }} {{28-28=)}} +} From 00b22bf412203f901764e756b21681ac6223306e Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 7 Aug 2020 11:51:05 -0700 Subject: [PATCH 064/123] [CSApply] NFC: Remove logic replaced by `TrailingClosureRequiresExplicitLabel` diagnostic --- lib/Sema/CSApply.cpp | 125 ------------------------------------------- 1 file changed, 125 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index dbdd3217b3e72..4c444634e29bd 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5462,124 +5462,6 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee, return false; } -/// Attach a Fix-It to the given diagnostic to give the trailing closure -/// argument a label. -static void labelTrailingClosureArgument( - ASTContext &ctx, Expr *fn, Expr *arg, Identifier paramName, - Expr *trailingClosure, InFlightDiagnostic &diag) { - // Dig out source locations. - SourceLoc existingRParenLoc; - SourceLoc leadingCommaLoc; - if (auto tupleExpr = dyn_cast(arg)) { - existingRParenLoc = tupleExpr->getRParenLoc(); - assert(tupleExpr->getNumElements() >= 2 && "Should be a ParenExpr?"); - leadingCommaLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, - tupleExpr->getElements()[tupleExpr->getNumElements()-2]->getEndLoc()); - } else { - auto parenExpr = cast(arg); - existingRParenLoc = parenExpr->getRParenLoc(); - } - - // Figure out the text to be inserted before the trailing closure. - SmallString<16> insertionText; - SourceLoc insertionLoc; - if (leadingCommaLoc.isValid()) { - insertionText += ", "; - assert(existingRParenLoc.isValid()); - insertionLoc = leadingCommaLoc; - } else if (existingRParenLoc.isInvalid()) { - insertionText += "("; - insertionLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, fn->getEndLoc()); - } else { - insertionLoc = existingRParenLoc; - } - - // Add the label, if there is one. - if (!paramName.empty()) { - insertionText += paramName.str(); - insertionText += ": "; - } - - // If there is an existing right parentheses, remove it while we - // insert the new text. - if (existingRParenLoc.isValid()) { - SourceLoc afterExistingRParenLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, existingRParenLoc); - diag.fixItReplaceChars( - insertionLoc, afterExistingRParenLoc, insertionText); - } else { - // Insert the appropriate prefix. - diag.fixItInsert(insertionLoc, insertionText); - } - - // Insert a right parenthesis after the closing '}' of the trailing closure; - SourceLoc newRParenLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, trailingClosure->getEndLoc()); - diag.fixItInsert(newRParenLoc, ")"); -} - -/// Find the trailing closure argument of a tuple or parenthesized expression. -/// -/// Due to a quirk of the backward scan that could allow reordering of -/// arguments in the presence of a trailing closure, it might not be the last -/// argument in the tuple. -static Expr *findTrailingClosureArgument(Expr *arg) { - if (auto parenExpr = dyn_cast(arg)) { - return parenExpr->getSubExpr(); - } - - auto tupleExpr = cast(arg); - SourceLoc endLoc = tupleExpr->getEndLoc(); - for (Expr *elt : llvm::reverse(tupleExpr->getElements())) { - if (elt->getEndLoc() == endLoc) - return elt; - } - - return tupleExpr->getElements().back(); -} - -/// Find the index of the parameter that binds the given argument. -static unsigned findParamBindingArgument( - ArrayRef parameterBindings, unsigned argIndex) { - for (unsigned paramIdx : indices(parameterBindings)) { - if (llvm::find(parameterBindings[paramIdx], argIndex) - != parameterBindings[paramIdx].end()) - return paramIdx; - } - - llvm_unreachable("No parameter binds the argument?"); -} - -/// Warn about the use of the deprecated "backward" scan for matching the -/// unlabeled trailing closure. It was needed to properly type check, but -/// this code will break with a future version of Swift. -static void warnAboutTrailingClosureBackwardScan( - ConcreteDeclRef callee, Expr *fn, Expr *arg, - ArrayRef params, - Optional unlabeledTrailingClosureIndex, - ArrayRef parameterBindings) { - - Expr *trailingClosure = findTrailingClosureArgument(arg); - unsigned paramIdx = findParamBindingArgument( - parameterBindings, *unlabeledTrailingClosureIndex); - ASTContext &ctx = params[paramIdx].getPlainType()->getASTContext(); - Identifier paramName = params[paramIdx].getLabel(); - - { - auto diag = ctx.Diags.diagnose( - trailingClosure->getStartLoc(), - diag::unlabeled_trailing_closure_deprecated, paramName); - labelTrailingClosureArgument( - ctx, fn, arg, paramName, trailingClosure, diag); - } - - if (auto decl = callee.getDecl()) { - ctx.Diags.diagnose(decl, diag::decl_declared_here, decl->getName()); - } -} - Expr *ExprRewriter::coerceCallArguments( Expr *arg, AnyFunctionType *funcType, ConcreteDeclRef callee, @@ -5671,13 +5553,6 @@ Expr *ExprRewriter::coerceCallArguments( // FIXME: Eventually, we want to enforce that we have either argTuple or // argParen here. - // Warn about the backward scan being deprecated. - if (trailingClosureMatching == TrailingClosureMatching::Backward) { - warnAboutTrailingClosureBackwardScan( - callee, apply ? apply->getFn() : nullptr, arg, params, - unlabeledTrailingClosureIndex, parameterBindings); - } - SourceLoc lParenLoc, rParenLoc; if (argTuple) { lParenLoc = argTuple->getLParenLoc(); From d8b6bafa6daac341832d014383b2976e070bce19 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 7 Aug 2020 14:59:36 -0400 Subject: [PATCH 065/123] Temporarily disable failing test --- test/attr/attr_availability_canonical_macos_version.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/test/attr/attr_availability_canonical_macos_version.swift b/test/attr/attr_availability_canonical_macos_version.swift index 10cf92286e255..c51ee164f24dd 100644 --- a/test/attr/attr_availability_canonical_macos_version.swift +++ b/test/attr/attr_availability_canonical_macos_version.swift @@ -1,4 +1,5 @@ // RUN: %swift -typecheck -verify -parse-stdlib -module-name Swift -target x86_64-apple-macosx11.0 %s +// REQUIRES: rdar66693249 @available(OSX, introduced: 10.5, deprecated: 10.8, obsoleted: 11.0, From bc449e35be3a2f08a2a1bc0a20132481c6164f16 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 7 Aug 2020 15:02:24 -0400 Subject: [PATCH 066/123] Revert "Temporarily disable failing test" --- test/attr/attr_availability_canonical_macos_version.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/test/attr/attr_availability_canonical_macos_version.swift b/test/attr/attr_availability_canonical_macos_version.swift index c51ee164f24dd..10cf92286e255 100644 --- a/test/attr/attr_availability_canonical_macos_version.swift +++ b/test/attr/attr_availability_canonical_macos_version.swift @@ -1,5 +1,4 @@ // RUN: %swift -typecheck -verify -parse-stdlib -module-name Swift -target x86_64-apple-macosx11.0 %s -// REQUIRES: rdar66693249 @available(OSX, introduced: 10.5, deprecated: 10.8, obsoleted: 11.0, From d6f19d2f22aa2d4a1c9d66cf1624ddbf290747eb Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 7 Aug 2020 15:03:25 -0400 Subject: [PATCH 067/123] Temporarily disable failing test --- test/IRGen/jit-debugging.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/IRGen/jit-debugging.swift b/test/IRGen/jit-debugging.swift index 78d59fa93fbf9..6a8a8a5243ee7 100644 --- a/test/IRGen/jit-debugging.swift +++ b/test/IRGen/jit-debugging.swift @@ -12,4 +12,6 @@ // RUN: %llvm-nm --defined-only --extern-only %t/main-jitted-objectbuffer.o | %FileCheck -check-prefix CHECK-OBJ %s // CHECK-OBJ: T {{_?}}main +// REQUIRES: rdar66644853 + let zero = 0 From 06c975cff4862bbba3ea1b1b19b9dd95da49d8d1 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Fri, 7 Aug 2020 12:40:11 -0700 Subject: [PATCH 068/123] Remove code sign from stdlib/Error.swift --- test/stdlib/Error.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/test/stdlib/Error.swift b/test/stdlib/Error.swift index 898bdcef0cc57..e235d6d296b98 100644 --- a/test/stdlib/Error.swift +++ b/test/stdlib/Error.swift @@ -1,6 +1,5 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -o %t/Error -DPTR_SIZE_%target-ptrsize -module-name main %/s -// RUN: %target-codesign %t/Error // RUN: %target-run %t/Error // REQUIRES: executable_test From 6d4706162233ac5ec89eaa4920e8adf3d2d33e94 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Fri, 7 Aug 2020 13:13:36 -0700 Subject: [PATCH 069/123] [AutoDiff] NFC: fix typo. (#33361) --- lib/SILOptimizer/Differentiation/PullbackCloner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index 0438285ed07aa..a30de6d5f71ea 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -2657,7 +2657,7 @@ void PullbackCloner::Implementation::accumulateIndirect(SILValue resultAddress, CanMetatypeType::get(adjointASTTy, MetatypeRepresentation::Thick); auto metatypeSILType = SILType::getPrimitiveObjectType(metatypeType); auto metatype = builder.createMetatype(loc, metatypeSILType); - // %2 = apply $0(%result, %new, %old, %1) + // %2 = apply %0(%result, %new, %old, %1) builder.createApply(loc, witnessMethod, subMap, {resultAddress, rhsAddress, lhsAddress, metatype}, /*isNonThrowing*/ false); From 3ae31d5173053e76764ac386150cd4dd2276219c Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 7 Aug 2020 16:02:56 -0400 Subject: [PATCH 070/123] Sema: Don't need to derive CaseIterable's AllCases associated type Just declaring a default in the standard library works fine. --- lib/Sema/DerivedConformanceCaseIterable.cpp | 24 --------------------- lib/Sema/DerivedConformances.h | 6 ------ lib/Sema/TypeCheckProtocol.cpp | 2 -- stdlib/public/core/CompilerProtocols.swift | 2 +- test/IDE/complete_override.swift | 3 +-- 5 files changed, 2 insertions(+), 35 deletions(-) diff --git a/lib/Sema/DerivedConformanceCaseIterable.cpp b/lib/Sema/DerivedConformanceCaseIterable.cpp index bc809b4e53930..14d3309936918 100644 --- a/lib/Sema/DerivedConformanceCaseIterable.cpp +++ b/lib/Sema/DerivedConformanceCaseIterable.cpp @@ -69,15 +69,6 @@ static ArraySliceType *computeAllCasesType(NominalTypeDecl *enumDecl) { return ArraySliceType::get(enumType); } -static Type deriveCaseIterable_AllCases(DerivedConformance &derived) { - // enum SomeEnum : CaseIterable { - // @derived - // typealias AllCases = [SomeEnum] - // } - auto *rawInterfaceType = computeAllCasesType(cast(derived.Nominal)); - return derived.getConformanceContext()->mapTypeIntoContext(rawInterfaceType); -} - ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { // Conformance can't be synthesized in an extension. if (checkAndDiagnoseDisallowedContext(requirement)) @@ -111,18 +102,3 @@ ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { return propDecl; } - -Type DerivedConformance::deriveCaseIterable(AssociatedTypeDecl *assocType) { - // Check that we can actually derive CaseIterable for this type. - if (!canDeriveConformance(Nominal)) - return nullptr; - - if (assocType->getName() == Context.Id_AllCases) { - return deriveCaseIterable_AllCases(*this); - } - - Context.Diags.diagnose(assocType->getLoc(), - diag::broken_case_iterable_requirement); - return nullptr; -} - diff --git a/lib/Sema/DerivedConformances.h b/lib/Sema/DerivedConformances.h index c5dba4bb20172..3465402b7a9d6 100644 --- a/lib/Sema/DerivedConformances.h +++ b/lib/Sema/DerivedConformances.h @@ -163,12 +163,6 @@ class DerivedConformance { /// \returns the derived member, which will also be added to the type. ValueDecl *deriveCaseIterable(ValueDecl *requirement); - /// Derive a CaseIterable type witness for an enum if it has no associated - /// values for any of its cases. - /// - /// \returns the derived member, which will also be added to the type. - Type deriveCaseIterable(AssociatedTypeDecl *assocType); - /// Determine if a RawRepresentable requirement can be derived for a type. /// /// This is implemented for non-empty enums without associated values, diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 7743f1d336f20..e68a7b2d095fa 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -5691,8 +5691,6 @@ TypeChecker::deriveTypeWitness(DeclContext *DC, switch (*knownKind) { case KnownProtocolKind::RawRepresentable: return std::make_pair(derived.deriveRawRepresentable(AssocType), nullptr); - case KnownProtocolKind::CaseIterable: - return std::make_pair(derived.deriveCaseIterable(AssocType), nullptr); case KnownProtocolKind::Differentiable: return derived.deriveDifferentiable(AssocType); default: diff --git a/stdlib/public/core/CompilerProtocols.swift b/stdlib/public/core/CompilerProtocols.swift index ca92b3d2b94cb..784fee1d14507 100644 --- a/stdlib/public/core/CompilerProtocols.swift +++ b/stdlib/public/core/CompilerProtocols.swift @@ -249,7 +249,7 @@ extension RawRepresentable where RawValue: Hashable, Self: Hashable { /// demonstrates this automatic implementation. public protocol CaseIterable { /// A type that can represent a collection of all values of this type. - associatedtype AllCases: Collection + associatedtype AllCases: Collection = [Self] where AllCases.Element == Self /// A collection of all values of this type. diff --git a/test/IDE/complete_override.swift b/test/IDE/complete_override.swift index 4213dfa1df6ee..7f186a8aafaa6 100644 --- a/test/IDE/complete_override.swift +++ b/test/IDE/complete_override.swift @@ -896,11 +896,10 @@ struct SynthesizedConformance3: Hashable { enum SynthesizedConformance4: CaseIterable { case a, b, c, d #^OVERRIDE_SYNTHESIZED_4^# -// OVERRIDE_SYNTHESIZED_4: Begin completions, 4 items +// OVERRIDE_SYNTHESIZED_4: Begin completions, 3 items // OVERRIDE_SYNTHESIZED_4-DAG: Decl[InstanceVar]/Super/IsSystem: var hashValue: Int // OVERRIDE_SYNTHESIZED_4-DAG: Decl[InstanceMethod]/Super/IsSystem: func hash(into hasher: inout Hasher) {|}; // OVERRIDE_SYNTHESIZED_4-DAG: Decl[StaticVar]/Super/IsSystem: static var allCases: [SynthesizedConformance4]; -// OVERRIDE_SYNTHESIZED_4-DAG: Decl[AssociatedType]/Super/IsSystem: typealias AllCases = {#(Type)#}; } class SynthesizedConformance5: SynthesizedConformance2 { From 635550cd83684193793e74adddbdb79edbb11e38 Mon Sep 17 00:00:00 2001 From: Ashley Garland Date: Fri, 7 Aug 2020 13:50:22 -0700 Subject: [PATCH 071/123] [SymbolGraph] Check Loc validity before extracting text Hit this crash while walking an `import protocol ...` declaration. Check loc validity before calling `SourceManager::extractText`: there is an assertion at the beginning of this function. rdar://65258208 --- lib/IDE/SourceEntityWalker.cpp | 2 +- .../Something/Inputs/SomeProtocol.swift | 3 +++ test/SymbolGraph/Something/Something.swift | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 test/SymbolGraph/Something/Inputs/SomeProtocol.swift create mode 100644 test/SymbolGraph/Something/Something.swift diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp index a7a3f7d0ea4de..7dc78419542f3 100644 --- a/lib/IDE/SourceEntityWalker.cpp +++ b/lib/IDE/SourceEntityWalker.cpp @@ -684,7 +684,7 @@ bool SemaAnnotator:: passReference(ValueDecl *D, Type Ty, DeclNameLoc Loc, ReferenceMetaData Data) { SourceManager &SM = D->getASTContext().SourceMgr; SourceLoc BaseStart = Loc.getBaseNameLoc(), BaseEnd = BaseStart; - if (SM.extractText({BaseStart, 1}) == "`") + if (BaseStart.isValid() && SM.extractText({BaseStart, 1}) == "`") BaseEnd = Lexer::getLocForEndOfToken(SM, BaseStart.getAdvancedLoc(1)); return passReference(D, Ty, BaseStart, {BaseStart, BaseEnd}, Data); } diff --git a/test/SymbolGraph/Something/Inputs/SomeProtocol.swift b/test/SymbolGraph/Something/Inputs/SomeProtocol.swift new file mode 100644 index 0000000000000..e3a42fe70da44 --- /dev/null +++ b/test/SymbolGraph/Something/Inputs/SomeProtocol.swift @@ -0,0 +1,3 @@ +public protocol P { + func foo() +} diff --git a/test/SymbolGraph/Something/Something.swift b/test/SymbolGraph/Something/Something.swift new file mode 100644 index 0000000000000..a56bb3b2d5bce --- /dev/null +++ b/test/SymbolGraph/Something/Something.swift @@ -0,0 +1,15 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %S/Inputs/SomeProtocol.swift -module-name SomeProtocol -emit-module -emit-module-path %t/ +// RUN: %target-build-swift %s -module-name Something -emit-module -emit-module-path %t/ -I %t +// RUN: %target-swift-symbolgraph-extract -module-name Something -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/Something.symbols.json + +import protocol SomeProtocol.P + +public struct MyStruct: P { + public func foo() {} +} + +// CHECK: "kind": "conformsTo", +// CHECK-NEXT: "source": "s:9Something8MyStructV", +// CHECK-NEXT: "target": "s:12SomeProtocol1PP", From a16aef2f47ccc80b56a086ead481d4adfa7b184a Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 7 Aug 2020 14:00:32 -0700 Subject: [PATCH 072/123] test: repair Interpreter/bridged_casts_folding on ASi ARM64 generates a `brk #0x1` for `unreachable` which generates a SIGTRAP. On x86, we would generate a `ud2` rather than `int 3` which are treated as `SIGILL` and `SIGTRAP` respectively. --- test/Interpreter/bridged_casts_folding.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Interpreter/bridged_casts_folding.swift b/test/Interpreter/bridged_casts_folding.swift index 31b5de2d61b3f..570a9b54e01da 100644 --- a/test/Interpreter/bridged_casts_folding.swift +++ b/test/Interpreter/bridged_casts_folding.swift @@ -57,7 +57,7 @@ Tests.test("NSString => Array. Crashing test case") { // CHECK: [ OK ] BridgedCastFolding.NSString => Array. Crashing test case // CHECK-OPT-LABEL: [ RUN ] BridgedCastFolding.NSString => Array. Crashing test case - // CHECK-OPT: stderr>>> OK: saw expected "crashed: sigill" + // CHECK-OPT: stderr>>> OK: saw expected "crashed: sig{{ill|trap}}" // CHECK-OPT: [ OK ] BridgedCastFolding.NSString => Array. Crashing test case expectCrashLater() do { @@ -129,7 +129,7 @@ Tests.test("NSNumber (Int) -> String. Crashing test.") { // CHECK: [ OK ] BridgedCastFolding.NSNumber (Int) -> String. Crashing test. // CHECK-OPT-LABEL: [ RUN ] BridgedCastFolding.NSNumber (Int) -> String. Crashing test. - // CHECK-OPT: stderr>>> OK: saw expected "crashed: sigill" + // CHECK-OPT: stderr>>> OK: saw expected "crashed: sig{{ill|trap}}" // CHECK-OPT: [ OK ] BridgedCastFolding.NSNumber (Int) -> String. Crashing test. expectCrashLater() do { @@ -392,7 +392,7 @@ Tests.test("String -> NSNumber. Crashing Test Case") { // CHECK: [ OK ] BridgedCastFolding.String -> NSNumber. Crashing Test Case // CHECK-OPT-LABEL: [ RUN ] BridgedCastFolding.String -> NSNumber. Crashing Test Case - // CHECK-OPT: stderr>>> OK: saw expected "crashed: sigill" + // CHECK-OPT: stderr>>> OK: saw expected "crashed: sig{{ill|trap}}" // CHECK-OPT: [ OK ] BridgedCastFolding.String -> NSNumber. Crashing Test Case expectCrashLater() do { From 88e13060ab4b28900f205a8bd2310fd9246d8b91 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 7 Aug 2020 14:27:45 -0700 Subject: [PATCH 073/123] test: repair Interpreter/SDK/interpreter_with_options on ASi Remove the target specific binary and instead compile a test binary on the fly. Because this test is restricted to macOS platforms, we know that we assume that we will have a compatible Objective-C runtime at our disposal. Use that to create a stub library for testing `NSClassFromString`. This allows this test to execute on ARM64. --- test/Interpreter/SDK/Inputs/libTestLoad.dylib | Bin 8688 -> 0 bytes .../Interpreter/SDK/interpret_with_options.swift | 11 +++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) delete mode 100755 test/Interpreter/SDK/Inputs/libTestLoad.dylib diff --git a/test/Interpreter/SDK/Inputs/libTestLoad.dylib b/test/Interpreter/SDK/Inputs/libTestLoad.dylib deleted file mode 100755 index d3d552658f1a387232acae2b9618987560ac51d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8688 zcmeHNJ8u&~5FRH1qL3&KG$178pa}7hd>|T1JGP@Zm^`qBB2g@7`%Es_K67^lOoN+9 z(7B@aAE2W}N@=BmKL8a44I*_4VCHVuUa#duqJ$l3vO7C7-|l?7mhNuz>FCF=GXRlE z062{rMctnQ*b9097t#KX%2*+@UBHeilpqVY5fe_KPH-P%zV*@{1gdyH=LbIOsWwbO zTaIANDejh7scL#&-K<&T@D_NIiYL}3FsaTr5vnttEF{G!wxYf#EwG zKMrr2#}hu~OCn|phB%&GGoM&?z2c~N(>z+>k*(GyVPkzEZ%*9{c0tB3oIX z3@7l)rf>4~4)fRLc$++n?BnogA68Kr%VpQ^Wzt!3=3*Rx;{mr1anDF-A9y#g=kV_> z)CPXj4;^9*+tiMTgHluKe`u=`_wa1 zj%%$r%{ra|+o{JZ!eczNTn|S)BdNq7{^f1TSs zv`KEFlAr8r*lN)XXa+O`ngPv#WplP~)~w@T>9K)(mI{Gy|Fe&46Y=GoTsJ3}^;4 z1DXNNz`w-6!Xh+cjYMPhL28TYI+tJ@%WEl?$|du8w#3%+8^v9#@0 zBLVH+Z!VEe=X`=+G+VWX-(n@Rv}3`C4o(mW@nHrgWSEf;6KOHQh$lM<-9@}a?%|bd zUyi=c(!U$fwWxf(OrJAI!YfeTna2xT@!f+k$QIuZ(r9B+KmL(oKM(Ex9B)Hg%mXnP p=5J*6q5Ig Date: Thu, 6 Aug 2020 14:39:16 -0700 Subject: [PATCH 074/123] test: repair stdlib/Dispatch on ASi The conversion of the naonseconds to Mach ticks in multiples of Mach timebase units alters the time. This would fail on ASi where mach ticks are not synonymous with nanoseconds. --- test/stdlib/Dispatch.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/stdlib/Dispatch.swift b/test/stdlib/Dispatch.swift index ee712560f306f..399cc90743606 100644 --- a/test/stdlib/Dispatch.swift +++ b/test/stdlib/Dispatch.swift @@ -278,7 +278,15 @@ DispatchAPI.test("DispatchTime.SchedulerTimeType.Stridable") { let time1 = DispatchQueue.SchedulerTimeType(.init(uptimeNanoseconds: 10000)) let time2 = DispatchQueue.SchedulerTimeType(.init(uptimeNanoseconds: 10431)) let addedTime = time2.distance(to: time1) - expectEqual((10000 - 10431), addedTime.magnitude) + // The magnitude of the time sum is in nanosecond units. Although + // the units match up, the internal representation of the + // DispatchTime may round up to multiples of Mach timebase. This + // requires the difference being converted, which is performed here + // by constructing a `DispatchTime` from the delta. However, the + // parameter is a `UInt64` which requires us to perform the negation + // manually. + expectEqual(-Int(DispatchTime(uptimeNanoseconds: 10431 - 10000).uptimeNanoseconds), + addedTime.magnitude) } } From 155e20c1ac3870b70fa142ad2ccb46e090248f66 Mon Sep 17 00:00:00 2001 From: Suyash Srijan Date: Fri, 7 Aug 2020 23:04:46 +0100 Subject: [PATCH 075/123] [Test] Add Interpreter and IRGen tests for SR-13203 (#33340) --- ...runtime_name_local_class_opaque_type.swift | 19 +++++++++++++++ ...runtime_name_local_class_opaque_type.swift | 24 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 test/IRGen/objc_runtime_name_local_class_opaque_type.swift create mode 100644 test/Interpreter/runtime_name_local_class_opaque_type.swift diff --git a/test/IRGen/objc_runtime_name_local_class_opaque_type.swift b/test/IRGen/objc_runtime_name_local_class_opaque_type.swift new file mode 100644 index 0000000000000..deef2463abef2 --- /dev/null +++ b/test/IRGen/objc_runtime_name_local_class_opaque_type.swift @@ -0,0 +1,19 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend %s -disable-availability-checking -emit-ir | %FileCheck %s + +// REQUIRES: objc_interop + +protocol MyProtocol {} + +func returnsClass1() -> some MyProtocol { + class MyClass1: MyProtocol {} + return MyClass1() +} + +var returnsClass2: some MyProtocol { + class MyClass2: MyProtocol {} + return MyClass2() +} + +// CHECK: @_DATA__TtCF41objc_runtime_name_local_class_opaque_type13returnsClass1FT_QuL_8MyClass1 = internal constant +// CHECK: @_DATA__TtCF41objc_runtime_name_local_class_opaque_typeg13returnsClass2QuL_8MyClass2 = internal constant diff --git a/test/Interpreter/runtime_name_local_class_opaque_type.swift b/test/Interpreter/runtime_name_local_class_opaque_type.swift new file mode 100644 index 0000000000000..1b325fc10664b --- /dev/null +++ b/test/Interpreter/runtime_name_local_class_opaque_type.swift @@ -0,0 +1,24 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -Xfrontend -disable-availability-checking %s -o %t/a.out +// RUN: %target-run %t/a.out | %FileCheck %s + +// REQUIRES: executable_test +// REQUIRES: objc_interop + +protocol MyProtocol {} + +func returnsClass1() -> some MyProtocol { + class MyClass1: MyProtocol {} + return MyClass1() +} + +var returnsClass2: some MyProtocol { + class MyClass2: MyProtocol {} + return MyClass2() +} + +print(returnsClass1()) +// CHECK: a.(unknown context at ${{[0-9a-z]+}}).(unknown context at ${{[0-9a-z]+}}).MyClass1 + +print(returnsClass2) +// CHECK: a.(unknown context at ${{[0-9a-z]+}}).(unknown context at ${{[0-9a-z]+}}).MyClass2 From ab4cdc12dc95e8b51128bd8098e8aed71ac07c54 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Fri, 7 Aug 2020 15:42:24 -0700 Subject: [PATCH 076/123] [Docs] [AutoDiff] Improve wording in various places in the manifesto. --- docs/DifferentiableProgramming.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/DifferentiableProgramming.md b/docs/DifferentiableProgramming.md index 0e1196f138cca..26d2e99fca2fb 100644 --- a/docs/DifferentiableProgramming.md +++ b/docs/DifferentiableProgramming.md @@ -893,8 +893,15 @@ extension Perceptron { ### `@differentiable` function types -A subtype of normal function types with a different runtime representation, -which stores metadata that allows their values to be differentiated anywhere. +Differentiable functions are first-class values, identified by a +`@differentiable` attribute in the function type. A `@differentiable` function +type is a subtype of its corresponding normal function type (i.e. without a +`@differentiable` attribute) with an extended ABI, which stores metadata that +allows their values to be differentiated anywhere the function is passed. A +`@differentiable(linear)` function type is a subtype of its corresponding +`@differentiable` function type. A normal function can be implicitly converted +to a `@differentiable` or `@differentiable(linear)` function with appropriate +compile-time checks. ```swift func addOne(_ x: Float) -> Float { x + 1 } @@ -920,8 +927,9 @@ func _(_ x: Float) -> (value: Float, ### Differential operators -Standard library differentiation APIs that take `@differentiable` functions and -return derivative functions or compute derivative values. +Differential operators are APIs defined in the standard library that take +`@differentiable` functions and return derivative functions or compute +derivative values. ```swift // In the standard library: @@ -2318,7 +2326,7 @@ As shown in the subsection, a `@differentiable` function value's runtime representation contains the original function along with extra information that allows the function to be differentiated (or transposed, if it is `@differentiable(linear)`). A -@differentiable or `@differentiable(linear)` function value can be called like a +`@differentiable` or `@differentiable(linear)` function value can be called like a non-`@differentiable` function. A `@differentiable(linear)` function value can be implicitly converted to a `@differentiable` one, which can be implicitly converted to a non-`@differentiable` one. From 473f55ced8009d988e9e0d146dff8e0f3c1b0171 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Fri, 7 Aug 2020 15:53:45 -0700 Subject: [PATCH 077/123] Remove codesign from test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift --- test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift b/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift index e3680337eab73..8853000397703 100644 --- a/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift +++ b/test/Interpreter/SDK/objc_swift3_deprecated_objc_inference.swift @@ -1,6 +1,5 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -swift-version 4 -Xfrontend -enable-swift3-objc-inference %s -o %t/a.out -// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out 2>&1 | %FileCheck %s -check-prefix=CHECK_WARNINGS // RUN: env %env-SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT=0 %target-run %t/a.out 2>&1 | %FileCheck %s -check-prefix=CHECK_NOTHING From d172129237282ce557e102076c5ddba5d0703f0f Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Mon, 3 Aug 2020 11:39:13 -0700 Subject: [PATCH 078/123] Improve @guaranteed args handling in ARCSequenceOpts @guaranteed args are treated conservatively in ARCSequenceOpts. A function call with a @guaranteed arg is assumed to decrement refcount of the @guaranteed arg. With this change, use swift::mayDecrementRefCount which uses EscapeAnalysis to determine if we need to transition conservatively at the instruction being visited. --- lib/SILOptimizer/ARC/RefCountState.cpp | 15 ++++++++ test/SILOptimizer/arcsequenceopts.sil | 47 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp index eabe4d5ed7958..e0c43fed19040 100644 --- a/lib/SILOptimizer/ARC/RefCountState.cpp +++ b/lib/SILOptimizer/ARC/RefCountState.cpp @@ -365,6 +365,14 @@ bool BottomUpRefCountState::handlePotentialGuaranteedUser( if (!mayGuaranteedUseValue(PotentialGuaranteedUser, getRCRoot(), AA)) return false; + // If we can prove that the pointer we are tracking cannot be decremented, + // return. On return, BottomUpRefCountState::handlePotentialUser can correctly + // handle transition of refcount state. It transitions from a Decrement + // refcount state to a MighBeUsed refcount state + if (!mayDecrementRefCount(PotentialGuaranteedUser, getRCRoot(), AA)) { + return false; + } + // Instructions that we do not recognize (and thus will not move) and that // *must* use RCIdentity, implies we are always known safe as long as meet // over all path constraints are satisfied. @@ -816,6 +824,13 @@ bool TopDownRefCountState::handlePotentialGuaranteedUser( if (!mayGuaranteedUseValue(PotentialGuaranteedUser, getRCRoot(), AA)) return false; + // If we can prove that the pointer we are tracking cannot be decremented, + // return. On return, TopDownRefCountState::handlePotentialUser can correctly + // handle transition of refcount state. + if (!mayDecrementRefCount(PotentialGuaranteedUser, getRCRoot(), AA)) { + return false; + } + // Otherwise, update our step given that we have a potential decrement. return handleGuaranteedUser(PotentialGuaranteedUser, getRCRoot(), SetFactory, AA); diff --git a/test/SILOptimizer/arcsequenceopts.sil b/test/SILOptimizer/arcsequenceopts.sil index ea05c13ea896e..8825d9cbae7f0 100644 --- a/test/SILOptimizer/arcsequenceopts.sil +++ b/test/SILOptimizer/arcsequenceopts.sil @@ -395,6 +395,53 @@ bb0(%0 : $*Builtin.Int32): return %4: $() } +struct Int { + var value : Builtin.Int64 +} + +sil @guaranteed_call : $@convention(thin) (@guaranteed <Ï„_0_0> { var Ï„_0_0 } ) -> () { +bb0(%0 : $<Ï„_0_0> { var Ï„_0_0 } ): + %1 = tuple () + return %1 : $() +} + +// CHECK_LABEL: sil hidden [noinline] @$test_guaranteed_call : +// CHECK: bb1{{.*}}: +// CHECK-NOT: strong_retain +// CHECK: apply +// CHECK-NOT: strong_release +// CHECK: bb2: +// CHECK_LABEL: } // end sil function '$test_guaranteed_call' +sil hidden [noinline] @$test_guaranteed_call : $@convention(thin) () -> () { +bb0: + %box = alloc_box $<Ï„_0_0> { var Ï„_0_0 } + %proj = project_box %box : $<Ï„_0_0> { var Ï„_0_0 } , 0 + %0 = integer_literal $Builtin.Int64, 1 + %1 = integer_literal $Builtin.Int64, 100 + %funcref = function_ref @guaranteed_call : $@convention(thin) (@guaranteed <Ï„_0_0> { var Ï„_0_0 } ) -> () + %3 = struct $Int (%0 : $Builtin.Int64) + %6 = integer_literal $Builtin.Int1, -1 + br bb1(%0 : $Builtin.Int64) + +bb1(%8 : $Builtin.Int64): + %9 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %0 : $Builtin.Int64, %6 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) + %10 = tuple_extract %9 : $(Builtin.Int64, Builtin.Int1), 0 + %11 = struct $Int (%10 : $Builtin.Int64) + %12 = builtin "cmp_eq_Int64"(%10 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1 + strong_retain %box : $<Ï„_0_0> { var Ï„_0_0 } + apply %funcref (%box) : $@convention(thin) (@guaranteed <Ï„_0_0> { var Ï„_0_0 } ) -> () + strong_release %box : $<Ï„_0_0> { var Ï„_0_0 } + cond_br %12, bb3, bb2 + +bb2: + br bb1(%10 : $Builtin.Int64) + +bb3: + strong_release %box : $<Ï„_0_0> { var Ï„_0_0 } + %17 = tuple () + return %17 : $() +} + // CHECK-LABEL: sil @silargument_retain_iterated : $@convention(thin) (@owned <Ï„_0_0> { var Ï„_0_0 } ) -> () // CHECK: bb0 // CHECK-NEXT: function_ref user From ccca08b7f7ff0d3a3fc681d3f7f93fb7cd5abc6b Mon Sep 17 00:00:00 2001 From: Alex Efremov Date: Sat, 8 Aug 2020 02:56:15 +0200 Subject: [PATCH 079/123] [AutoDiff] Add reverse-mode `switch_enum` support for `Optional`. (#33218) Pullback generation now supports `switch_enum` and `switch_enum_addr` instructions for `Optional`-typed operands. Currently, the logic is special-cased to `Optional`, but may be generalized in the future to support enums following general rules. --- .../Differentiation/PullbackCloner.cpp | 219 +++++++++++- .../SILOptimizer/activity_analysis.swift | 4 +- .../differentiation_diagnostics.swift | 2 +- test/AutoDiff/validation-test/optional.swift | 319 ++++++++++++++++++ 4 files changed, 524 insertions(+), 20 deletions(-) create mode 100644 test/AutoDiff/validation-test/optional.swift diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index a30de6d5f71ea..79611c38eaaf4 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -650,6 +650,19 @@ class PullbackCloner::Implementation final return alloc; } + //--------------------------------------------------------------------------// + // Optional differentiation + //--------------------------------------------------------------------------// + + /// Given a `wrappedAdjoint` value of type `T.TangentVector`, creates an + /// `Optional.TangentVector` value from it and adds it to the adjoint value + /// of `optionalValue`. + /// + /// `wrappedAdjoint` may be an object or address value, both cases are + /// handled. + void accumulateAdjointForOptional(SILBasicBlock *bb, SILValue optionalValue, + SILValue wrappedAdjoint); + //--------------------------------------------------------------------------// // Array literal initialization differentiation //--------------------------------------------------------------------------// @@ -1503,6 +1516,30 @@ class PullbackCloner::Implementation final } } + /// Handle `unchecked_take_enum_data_addr` instruction. + /// Currently, only `Optional`-typed operands are supported. + /// Original: y = unchecked_take_enum_data_addr x : $*Enum, #Enum.Case + /// Adjoint: adj[x] += $Enum.TangentVector(adj[y]) + void + visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *utedai) { + auto *bb = utedai->getParent(); + auto adjBuf = getAdjointBuffer(bb, utedai); + auto enumTy = utedai->getOperand()->getType(); + auto *optionalEnumDecl = getASTContext().getOptionalDecl(); + // Only `Optional`-typed operands are supported for now. Diagnose all other + // enum operand types. + if (enumTy.getASTType().getEnumOrBoundGenericEnum() != optionalEnumDecl) { + LLVM_DEBUG(getADDebugStream() + << "Unhandled instruction in PullbackCloner: " << *utedai); + getContext().emitNondifferentiabilityError( + utedai, getInvoker(), + diag::autodiff_expression_not_differentiable_note); + errorOccurred = true; + return; + } + accumulateAdjointForOptional(bb, utedai->getOperand(), adjBuf); + } + #define NOT_DIFFERENTIABLE(INST, DIAG) void visit##INST##Inst(INST##Inst *inst); #undef NOT_DIFFERENTIABLE @@ -1639,11 +1676,16 @@ bool PullbackCloner::Implementation::run() { // Diagnose active enum values. Differentiation of enum values requires // special adjoint value handling and is not yet supported. Diagnose // only the first active enum value to prevent too many diagnostics. - if (type.getEnumOrBoundGenericEnum()) { - getContext().emitNondifferentiabilityError( - v, getInvoker(), diag::autodiff_enums_unsupported); - errorOccurred = true; - return true; + // + // Do not diagnose `Optional`-typed values, which will have special-case + // differentiation support. + if (auto *enumDecl = type.getEnumOrBoundGenericEnum()) { + if (enumDecl != getContext().getASTContext().getOptionalDecl()) { + getContext().emitNondifferentiabilityError( + v, getInvoker(), diag::autodiff_enums_unsupported); + errorOccurred = true; + return true; + } } // Diagnose unsupported stored property projections. if (auto *inst = dyn_cast(v)) { @@ -1972,6 +2014,103 @@ void PullbackCloner::Implementation::emitZeroDerivativesForNonvariedResult( << pullback); } +void PullbackCloner::Implementation::accumulateAdjointForOptional( + SILBasicBlock *bb, SILValue optionalValue, SILValue wrappedAdjoint) { + auto pbLoc = getPullback().getLocation(); + // Handle `switch_enum` on `Optional`. + auto *optionalEnumDecl = getASTContext().getOptionalDecl(); + auto optionalTy = optionalValue->getType(); + assert(optionalTy.getASTType().getEnumOrBoundGenericEnum() == + optionalEnumDecl); + // `Optional` + optionalTy = remapType(optionalTy); + // `T` + auto wrappedType = optionalTy.getOptionalObjectType(); + // `T.TangentVector` + auto wrappedTanType = remapType(wrappedAdjoint->getType()); + // `Optional` + auto optionalOfWrappedTanType = SILType::getOptionalType(wrappedTanType); + // `Optional.TangentVector` + auto optionalTanTy = getRemappedTangentType(optionalTy); + auto *optionalTanDecl = optionalTanTy.getNominalOrBoundGenericNominal(); + // Look up the `Optional.TangentVector.init` declaration. + auto initLookup = + optionalTanDecl->lookupDirect(DeclBaseName::createConstructor()); + ConstructorDecl *constructorDecl = nullptr; + for (auto *candidate : initLookup) { + auto candidateModule = candidate->getModuleContext(); + if (candidateModule->getName() == + builder.getASTContext().Id_Differentiation || + candidateModule->isStdlibModule()) { + assert(!constructorDecl && "Multiple `Optional.TangentVector.init`s"); + constructorDecl = cast(candidate); +#ifdef NDEBUG + break; +#endif + } + } + assert(constructorDecl && "No `Optional.TangentVector.init`"); + + // Allocate a local buffer for the `Optional` adjoint value. + auto *optTanAdjBuf = builder.createAllocStack(pbLoc, optionalTanTy); + // Find `Optional.some` EnumElementDecl. + auto someEltDecl = builder.getASTContext().getOptionalSomeDecl(); + + // Initialize a `Optional` buffer from `wrappedAdjoint`as the + // input for `Optional.TangentVector.init`. + auto *optArgBuf = builder.createAllocStack(pbLoc, optionalOfWrappedTanType); + if (optionalOfWrappedTanType.isLoadableOrOpaque(builder.getFunction())) { + // %enum = enum $Optional, #Optional.some!enumelt, + // %wrappedAdjoint : $T + auto *enumInst = builder.createEnum(pbLoc, wrappedAdjoint, someEltDecl, + optionalOfWrappedTanType); + // store %enum to %optArgBuf + builder.emitStoreValueOperation(pbLoc, enumInst, optArgBuf, + StoreOwnershipQualifier::Trivial); + } else { + // %enumAddr = init_enum_data_addr %optArgBuf $Optional, + // #Optional.some!enumelt + auto *enumAddr = builder.createInitEnumDataAddr( + pbLoc, optArgBuf, someEltDecl, wrappedTanType.getAddressType()); + // copy_addr %wrappedAdjoint to [initialization] %enumAddr + builder.createCopyAddr(pbLoc, wrappedAdjoint, enumAddr, IsNotTake, + IsInitialization); + // inject_enum_addr %optArgBuf : $*Optional, + // #Optional.some!enumelt + builder.createInjectEnumAddr(pbLoc, optArgBuf, someEltDecl); + } + + // Apply `Optional.TangentVector.init`. + SILOptFunctionBuilder fb(getContext().getTransform()); + // %init_fn = function_ref @Optional.TangentVector.init + auto *initFn = fb.getOrCreateFunction(pbLoc, SILDeclRef(constructorDecl), + NotForDefinition); + auto *initFnRef = builder.createFunctionRef(pbLoc, initFn); + auto *diffProto = + builder.getASTContext().getProtocol(KnownProtocolKind::Differentiable); + auto *swiftModule = getModule().getSwiftModule(); + auto diffConf = + swiftModule->lookupConformance(wrappedType.getASTType(), diffProto); + assert(!diffConf.isInvalid() && "Missing conformance to `Differentiable`"); + auto subMap = SubstitutionMap::get( + initFn->getLoweredFunctionType()->getSubstGenericSignature(), + ArrayRef(wrappedType.getASTType()), {diffConf}); + // %metatype = metatype $Optional.TangentVector.Type + auto metatypeType = CanMetatypeType::get(optionalTanTy.getASTType(), + MetatypeRepresentation::Thin); + auto metatypeSILType = SILType::getPrimitiveObjectType(metatypeType); + auto metatype = builder.createMetatype(pbLoc, metatypeSILType); + // apply %init_fn(%optTanAdjBuf, %optArgBuf, %metatype) + builder.createApply(pbLoc, initFnRef, subMap, + {optTanAdjBuf, optArgBuf, metatype}); + builder.createDeallocStack(pbLoc, optArgBuf); + + // Accumulate adjoint for the incoming `Optional` value. + addToAdjointBuffer(bb, optionalValue, optTanAdjBuf, pbLoc); + builder.emitDestroyAddr(pbLoc, optTanAdjBuf); + builder.createDeallocStack(pbLoc, optTanAdjBuf); +} + SILBasicBlock *PullbackCloner::Implementation::buildPullbackSuccessor( SILBasicBlock *origBB, SILBasicBlock *origPredBB, SmallDenseMap &pullbackTrampolineBlockMap) { @@ -2110,18 +2249,64 @@ void PullbackCloner::Implementation::visitSILBasicBlock(SILBasicBlock *bb) { // Get predecessor terminator operands. SmallVector, 4> incomingValues; bbArg->getSingleTerminatorOperands(incomingValues); - // Materialize adjoint value of active basic block argument, create a - // copy, and set copy as adjoint value of incoming values. - auto bbArgAdj = getAdjointValue(bb, bbArg); - auto concreteBBArgAdj = materializeAdjointDirect(bbArgAdj, pbLoc); - auto concreteBBArgAdjCopy = - builder.emitCopyValueOperation(pbLoc, concreteBBArgAdj); - for (auto pair : incomingValues) { - auto *predBB = std::get<0>(pair); - auto incomingValue = std::get<1>(pair); - blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); - setAdjointValue(predBB, incomingValue, - makeConcreteAdjointValue(concreteBBArgAdjCopy)); + + // Returns true if the given terminator instruction is a `switch_enum` on + // an `Optional`-typed value. `switch_enum` instructions require + // special-case adjoint value propagation for the operand. + auto isSwitchEnumInstOnOptional = + [&ctx = getASTContext()](TermInst *termInst) { + if (!termInst) + return false; + if (auto *sei = dyn_cast(termInst)) { + auto *optionalEnumDecl = ctx.getOptionalDecl(); + auto operandTy = sei->getOperand()->getType(); + return operandTy.getASTType().getEnumOrBoundGenericEnum() == + optionalEnumDecl; + } + return false; + }; + + // Check the tangent value category of the active basic block argument. + switch (getTangentValueCategory(bbArg)) { + // If argument has a loadable tangent value category: materialize adjoint + // value of the argument, create a copy, and set the copy as the adjoint + // value of incoming values. + case SILValueCategory::Object: { + auto bbArgAdj = getAdjointValue(bb, bbArg); + auto concreteBBArgAdj = materializeAdjointDirect(bbArgAdj, pbLoc); + auto concreteBBArgAdjCopy = + builder.emitCopyValueOperation(pbLoc, concreteBBArgAdj); + for (auto pair : incomingValues) { + auto *predBB = std::get<0>(pair); + auto incomingValue = std::get<1>(pair); + blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); + // Handle `switch_enum` on `Optional`. + auto termInst = bbArg->getSingleTerminator(); + if (isSwitchEnumInstOnOptional(termInst)) + accumulateAdjointForOptional(bb, incomingValue, concreteBBArgAdjCopy); + else + setAdjointValue(predBB, incomingValue, + makeConcreteAdjointValue(concreteBBArgAdjCopy)); + } + break; + } + // If argument has an address tangent value category: materialize adjoint + // value of the argument, create a copy, and set the copy as the adjoint + // value of incoming values. + case SILValueCategory::Address: { + auto bbArgAdjBuf = getAdjointBuffer(bb, bbArg); + for (auto pair : incomingValues) { + auto *predBB = std::get<0>(pair); + auto incomingValue = std::get<1>(pair); + // Handle `switch_enum` on `Optional`. + auto termInst = bbArg->getSingleTerminator(); + if (isSwitchEnumInstOnOptional(termInst)) + accumulateAdjointForOptional(bb, incomingValue, bbArgAdjBuf); + else + addToAdjointBuffer(predBB, incomingValue, bbArgAdjBuf, pbLoc); + } + break; + } } } diff --git a/test/AutoDiff/SILOptimizer/activity_analysis.swift b/test/AutoDiff/SILOptimizer/activity_analysis.swift index bb177b0d5bc97..fe8fd1a7785c1 100644 --- a/test/AutoDiff/SILOptimizer/activity_analysis.swift +++ b/test/AutoDiff/SILOptimizer/activity_analysis.swift @@ -200,7 +200,7 @@ func checked_cast_addr_nonactive_result(_ x: T) -> T { @differentiable // expected-note @+1 {{when differentiating this function definition}} func checked_cast_addr_active_result(x: T) -> T { - // expected-note @+1 {{differentiating enum values is not yet supported}} + // expected-note @+1 {{expression is not differentiable}} if let y = x as? Float { // Use `y: Float?` value in an active way. return y as! T @@ -744,8 +744,8 @@ func testClassModifyAccessor(_ c: inout C) { @differentiable // expected-note @+1 {{when differentiating this function definition}} func testActiveOptional(_ x: Float) -> Float { - // expected-note @+1 {{differentiating enum values is not yet supported}} var maybe: Float? = 10 + // expected-note @+1 {{expression is not differentiable}} maybe = x return maybe! } diff --git a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift index 13c23dcc656da..9473311a62247 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift @@ -157,8 +157,8 @@ class C: Differentiable { @differentiable // expected-note @+1 {{when differentiating this function definition}} func usesOptionals(_ x: Float) -> Float { - // expected-note @+1 {{differentiating enum values is not yet supported}} var maybe: Float? = 10 + // expected-note @+1 {{expression is not differentiable}} maybe = x return maybe! } diff --git a/test/AutoDiff/validation-test/optional.swift b/test/AutoDiff/validation-test/optional.swift new file mode 100644 index 0000000000000..c2fc0fac4a695 --- /dev/null +++ b/test/AutoDiff/validation-test/optional.swift @@ -0,0 +1,319 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import StdlibUnittest +import DifferentiationUnittest + +var OptionalTests = TestSuite("OptionalDifferentiation") + +//===----------------------------------------------------------------------===// +// Basic tests. +//===----------------------------------------------------------------------===// + +/* +// TODO(TF-433): operator `??` lowers to `try_apply` instead of `switch_enum`, +// which is not yet supported by differentiation. +@differentiable +func optional1(_ maybeX: Float?) -> Float { + return maybeX ?? 10 +} +*/ + +OptionalTests.test("Let") { + @differentiable + func optional_let(_ maybeX: Float?) -> Float { + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_let), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_let), .init(0.0)) + + @differentiable + func optional_let_tracked(_ maybeX: Tracked?) -> Tracked { + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_let_tracked), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_let_tracked), .init(0.0)) + + @differentiable + func optional_let_nested(_ nestedMaybeX: Float??) -> Float { + if let maybeX = nestedMaybeX { + if let x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_let_nested), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_let_nested), .init(.init(0.0))) + + @differentiable + func optional_let_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + if let maybeX = nestedMaybeX { + if let x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_let_nested_tracked), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_let_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_let_generic(_ maybeX: T?, _ defaultValue: T) -> T { + if let x = maybeX { + return x + } + return defaultValue + } + expectEqual(gradient(at: 10, 20, in: optional_let_generic), (.init(1.0), 0.0)) + expectEqual(gradient(at: nil, 20, in: optional_let_generic), (.init(0.0), 1.0)) + + expectEqual(gradient(at: Tracked.init(10), Tracked.init(20), in: optional_let_generic), (.init(1.0), 0.0)) + expectEqual(gradient(at: nil, Tracked.init(20), in: optional_let_generic), (.init(0.0), 1.0)) + + @differentiable + func optional_let_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + if let maybeX = nestedMaybeX { + if let x = maybeX { + return x + } + return defaultValue + } + return defaultValue + } + + expectEqual(gradient(at: 10.0, 20.0, in: optional_let_nested_generic), (.init(.init(1.0)), 0.0)) + expectEqual(gradient(at: nil, 20, in: optional_let_nested_generic), (.init(.init(0.0)), 1.0)) +} + +OptionalTests.test("Switch") { + @differentiable + func optional_switch(_ maybeX: Float?) -> Float { + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + expectEqual(gradient(at: 10, in: optional_switch), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_switch), .init(0.0)) + + @differentiable + func optional_switch_tracked(_ maybeX: Tracked?) -> Tracked { + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + expectEqual(gradient(at: 10, in: optional_switch_tracked), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_switch_tracked), .init(0.0)) + + @differentiable + func optional_switch_nested(_ nestedMaybeX: Float??) -> Float { + switch nestedMaybeX { + case nil: return 10 + case let .some(maybeX): + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + } + expectEqual(gradient(at: 10, in: optional_switch_nested), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_switch_nested), .init(.init(0.0))) + + @differentiable + func optional_switch_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + switch nestedMaybeX { + case nil: return 10 + case let .some(maybeX): + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + } + expectEqual(gradient(at: 10, in: optional_switch_nested_tracked), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_switch_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_switch_generic(_ maybeX: T?, _ defaultValue: T) -> T { + switch maybeX { + case nil: return defaultValue + case let .some(x): return x + } + } + expectEqual(gradient(at: 10, 20, in: optional_switch_generic), (.init(1.0), 0.0)) + expectEqual(gradient(at: nil, 20, in: optional_switch_generic), (.init(0.0), 1.0)) + + @differentiable + func optional_switch_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + switch nestedMaybeX { + case nil: return defaultValue + case let .some(maybeX): + switch maybeX { + case nil: return defaultValue + case let .some(x): return x + } + } + } + expectEqual(gradient(at: 10, 20, in: optional_switch_nested_generic), (.init(.init(1.0)), 0.0)) + expectEqual(gradient(at: nil, 20, in: optional_switch_nested_generic), (.init(.init(0.0)), 1.0)) +} + +OptionalTests.test("Var1") { + @differentiable + func optional_var1(_ maybeX: Float?) -> Float { + var maybeX = maybeX + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var1), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_var1), .init(0.0)) + + @differentiable + func optional_var1_tracked(_ maybeX: Tracked?) -> Tracked { + var maybeX = maybeX + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var1_tracked), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_var1_tracked), .init(0.0)) + + @differentiable + func optional_var1_nested(_ nestedMaybeX: Float??) -> Float { + var nestedMaybeX = nestedMaybeX + if let maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var1_nested), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_var1_nested), .init(.init(0.0))) + + @differentiable + func optional_var1_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + var nestedMaybeX = nestedMaybeX + if let maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var1_nested_tracked), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_var1_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_var1_generic(_ maybeX: T?, _ defaultValue: T) -> T { + var maybeX = maybeX + if let x = maybeX { + return x + } + return defaultValue + } + expectEqual(gradient(at: 10, 20, in: optional_var1_generic), (.init(1.0), 0.0)) + expectEqual(gradient(at: nil, 20, in: optional_var1_generic), (.init(0.0), 1.0)) + + @differentiable + func optional_var1_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + var nestedMaybeX = nestedMaybeX + if let maybeX = nestedMaybeX { + if var x = maybeX { + return x + } + return defaultValue + } + return defaultValue + } + expectEqual(gradient(at: 10, 20, in: optional_var1_nested_generic), (.init(.init(1.0)), 0.0)) + expectEqual(gradient(at: nil, 20, in: optional_var1_nested_generic), (.init(.init(0.0)), 1.0)) +} + +OptionalTests.test("Var2") { + @differentiable + func optional_var2(_ maybeX: Float?) -> Float { + if var x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var2), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_var2), .init(0.0)) + + @differentiable + func optional_var2_tracked(_ maybeX: Tracked?) -> Tracked { + if var x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var2_tracked), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_var2_tracked), .init(0.0)) + + @differentiable + func optional_var2_nested(_ nestedMaybeX: Float??) -> Float { + if var maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var2_nested), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_var2_nested), .init(.init(0.0))) + + @differentiable + func optional_var2_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + if var maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var2_nested_tracked), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_var2_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_var2_generic(_ maybeX: T?, _ defaultValue: T) -> T { + if var x = maybeX { + return x + } + return defaultValue + } + expectEqual(gradient(at: 10, 20, in: optional_var2_generic), (.init(1.0), 0.0)) + expectEqual(gradient(at: nil, 20, in: optional_var2_generic), (.init(0.0), 1.0)) + + @differentiable + func optional_var2_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + if var maybeX = nestedMaybeX { + if var x = maybeX { + return x + } + return defaultValue + } + return defaultValue + } + expectEqual(gradient(at: 10, 20, in: optional_var2_nested_generic), (.init(.init(1.0)), 0.0)) + expectEqual(gradient(at: nil, 20, in: optional_var2_nested_generic), (.init(.init(0.0)), 1.0)) +} + +runAllTests() From fba46ee9f2691f5637a45107272999656bf947b2 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Fri, 7 Aug 2020 14:37:36 -0700 Subject: [PATCH 080/123] Fix edgecase in AllocBoxToStack handling of local apply rdar://66542551 --- .../Transforms/AllocBoxToStack.cpp | 40 +++-- .../allocboxtostack_localapply.swift | 64 ++++++++ .../allocboxtostack_localapply_ossa.sil | 139 ++++++++++++++++++ 3 files changed, 228 insertions(+), 15 deletions(-) diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index 9cde36a2239f4..96177794b7cb0 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -12,6 +12,7 @@ #define DEBUG_TYPE "allocbox-to-stack" #include "swift/AST/DiagnosticsSIL.h" +#include "swift/Basic/BlotMapVector.h" #include "swift/SIL/ApplySite.h" #include "swift/SIL/Dominance.h" #include "swift/SIL/SILArgument.h" @@ -978,8 +979,7 @@ specializeApplySite(SILOptFunctionBuilder &FuncBuilder, ApplySite Apply, } static void rewriteApplySites(AllocBoxToStackState &pass) { - llvm::DenseMap IndexMap; - llvm::SmallVector AppliesToSpecialize; + swift::SmallBlotMapVector AppliesToSpecialize; ArgIndexList Indices; // Build a map from the ApplySite to the indices of the operands @@ -993,17 +993,26 @@ static void rewriteApplySites(AllocBoxToStackState &pass) { Indices.clear(); Indices.push_back(CalleeArgIndexNumber); - auto iterAndSuccess = IndexMap.try_emplace(Apply, Indices); // AllocBoxStack opt promotes boxes passed to a chain of applies when it is // safe to do so. All such applies have to be specialized to take pointer // arguments instead of box arguments. This has to be done in dfs order. - // Since PromotedOperands is already populated in dfs order by - // `recursivelyFindBoxOperandsPromotableToAddress`. Build - // `AppliesToSpecialize` in the same order. - if (iterAndSuccess.second) { - AppliesToSpecialize.push_back(Apply); - } else { - iterAndSuccess.first->second.push_back(CalleeArgIndexNumber); + + // PromotedOperands is already populated in dfs order by + // `recursivelyFindBoxOperandsPromotableToAddress` w.r.t a single alloc_box. + // AppliesToSpecialize is then populated in the order of PromotedOperands. + // If multiple alloc_boxes are passed to the same apply instruction, then + // the apply instruction can appear multiple times in AppliesToSpecialize. + // Only its last appearance is maintained and previous appearances are + // blotted. + auto iterAndSuccess = + AppliesToSpecialize.insert(std::make_pair(Apply, Indices)); + if (!iterAndSuccess.second) { + // Blot the previously inserted apply and insert at the end with updated + // indices + auto OldIndices = iterAndSuccess.first->getValue().second; + OldIndices.push_back(CalleeArgIndexNumber); + AppliesToSpecialize.erase(iterAndSuccess.first); + AppliesToSpecialize.insert(std::make_pair(Apply, OldIndices)); } } @@ -1011,11 +1020,12 @@ static void rewriteApplySites(AllocBoxToStackState &pass) { // operands that we will not need, and remove the existing // ApplySite. SILOptFunctionBuilder FuncBuilder(*pass.T); - for (auto &Apply : AppliesToSpecialize) { - auto It = IndexMap.find(Apply); - assert(It != IndexMap.end()); - auto &Indices = It->second; - + for (auto &It : AppliesToSpecialize) { + if (!It.hasValue()) { + continue; + } + auto Apply = It.getValue().first; + auto Indices = It.getValue().second; // Sort the indices and unique them. sortUnique(Indices); diff --git a/test/SILOptimizer/allocboxtostack_localapply.swift b/test/SILOptimizer/allocboxtostack_localapply.swift index c9c73539ae6b4..5f3522aa07715 100644 --- a/test/SILOptimizer/allocboxtostack_localapply.swift +++ b/test/SILOptimizer/allocboxtostack_localapply.swift @@ -118,3 +118,67 @@ public func testrecur() -> Int { } return bas() + bar() } + +// Test to make sure AppliesToSpecialize in AllocBoxToStack is populated correctly when there are common function calls for mutiple allox_boxes. +// Order of function calls constructed in PromotedOperands: bar common bas common. +// AppliesToSpecialize should have the order: bar bas common. +// Only then, the functions get specialized correctly, and we won't see an assert in checkNoPromotedBoxInApply. +// CHECK-LABEL: sil [noinline] @$s26allocboxtostack_localapply8testdfs1SiyF : +// CHECK-NOT : alloc_box ${ var Int }, var, name "x" +// CHECK-NOT : alloc_box ${ var Int }, var, name "y" +// CHECK-LABEL:} // end sil function '$s26allocboxtostack_localapply8testdfs1SiyF' +@inline(never) +public func testdfs1() -> Int { + var x = 0 + var y = 0 + @inline(never) + func bar() -> Int { + return x + } + @inline(never) + func bas() -> Int { + return y + } + @inline(never) + func common() -> Int { + return bar() + bas() + } + return common() +} + +// Test to make sure we don't optimize the case when we have an inner common function call for multiple boxes. +// We don't optimize this case now, because we don't have additional logic to correctly construct AppliesToSpecialize +// Order of function calls constructed in PromotedOperands: bar innercommon local1 bas innercommon local2 +// AppliesToSpecialize should have the order: bar bas innercommon local1 local2 +// Since we don't maintain any tree like data structure with more info on the call tree, this is not possible to contruct today +// CHECK-LABEL: sil [noinline] @$s26allocboxtostack_localapply8testdfs2SiyF : +// CHECK: alloc_box ${ var Int }, var, name "x" +// CHECK: alloc_box ${ var Int }, var, name "y" +// CHECK-LABEL:} // end sil function '$s26allocboxtostack_localapply8testdfs2SiyF' +@inline(never) +public func testdfs2() -> Int { + var x = 0 + var y = 0 + @inline(never) + func bar() -> Int { + return x + } + @inline(never) + func bas() -> Int { + return y + } + @inline(never) + func innercommon() -> Int { + return bar() + bas() + } + @inline(never) + func local1() -> Int { + return innercommon() + } + @inline(never) + func local2() -> Int { + return innercommon() + } + return local1() + local2() +} + diff --git a/test/SILOptimizer/allocboxtostack_localapply_ossa.sil b/test/SILOptimizer/allocboxtostack_localapply_ossa.sil index 6807349240adc..e1e15aef27a31 100644 --- a/test/SILOptimizer/allocboxtostack_localapply_ossa.sil +++ b/test/SILOptimizer/allocboxtostack_localapply_ossa.sil @@ -349,3 +349,142 @@ bb2: unwind } +struct Int { + var _value: Builtin.Int64 +} + +// Test to make sure AppliesToSpecialize in AllocBoxToStack is populated correctly when there are common function calls for mutiple allox_boxes. +// Order of function calls constructed in PromotedOperands: bar common bas common. +// AppliesToSpecialize should have the order: bar bas common. +// Only then, the functions get specialized correctly, and we won't see an assert in checkNoPromotedBoxInApply. +// CHECK-LABEL: sil [noinline] [ossa] @$testdfs1 : +// CHECK-NOT : alloc_box ${ var Int64 }, var, name "x" +// CHECK-NOT : alloc_box ${ var Int64 }, var, name "y" +// CHECK-LABEL:} // end sil function '$testdfs1' +sil [noinline] [ossa] @$testdfs1 : $@convention(thin) () -> Int64 { +bb0: + %0 = alloc_box ${ var Int64 }, var, name "x" + %1 = project_box %0 : ${ var Int64 }, 0 + %2 = integer_literal $Builtin.Int64, 0 + %3 = struct $Int64 (%2 : $Builtin.Int64) + store %3 to [trivial] %1 : $*Int64 + %5 = alloc_box ${ var Int64 }, var, name "y" + %6 = project_box %5 : ${ var Int64 }, 0 + %7 = integer_literal $Builtin.Int64, 0 + %8 = struct $Int64 (%7 : $Builtin.Int64) + store %8 to [trivial] %6 : $*Int64 + %10 = function_ref @$testdfs1common : $@convention(thin) (@guaranteed { var Int64 }, @guaranteed { var Int64 }) -> Int64 + %11 = apply %10(%0, %5) : $@convention(thin) (@guaranteed { var Int64 }, @guaranteed { var Int64 }) -> Int64 + destroy_value %5 : ${ var Int64 } + destroy_value %0 : ${ var Int64 } + return %11 : $Int64 +} + +sil private [noinline] [ossa] @$testdfs1common : $@convention(thin) (@guaranteed { var Int64 }, @guaranteed { var Int64 }) -> Int64 { +bb0(%0 : @guaranteed ${ var Int64 }, %1 : @guaranteed ${ var Int64 }): + %proj1 = project_box %0 : ${ var Int64 }, 0 + %proj2 = project_box %1 : ${ var Int64 }, 0 + %barfunc = function_ref @$testdfs1bar : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 + %res1 = apply %barfunc(%0) : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 + %basfunc = function_ref @$testdfs1bas : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 + %res2 = apply %basfunc(%1) : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 + %func = function_ref @$blackhole : $@convention(thin) <Ï„_0_0> (@in_guaranteed Ï„_0_0) -> () + %tmp1 = apply %func(%proj1) : $@convention(thin) <Ï„_0_0> (@in_guaranteed Ï„_0_0) -> () + %tmp2 = apply %func(%proj2) : $@convention(thin) <Ï„_0_0> (@in_guaranteed Ï„_0_0) -> () + %res = load [trivial] %proj1 : $*Int64 + return %res : $Int64 +} + +sil private [noinline] [ossa] @$testdfs1bar : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 { +bb0(%0 : @guaranteed ${ var Int64 }): + %1 = project_box %0 : ${ var Int64 }, 0 + %4 = load [trivial] %1 : $*Int64 + return %4 : $Int64 +} + +sil private [noinline] [ossa] @$testdfs1bas : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 { +bb0(%0 : @guaranteed ${ var Int64 }): + %1 = project_box %0 : ${ var Int64 }, 0 + %4 = load [trivial] %1 : $*Int64 + return %4 : $Int64 +} + +// Test to make sure we don't optimize the case when we have an inner common function call for multiple boxes. +// We don't optimize this case now, because we don't have additional logic to correctly construct AppliesToSpecialize +// Order of function calls constructed in PromotedOperands: bar innercommon local1 bas innercommon local2 +// AppliesToSpecialize should have the order: bar bas innercommon local1 local2 +// Since we don't maintain any tree like data structure with more info on the call tree, this is not possible to contruct today +// CHECK-LABEL: sil [noinline] @$s26allocboxtostack_localapply8testdfs2SiyF : +// CHECK: alloc_box ${ var Int }, var, name "x" +// CHECK: alloc_box ${ var Int }, var, name "y" +// CHECK-LABEL:} // end sil function '$s26allocboxtostack_localapply8testdfs2SiyF' +sil [noinline] [ossa] @$testdfs2 : $@convention(thin) () -> Int { +bb0: + %0 = alloc_box ${ var Int }, var, name "x" + %1 = project_box %0 : ${ var Int }, 0 + %2 = integer_literal $Builtin.Int64, 0 + %3 = struct $Int (%2 : $Builtin.Int64) + store %3 to [trivial] %1 : $*Int + %5 = alloc_box ${ var Int }, var, name "y" + %6 = project_box %5 : ${ var Int }, 0 + %7 = integer_literal $Builtin.Int64, 0 + %8 = struct $Int (%7 : $Builtin.Int64) + store %8 to [trivial] %6 : $*Int + %10 = function_ref @$testdfs2local1 : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %11 = apply %10(%0, %5) : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %12 = function_ref @$testdfs2local2 : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %13 = apply %12(%0, %5) : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %14 = struct_extract %11 : $Int, #Int._value + %15 = struct_extract %13 : $Int, #Int._value + %16 = integer_literal $Builtin.Int1, -1 + %17 = builtin "sadd_with_overflow_Int64"(%14 : $Builtin.Int64, %15 : $Builtin.Int64, %16 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) + (%18, %19) = destructure_tuple %17 : $(Builtin.Int64, Builtin.Int1) + cond_fail %19 : $Builtin.Int1, "arithmetic overflow" + %21 = struct $Int (%18 : $Builtin.Int64) + destroy_value %5 : ${ var Int } + destroy_value %0 : ${ var Int } + return %21 : $Int +} + +sil private [noinline] [ossa] @$testdfs2bar : $@convention(thin) (@guaranteed { var Int }) -> Int { +bb0(%0 : @guaranteed ${ var Int }): + %1 = project_box %0 : ${ var Int }, 0 + %4 = load [trivial] %1 : $*Int + return %4 : $Int +} + +sil private [noinline] [ossa] @$testdfs2bas : $@convention(thin) (@guaranteed { var Int }) -> Int { +bb0(%0 : @guaranteed ${ var Int }): + %1 = project_box %0 : ${ var Int }, 0 + %4 = load [trivial] %1 : $*Int + return %4 : $Int +} + +sil private [noinline] [ossa] @$testdfs2innercommon : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int { +bb0(%0 : @guaranteed ${ var Int }, %1 : @guaranteed ${ var Int }): + %2 = project_box %0 : ${ var Int }, 0 + %4 = project_box %1 : ${ var Int }, 0 + %8 = function_ref @$testdfs2bar : $@convention(thin) (@guaranteed { var Int }) -> Int + %9 = apply %8(%0) : $@convention(thin) (@guaranteed { var Int }) -> Int + %11 = function_ref @$testdfs2bas : $@convention(thin) (@guaranteed { var Int }) -> Int + %12 = apply %11(%1) : $@convention(thin) (@guaranteed { var Int }) -> Int + return %12 : $Int +} + +sil private [noinline] [ossa] @$testdfs2local1 : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int { +bb0(%0 : @guaranteed ${ var Int }, %1 : @guaranteed ${ var Int }): + %2 = project_box %0 : ${ var Int }, 0 + %4 = project_box %1 : ${ var Int }, 0 + %7 = function_ref @$testdfs2innercommon : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %8 = apply %7(%0, %1) : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + return %8 : $Int +} + +sil private [noinline] [ossa] @$testdfs2local2 : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int { +bb0(%0 : @guaranteed ${ var Int }, %1 : @guaranteed ${ var Int }): + %2 = project_box %0 : ${ var Int }, 0 + %4 = project_box %1 : ${ var Int }, 0 + %7 = function_ref @$testdfs2innercommon : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %8 = apply %7(%0, %1) : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + return %8 : $Int +} From 4d4af135820a861afbdfafb239131374676fb3d3 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Fri, 7 Aug 2020 15:27:25 -0700 Subject: [PATCH 081/123] Add a flag to turn off analysis of function calls in AllocBoxToStack --- lib/SILOptimizer/Transforms/AllocBoxToStack.cpp | 8 ++++++++ test/SILOptimizer/allocboxtostack_localapply_ossa.sil | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index 96177794b7cb0..6483b47a12a6f 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -44,6 +44,10 @@ static llvm::cl::opt MaxLocalApplyRecurDepth( "max-local-apply-recur-depth", llvm::cl::init(4), llvm::cl::desc("Max recursive depth for analyzing local functions")); +static llvm::cl::opt AllocBoxToStackAnalyzeApply( + "allocbox-to-stack-analyze-apply", llvm::cl::init(true), + llvm::cl::desc("Analyze functions into while alloc_box is passed")); + //===-----------------------------------------------------------------------===// // SIL Utilities for alloc_box Promotion //===----------------------------------------------------------------------===// @@ -320,6 +324,10 @@ static bool checkLocalApplyBody(Operand *O, // AllocBoxToStack opt. We don't want to increase code size, so this is // restricted only for private local functions currently. static bool isOptimizableApplySite(ApplySite Apply) { + if (!AllocBoxToStackAnalyzeApply) { + // turned off explicitly + return false; + } auto callee = Apply.getReferencedFunctionOrNull(); if (!callee) { return false; diff --git a/test/SILOptimizer/allocboxtostack_localapply_ossa.sil b/test/SILOptimizer/allocboxtostack_localapply_ossa.sil index e1e15aef27a31..48b12ef9efd5e 100644 --- a/test/SILOptimizer/allocboxtostack_localapply_ossa.sil +++ b/test/SILOptimizer/allocboxtostack_localapply_ossa.sil @@ -414,10 +414,10 @@ bb0(%0 : @guaranteed ${ var Int64 }): // Order of function calls constructed in PromotedOperands: bar innercommon local1 bas innercommon local2 // AppliesToSpecialize should have the order: bar bas innercommon local1 local2 // Since we don't maintain any tree like data structure with more info on the call tree, this is not possible to contruct today -// CHECK-LABEL: sil [noinline] @$s26allocboxtostack_localapply8testdfs2SiyF : +// CHECK-LABEL: sil [noinline] [ossa] @$testdfs2 : // CHECK: alloc_box ${ var Int }, var, name "x" // CHECK: alloc_box ${ var Int }, var, name "y" -// CHECK-LABEL:} // end sil function '$s26allocboxtostack_localapply8testdfs2SiyF' +// CHECK-LABEL:} // end sil function '$testdfs2' sil [noinline] [ossa] @$testdfs2 : $@convention(thin) () -> Int { bb0: %0 = alloc_box ${ var Int }, var, name "x" From eb625f7b2a225f8a3be64ac660bd0b8bbc1f47a7 Mon Sep 17 00:00:00 2001 From: Frederick Kellison-Linn Date: Fri, 7 Aug 2020 14:18:54 -0400 Subject: [PATCH 082/123] =?UTF-8?q?[Sema]=20Allow=20inference=20of=20bindi?= =?UTF-8?q?ng=20to=20type=20var=20of=20differing=20lvalue-ness=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit when we have an optional type. This uncovered an error with unresolved member lookup where we allowed an unresolved value member constraint to fail if lookup failed in an optional type wrapping a type variable. This resolves SR-13357. --- lib/Sema/CSApply.cpp | 2 +- lib/Sema/CSBindings.cpp | 3 +-- lib/Sema/CSSimplify.cpp | 8 ++++++++ test/Constraints/patterns.swift | 6 +----- test/expr/delayed-ident/enum.swift | 10 ++++++++++ test/expr/delayed-ident/static_var.swift | 14 ++++++++++++++ 6 files changed, 35 insertions(+), 8 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index e8d103da90d1b..b4971a00bf409 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2696,7 +2696,7 @@ namespace { // then we're in an ambiguity tolerant mode used for diagnostic // generation. Just leave this as an unresolved member reference. Type resultTy = simplifyType(cs.getType(expr)); - if (resultTy->getRValueType()->is()) { + if (resultTy->hasUnresolvedType()) { cs.setType(expr, resultTy); return expr; } diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 46c02ad1b70a2..bb99b97afd980 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -715,8 +715,7 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( // Make sure we aren't trying to equate type variables with different // lvalue-binding rules. - if (auto otherTypeVar = - type->lookThroughAllOptionalTypes()->getAs()) { + if (auto otherTypeVar = type->getAs()) { if (typeVar->getImpl().canBindToLValue() != otherTypeVar->getImpl().canBindToLValue()) return None; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index b85e02d509480..d90d62577ca78 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -6590,6 +6590,14 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, baseObjTy->is() && constraintKind == ConstraintKind::UnresolvedValueMember) { if (auto objectType = instanceTy->getOptionalObjectType()) { + // If we don't have a wrapped type yet, we can't look through the optional + // type. + if (objectType->getAs()) { + MemberLookupResult result; + result.OverallResult = MemberLookupResult::Unsolved; + return result; + } + if (objectType->mayHaveMembers()) { LookupResult &optionalLookup = lookupMember(objectType, memberName); for (auto result : optionalLookup) diff --git a/test/Constraints/patterns.swift b/test/Constraints/patterns.swift index 2250343a9e666..c79fc2195c719 100644 --- a/test/Constraints/patterns.swift +++ b/test/Constraints/patterns.swift @@ -296,8 +296,7 @@ switch staticMembers { // expected-note@-2 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} case .prop: break - // TODO: repeated error message - case .optProp: break // expected-error* {{not unwrapped}} + case .optProp: break case .method: break // expected-error{{member 'method' expects argument of type 'Int'}} case .method(0): break @@ -311,9 +310,6 @@ switch staticMembers { case .optMethod: break // expected-error{{member 'optMethod' expects argument of type 'Int'}} case .optMethod(0): break - // expected-error@-1 {{value of optional type 'StaticMembers?' must be unwrapped to a value of type 'StaticMembers'}} - // expected-note@-2 {{coalesce}} - // expected-note@-3 {{force-unwrap}} } _ = 0 diff --git a/test/expr/delayed-ident/enum.swift b/test/expr/delayed-ident/enum.swift index 20fa5e6e5431b..cbb3d242f24a1 100644 --- a/test/expr/delayed-ident/enum.swift +++ b/test/expr/delayed-ident/enum.swift @@ -25,3 +25,13 @@ e2a = .Second(5) var e2b: E2 = .Second(5) e2b = .First var e2c: E2 = .First // expected-error{{generic parameter 'T' could not be inferred}} + +// SR-13357 +struct SR13357 {} +extension Optional where Wrapped == SR13357 { + static var sr13357: Self { .none } +} + +func f_sr13357(_: T?) { } + +f_sr13357(.sr13357) diff --git a/test/expr/delayed-ident/static_var.swift b/test/expr/delayed-ident/static_var.swift index f6b28bf5569c5..cfe701754f791 100644 --- a/test/expr/delayed-ident/static_var.swift +++ b/test/expr/delayed-ident/static_var.swift @@ -52,3 +52,17 @@ var _: HasClosure = .factoryOpt(3) // expected-note@-3 {{force-unwrap}} // FIXME: we should accept this var _: HasClosure = .factoryOpt!(4) // expected-error {{cannot infer contextual base in reference to member 'factoryOpt'}} + +infix operator =%: ComparisonPrecedence + +extension Optional { + static func =%(lhs: Self, rhs: Self) -> Bool { return true } +} + +struct ImplicitMembers { + static var optional: ImplicitMembers? = ImplicitMembers() +} + +func implicit(_ i: inout ImplicitMembers) { + if i =% .optional {} +} From 03d94b44a6ecb2a8e4e05e9ff55081209684d7f7 Mon Sep 17 00:00:00 2001 From: John McCall Date: Sat, 8 Aug 2020 02:28:47 -0400 Subject: [PATCH 083/123] Add default IR attributes to helper functions and convert several more places to use getOrCreateHelperFunction. This means that several of these places are now emitting shared functions rather than private ones, which I've verified is okay. There are some other places where privacy is still unfortunately necessary. I've also fixed the name of the store-extra-inhabitants helper function to say "store" instead of "get", which is longstanding (but harmless because it's private). Fixes rdar://66707994. --- lib/IRGen/GenCast.cpp | 147 ++++--- lib/IRGen/GenDecl.cpp | 1 + lib/IRGen/GenKeyPath.cpp | 21 +- lib/IRGen/GenOpaque.cpp | 4 +- lib/IRGen/IRGenModule.cpp | 1 + lib/IRGen/MetadataRequest.cpp | 362 +++++++++--------- test/IRGen/casts.sil | 8 +- .../default_function_ir_attributes.swift | 175 +++++++++ test/IRGen/keypaths_objc.sil | 2 +- test/IRGen/subclass_existentials.sil | 4 +- test/Serialization/autolinking.swift | 4 +- 11 files changed, 437 insertions(+), 292 deletions(-) create mode 100644 test/IRGen/default_function_ir_attributes.swift diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp index 5054b5344303f..90ff58b9bfa15 100644 --- a/lib/IRGen/GenCast.cpp +++ b/lib/IRGen/GenCast.cpp @@ -357,7 +357,7 @@ llvm::Value *irgen::emitReferenceToObjCProtocol(IRGenFunction &IGF, /// The function's output type is (value, witnessTable...) /// /// The value is NULL if the cast failed. -static llvm::Function * +static llvm::Constant * emitExistentialScalarCastFn(IRGenModule &IGM, unsigned numProtocols, CheckedCastMode mode, @@ -385,13 +385,7 @@ emitExistentialScalarCastFn(IRGenModule &IGM, } } - // See if we already defined this function. - - if (auto fn = IGM.Module.getFunction(name)) - return fn; - // Build the function type. - llvm::SmallVector argTys; llvm::SmallVector returnTys; argTys.push_back(IGM.Int8PtrTy); @@ -405,84 +399,77 @@ emitExistentialScalarCastFn(IRGenModule &IGM, } llvm::Type *returnTy = llvm::StructType::get(IGM.getLLVMContext(), returnTys); - - auto fnTy = llvm::FunctionType::get(returnTy, argTys, /*vararg*/ false); - auto fn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, - llvm::Twine(name), IGM.getModule()); - fn->setAttributes(IGM.constructInitialAttributes()); - - IRGenFunction IGF(IGM, fn); - if (IGM.DebugInfo) - IGM.DebugInfo->emitArtificialFunction(IGF, fn); - Explosion args = IGF.collectParameters(); - - auto value = args.claimNext(); - auto ref = args.claimNext(); - auto failBB = IGF.createBasicBlock("fail"); - auto conformsToProtocol = IGM.getConformsToProtocolFn(); - - Explosion rets; - rets.add(value); - - // Check the class constraint if necessary. - if (checkSuperclassConstraint) { - auto superclassMetadata = args.claimNext(); - auto castFn = IGF.IGM.getDynamicCastMetatypeFn(); - auto castResult = IGF.Builder.CreateCall(castFn, {ref, - superclassMetadata}); - - auto cc = cast(castFn)->getCallingConv(); - - // FIXME: Eventually, we may want to throw. - castResult->setCallingConv(cc); - castResult->setDoesNotThrow(); - auto isClass = IGF.Builder.CreateICmpNE( - castResult, - llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy)); + return IGM.getOrCreateHelperFunction(name, returnTy, argTys, + [&](IRGenFunction &IGF) { + Explosion args = IGF.collectParameters(); + + auto value = args.claimNext(); + auto ref = args.claimNext(); + auto failBB = IGF.createBasicBlock("fail"); + auto conformsToProtocol = IGM.getConformsToProtocolFn(); + + Explosion rets; + rets.add(value); + + // Check the class constraint if necessary. + if (checkSuperclassConstraint) { + auto superclassMetadata = args.claimNext(); + auto castFn = IGF.IGM.getDynamicCastMetatypeFn(); + auto castResult = IGF.Builder.CreateCall(castFn, {ref, + superclassMetadata}); + + auto cc = cast(castFn)->getCallingConv(); + + // FIXME: Eventually, we may want to throw. + castResult->setCallingConv(cc); + castResult->setDoesNotThrow(); + + auto isClass = IGF.Builder.CreateICmpNE( + castResult, + llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy)); + + auto contBB = IGF.createBasicBlock("cont"); + IGF.Builder.CreateCondBr(isClass, contBB, failBB); + IGF.Builder.emitBlock(contBB); + } else if (checkClassConstraint) { + auto isClass = IGF.Builder.CreateCall(IGM.getIsClassTypeFn(), ref); + auto contBB = IGF.createBasicBlock("cont"); + IGF.Builder.CreateCondBr(isClass, contBB, failBB); + IGF.Builder.emitBlock(contBB); + } - auto contBB = IGF.createBasicBlock("cont"); - IGF.Builder.CreateCondBr(isClass, contBB, failBB); - IGF.Builder.emitBlock(contBB); - } else if (checkClassConstraint) { - auto isClass = IGF.Builder.CreateCall(IGM.getIsClassTypeFn(), ref); - auto contBB = IGF.createBasicBlock("cont"); - IGF.Builder.CreateCondBr(isClass, contBB, failBB); - IGF.Builder.emitBlock(contBB); - } + // Look up each protocol conformance we want. + for (unsigned i = 0; i < numProtocols; ++i) { + auto proto = args.claimNext(); + auto witness = IGF.Builder.CreateCall(conformsToProtocol, {ref, proto}); + auto isNull = IGF.Builder.CreateICmpEQ(witness, + llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy)); + auto contBB = IGF.createBasicBlock("cont"); + IGF.Builder.CreateCondBr(isNull, failBB, contBB); + + IGF.Builder.emitBlock(contBB); + rets.add(witness); + } - // Look up each protocol conformance we want. - for (unsigned i = 0; i < numProtocols; ++i) { - auto proto = args.claimNext(); - auto witness = IGF.Builder.CreateCall(conformsToProtocol, {ref, proto}); - auto isNull = IGF.Builder.CreateICmpEQ(witness, - llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy)); - auto contBB = IGF.createBasicBlock("cont"); - IGF.Builder.CreateCondBr(isNull, failBB, contBB); + // If we succeeded, return the witnesses. + IGF.emitScalarReturn(returnTy, rets); - IGF.Builder.emitBlock(contBB); - rets.add(witness); - } - - // If we succeeded, return the witnesses. - IGF.emitScalarReturn(returnTy, rets); - - // If we failed, return nil or trap. - IGF.Builder.emitBlock(failBB); - switch (mode) { - case CheckedCastMode::Conditional: { - auto null = llvm::ConstantStruct::getNullValue(returnTy); - IGF.Builder.CreateRet(null); - break; - } + // If we failed, return nil or trap. + IGF.Builder.emitBlock(failBB); + switch (mode) { + case CheckedCastMode::Conditional: { + auto null = llvm::ConstantStruct::getNullValue(returnTy); + IGF.Builder.CreateRet(null); + break; + } - case CheckedCastMode::Unconditional: { - IGF.emitTrap("type cast failed", /*EmitUnreachable=*/true); - break; - } - } - - return fn; + case CheckedCastMode::Unconditional: { + IGF.emitTrap("type cast failed", /*EmitUnreachable=*/true); + break; + } + } + }); } llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF, diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 0cf022d9cbee3..b5fbcef362e4e 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -4862,6 +4862,7 @@ static llvm::Function *shouldDefineHelper(IRGenModule &IGM, if (!def) return nullptr; if (!def->empty()) return nullptr; + def->setAttributes(IGM.constructInitialAttributes()); ApplyIRLinkage(IRLinkage::InternalLinkOnceODR).to(def); def->setDoesNotThrow(); def->setCallingConv(IGM.DefaultCC); diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index 41128f62b8620..6cfc8d962c9b9 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -277,6 +277,7 @@ getLayoutFunctionForComputedComponent(IRGenModule &IGM, auto layoutFn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, "keypath_get_arg_layout", IGM.getModule()); + layoutFn->setAttributes(IGM.constructInitialAttributes()); { IRGenFunction IGF(IGM, layoutFn); @@ -378,6 +379,7 @@ getWitnessTableForComputedComponent(IRGenModule &IGM, auto destroyFn = llvm::Function::Create(destroyType, llvm::GlobalValue::PrivateLinkage, "keypath_destroy", IGM.getModule()); destroy = destroyFn; + destroyFn->setAttributes(IGM.constructInitialAttributes()); IRGenFunction IGF(IGM, destroyFn); if (IGM.DebugInfo) @@ -426,6 +428,7 @@ getWitnessTableForComputedComponent(IRGenModule &IGM, auto copyFn = llvm::Function::Create(copyType, llvm::GlobalValue::PrivateLinkage, "keypath_copy", IGM.getModule()); copy = copyFn; + copyFn->setAttributes(IGM.constructInitialAttributes()); IRGenFunction IGF(IGM, copyFn); if (IGM.DebugInfo) @@ -538,6 +541,7 @@ getInitializerForComputedComponent(IRGenModule &IGM, auto initFn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, "keypath_arg_init", IGM.getModule()); + initFn->setAttributes(IGM.constructInitialAttributes()); { IRGenFunction IGF(IGM, initFn); @@ -945,23 +949,16 @@ emitKeyPathComponent(IRGenModule &IGM, // Note that we'd need to do this anyway in JIT mode because we would // need to unique the selector at runtime anyway. auto selectorName = IGM.getObjCSelectorName(declRef); - llvm::Type *fnParams[] = {IGM.Int8PtrTy}; - auto fnTy = llvm::FunctionType::get(IGM.Int8PtrTy, fnParams, false); SmallString<32> fnName; fnName.append("keypath_get_selector_"); fnName.append(selectorName); - auto fn = cast( - IGM.Module.getOrInsertFunction(fnName, fnTy).getCallee()); - if (fn->empty()) { - fn->setLinkage(llvm::Function::PrivateLinkage); - IRGenFunction subIGF(IGM, fn); - if (IGM.DebugInfo) - IGM.DebugInfo->emitArtificialFunction(subIGF, fn); - + auto fn = IGM.getOrCreateHelperFunction(fnName, IGM.Int8PtrTy, + {IGM.Int8PtrTy}, + [&selectorName](IRGenFunction &subIGF) { auto selectorValue = subIGF.emitObjCSelectorRefLoad(selectorName); subIGF.Builder.CreateRet(selectorValue); - } - + }); + idValue = fn; idResolution = KeyPathComponentHeader::FunctionCall; } else { diff --git a/lib/IRGen/GenOpaque.cpp b/lib/IRGen/GenOpaque.cpp index a6a328f273aa4..a01ff1ad59adc 100644 --- a/lib/IRGen/GenOpaque.cpp +++ b/lib/IRGen/GenOpaque.cpp @@ -1354,6 +1354,7 @@ irgen::getOrCreateGetExtraInhabitantTagFunction(IRGenModule &IGM, auto fn = llvm::Function::Create(fnTy, llvm::Function::PrivateLinkage, "__swift_get_extra_inhabitant_index", &IGM.Module); + fn->setAttributes(IGM.constructInitialAttributes()); fn->setCallingConv(IGM.SwiftCC); IRGenFunction IGF(IGM, fn); auto parameters = IGF.collectParameters(); @@ -1427,8 +1428,9 @@ irgen::getOrCreateStoreExtraInhabitantTagFunction(IRGenModule &IGM, // TODO: use a meaningful mangled name and internal/shared linkage. auto fn = llvm::Function::Create(fnTy, llvm::Function::PrivateLinkage, - "__swift_get_extra_inhabitant_index", + "__swift_store_extra_inhabitant_index", &IGM.Module); + fn->setAttributes(IGM.constructInitialAttributes()); fn->setCallingConv(IGM.SwiftCC); IRGenFunction IGF(IGM, fn); auto parameters = IGF.collectParameters(); diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 03c871a9ffe13..dd90ae9399526 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -1407,6 +1407,7 @@ void IRGenModule::emitAutolinkInfo() { llvm::Function::Create(llvm::FunctionType::get(VoidTy, false), llvm::GlobalValue::ExternalLinkage, buf, &Module); + ForceImportThunk->setAttributes(constructInitialAttributes()); ApplyIRLinkage(IRLinkage::ExternalExport).to(ForceImportThunk); if (Triple.supportsCOMDAT()) if (auto *GO = cast(ForceImportThunk)) diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 7dfd2be9b2f44..5a794512e3ff1 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -2256,66 +2256,57 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction( // Factor out the buffer shuffling for metadata accessors that take their // arguments directly, so that the accessor function itself only needs to // materialize the nominal type descriptor and call this thunk. - auto thunkFn = cast( - IGM.getModule() - ->getOrInsertFunction("__swift_instantiateGenericMetadata", - IGM.TypeMetadataResponseTy, - IGM.SizeTy, // request - IGM.Int8PtrTy, // arg 0 - IGM.Int8PtrTy, // arg 1 - IGM.Int8PtrTy, // arg 2 - IGM.TypeContextDescriptorPtrTy) // type context descriptor - .getCallee() - ->stripPointerCasts()); - - if (thunkFn->empty()) { - ApplyIRLinkage(IRLinkage::InternalLinkOnceODR) - .to(thunkFn); - thunkFn->setDoesNotAccessMemory(); - thunkFn->setDoesNotThrow(); - thunkFn->setCallingConv(IGM.SwiftCC); - thunkFn->addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoInline); - IGM.setHasNoFramePointer(thunkFn); - - [&IGM, thunkFn]{ - IRGenFunction subIGF(IGM, thunkFn); - - auto params = subIGF.collectParameters(); - auto request = params.claimNext(); - auto arg0 = params.claimNext(); - auto arg1 = params.claimNext(); - auto arg2 = params.claimNext(); - auto descriptor = params.claimNext(); - - // Allocate a buffer with enough storage for the arguments. - auto argsBufferTy = - llvm::ArrayType::get(IGM.Int8PtrTy, - NumDirectGenericTypeMetadataAccessFunctionArgs); - auto argsBuffer = subIGF.createAlloca(argsBufferTy, - IGM.getPointerAlignment(), - "generic.arguments"); - subIGF.Builder.CreateLifetimeStart(argsBuffer, - IGM.getPointerSize() * NumDirectGenericTypeMetadataAccessFunctionArgs); - - auto arg0Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, - argsBuffer.getAddress(), 0, 0); - subIGF.Builder.CreateStore(arg0, arg0Buf, IGM.getPointerAlignment()); - auto arg1Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, - argsBuffer.getAddress(), 0, 1); - subIGF.Builder.CreateStore(arg1, arg1Buf, IGM.getPointerAlignment()); - auto arg2Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, - argsBuffer.getAddress(), 0, 2); - subIGF.Builder.CreateStore(arg2, arg2Buf, IGM.getPointerAlignment()); - - // Make the call. - auto argsAddr = subIGF.Builder.CreateBitCast(argsBuffer.getAddress(), - IGM.Int8PtrTy); - auto result = subIGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(), - {request, argsAddr, descriptor}); - subIGF.Builder.CreateRet(result); - }(); - } + auto generateThunkFn = [&IGM](IRGenFunction &subIGF) { + subIGF.CurFn->setDoesNotAccessMemory(); + subIGF.CurFn->setCallingConv(IGM.SwiftCC); + IGM.setHasNoFramePointer(subIGF.CurFn); + + auto params = subIGF.collectParameters(); + auto request = params.claimNext(); + auto arg0 = params.claimNext(); + auto arg1 = params.claimNext(); + auto arg2 = params.claimNext(); + auto descriptor = params.claimNext(); + + // Allocate a buffer with enough storage for the arguments. + auto argsBufferTy = + llvm::ArrayType::get(IGM.Int8PtrTy, + NumDirectGenericTypeMetadataAccessFunctionArgs); + auto argsBuffer = subIGF.createAlloca(argsBufferTy, + IGM.getPointerAlignment(), + "generic.arguments"); + subIGF.Builder.CreateLifetimeStart(argsBuffer, + IGM.getPointerSize() * NumDirectGenericTypeMetadataAccessFunctionArgs); + + auto arg0Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, + argsBuffer.getAddress(), 0, 0); + subIGF.Builder.CreateStore(arg0, arg0Buf, IGM.getPointerAlignment()); + auto arg1Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, + argsBuffer.getAddress(), 0, 1); + subIGF.Builder.CreateStore(arg1, arg1Buf, IGM.getPointerAlignment()); + auto arg2Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, + argsBuffer.getAddress(), 0, 2); + subIGF.Builder.CreateStore(arg2, arg2Buf, IGM.getPointerAlignment()); + + // Make the call. + auto argsAddr = subIGF.Builder.CreateBitCast(argsBuffer.getAddress(), + IGM.Int8PtrTy); + auto result = subIGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(), + {request, argsAddr, descriptor}); + subIGF.Builder.CreateRet(result); + }; + auto thunkFn = IGM.getOrCreateHelperFunction( + "__swift_instantiateGenericMetadata", + IGM.TypeMetadataResponseTy, + { + IGM.SizeTy, // request + IGM.Int8PtrTy, // arg 0 + IGM.Int8PtrTy, // arg 1 + IGM.Int8PtrTy, // arg 2 + IGM.TypeContextDescriptorPtrTy // type context descriptor + }, + generateThunkFn, + /*noinline*/true); // Call out to the helper. auto arg0 = numArguments >= 1 @@ -2805,136 +2796,127 @@ emitMetadataAccessByMangledName(IRGenFunction &IGF, CanType type, request.isStaticallyAbstract() ? "__swift_instantiateConcreteTypeFromMangledNameAbstract" : "__swift_instantiateConcreteTypeFromMangledName"; - auto instantiationFn = cast( - IGM.getModule() - ->getOrInsertFunction(instantiationFnName, IGF.IGM.TypeMetadataPtrTy, - cache->getType()) - .getCallee() - ->stripPointerCasts()); - if (instantiationFn->empty()) { - ApplyIRLinkage(IRLinkage::InternalLinkOnceODR) - .to(instantiationFn); - instantiationFn->setDoesNotAccessMemory(); - instantiationFn->setDoesNotThrow(); - instantiationFn->addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoInline); - IGM.setHasNoFramePointer(instantiationFn); - - [&IGM, instantiationFn, request]{ - IRGenFunction subIGF(IGM, instantiationFn); - - auto params = subIGF.collectParameters(); - auto cache = params.claimNext(); - - // Load the existing cache value. - // Conceptually, this needs to establish memory ordering with the - // store we do later in the function: if the metadata value is - // non-null, we must be able to see any stores performed by the - // initialization of the metadata. However, any attempt to read - // from the metadata will be address-dependent on the loaded - // metadata pointer, which is sufficient to provide adequate - // memory ordering guarantees on all the platforms we care about: - // ARM has special rules about address dependencies, and x86's - // memory ordering is strong enough to guarantee the visibility - // even without the address dependency. - // - // And we do not need to worry about the compiler because the - // address dependency naturally forces an order to the memory - // accesses. - // - // Therefore, we can perform a completely naked load here. - // FIXME: Technically should be "consume", but that introduces barriers - // in the current LLVM ARM backend. - auto cacheWordAddr = subIGF.Builder.CreateBitCast(cache, - IGM.Int64Ty->getPointerTo()); - auto load = subIGF.Builder.CreateLoad(cacheWordAddr, Alignment(8)); - // Make this barrier explicit when building for TSan to avoid false positives. - if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread) - load->setOrdering(llvm::AtomicOrdering::Acquire); - else - load->setOrdering(llvm::AtomicOrdering::Monotonic); - - // Compare the load result to see if it's negative. - auto isUnfilledBB = subIGF.createBasicBlock(""); - auto contBB = subIGF.createBasicBlock(""); - llvm::Value *comparison = subIGF.Builder.CreateICmpSLT(load, - llvm::ConstantInt::get(IGM.Int64Ty, 0)); - comparison = subIGF.Builder.CreateExpect(comparison, - llvm::ConstantInt::get(IGM.Int1Ty, 0)); - subIGF.Builder.CreateCondBr(comparison, isUnfilledBB, contBB); - auto loadBB = subIGF.Builder.GetInsertBlock(); - - // If the load is negative, emit the call to instantiate the type - // metadata. - subIGF.Builder.SetInsertPoint(&subIGF.CurFn->back()); - subIGF.Builder.emitBlock(isUnfilledBB); - - // Break up the loaded value into size and relative address to the - // string. - auto size = subIGF.Builder.CreateAShr(load, 32); - size = subIGF.Builder.CreateTruncOrBitCast(size, IGM.SizeTy); - size = subIGF.Builder.CreateNeg(size); - - auto stringAddrOffset = subIGF.Builder.CreateTrunc(load, - IGM.Int32Ty); - stringAddrOffset = subIGF.Builder.CreateSExtOrBitCast(stringAddrOffset, - IGM.SizeTy); - auto stringAddrBase = subIGF.Builder.CreatePtrToInt(cache, IGM.SizeTy); - if (IGM.getModule()->getDataLayout().isBigEndian()) { - stringAddrBase = subIGF.Builder.CreateAdd(stringAddrBase, - llvm::ConstantInt::get(IGM.SizeTy, 4)); - } - auto stringAddr = subIGF.Builder.CreateAdd(stringAddrBase, - stringAddrOffset); - stringAddr = subIGF.Builder.CreateIntToPtr(stringAddr, IGM.Int8PtrTy); - - llvm::CallInst *call; - if (request.isStaticallyAbstract()) { - call = subIGF.Builder.CreateCall( - IGM.getGetTypeByMangledNameInContextInMetadataStateFn(), - {llvm::ConstantInt::get(IGM.SizeTy, (size_t)MetadataState::Abstract), - stringAddr, size, - // TODO: Use mangled name lookup in generic - // contexts? - llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy), - llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)}); - } else { - call = subIGF.Builder.CreateCall( - IGM.getGetTypeByMangledNameInContextFn(), - {stringAddr, size, - // TODO: Use mangled name lookup in generic - // contexts? - llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy), - llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)}); - } - call->setDoesNotThrow(); - call->setDoesNotAccessMemory(); - call->setCallingConv(IGM.SwiftCC); - - // Store the result back to the cache. Metadata instantatiation should - // already have emitted the necessary barriers to publish the instantiated - // metadata to other threads, so we only need to expose the pointer. - // Worst case, another thread might race with us and reinstantiate the - // exact same metadata pointer. - auto resultWord = subIGF.Builder.CreatePtrToInt(call, IGM.SizeTy); - resultWord = subIGF.Builder.CreateZExtOrBitCast(resultWord, IGM.Int64Ty); - auto store = subIGF.Builder.CreateStore(resultWord, cacheWordAddr, - Alignment(8)); - store->setOrdering(llvm::AtomicOrdering::Monotonic); - subIGF.Builder.CreateBr(contBB); - - subIGF.Builder.SetInsertPoint(loadBB); - subIGF.Builder.emitBlock(contBB); - auto phi = subIGF.Builder.CreatePHI(IGM.Int64Ty, 2); - phi->addIncoming(load, loadBB); - phi->addIncoming(resultWord, isUnfilledBB); - - auto resultAddr = subIGF.Builder.CreateTruncOrBitCast(phi, IGM.SizeTy); - resultAddr = subIGF.Builder.CreateIntToPtr(resultAddr, - IGM.TypeMetadataPtrTy); - subIGF.Builder.CreateRet(resultAddr); - }(); - } + auto generateInstantiationFn = [&IGM, request](IRGenFunction &subIGF) { + subIGF.CurFn->setDoesNotAccessMemory(); + IGM.setHasNoFramePointer(subIGF.CurFn); + + auto params = subIGF.collectParameters(); + auto cache = params.claimNext(); + + // Load the existing cache value. + // Conceptually, this needs to establish memory ordering with the + // store we do later in the function: if the metadata value is + // non-null, we must be able to see any stores performed by the + // initialization of the metadata. However, any attempt to read + // from the metadata will be address-dependent on the loaded + // metadata pointer, which is sufficient to provide adequate + // memory ordering guarantees on all the platforms we care about: + // ARM has special rules about address dependencies, and x86's + // memory ordering is strong enough to guarantee the visibility + // even without the address dependency. + // + // And we do not need to worry about the compiler because the + // address dependency naturally forces an order to the memory + // accesses. + // + // Therefore, we can perform a completely naked load here. + // FIXME: Technically should be "consume", but that introduces barriers + // in the current LLVM ARM backend. + auto cacheWordAddr = subIGF.Builder.CreateBitCast(cache, + IGM.Int64Ty->getPointerTo()); + auto load = subIGF.Builder.CreateLoad(cacheWordAddr, Alignment(8)); + // Make this barrier explicit when building for TSan to avoid false positives. + if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread) + load->setOrdering(llvm::AtomicOrdering::Acquire); + else + load->setOrdering(llvm::AtomicOrdering::Monotonic); + + // Compare the load result to see if it's negative. + auto isUnfilledBB = subIGF.createBasicBlock(""); + auto contBB = subIGF.createBasicBlock(""); + llvm::Value *comparison = subIGF.Builder.CreateICmpSLT(load, + llvm::ConstantInt::get(IGM.Int64Ty, 0)); + comparison = subIGF.Builder.CreateExpect(comparison, + llvm::ConstantInt::get(IGM.Int1Ty, 0)); + subIGF.Builder.CreateCondBr(comparison, isUnfilledBB, contBB); + auto loadBB = subIGF.Builder.GetInsertBlock(); + + // If the load is negative, emit the call to instantiate the type + // metadata. + subIGF.Builder.SetInsertPoint(&subIGF.CurFn->back()); + subIGF.Builder.emitBlock(isUnfilledBB); + + // Break up the loaded value into size and relative address to the + // string. + auto size = subIGF.Builder.CreateAShr(load, 32); + size = subIGF.Builder.CreateTruncOrBitCast(size, IGM.SizeTy); + size = subIGF.Builder.CreateNeg(size); + + auto stringAddrOffset = subIGF.Builder.CreateTrunc(load, + IGM.Int32Ty); + stringAddrOffset = subIGF.Builder.CreateSExtOrBitCast(stringAddrOffset, + IGM.SizeTy); + auto stringAddrBase = subIGF.Builder.CreatePtrToInt(cache, IGM.SizeTy); + if (IGM.getModule()->getDataLayout().isBigEndian()) { + stringAddrBase = subIGF.Builder.CreateAdd(stringAddrBase, + llvm::ConstantInt::get(IGM.SizeTy, 4)); + } + auto stringAddr = subIGF.Builder.CreateAdd(stringAddrBase, + stringAddrOffset); + stringAddr = subIGF.Builder.CreateIntToPtr(stringAddr, IGM.Int8PtrTy); + + llvm::CallInst *call; + if (request.isStaticallyAbstract()) { + call = subIGF.Builder.CreateCall( + IGM.getGetTypeByMangledNameInContextInMetadataStateFn(), + {llvm::ConstantInt::get(IGM.SizeTy, (size_t)MetadataState::Abstract), + stringAddr, size, + // TODO: Use mangled name lookup in generic + // contexts? + llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy), + llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)}); + } else { + call = subIGF.Builder.CreateCall( + IGM.getGetTypeByMangledNameInContextFn(), + {stringAddr, size, + // TODO: Use mangled name lookup in generic + // contexts? + llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy), + llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)}); + } + call->setDoesNotThrow(); + call->setDoesNotAccessMemory(); + call->setCallingConv(IGM.SwiftCC); + + // Store the result back to the cache. Metadata instantatiation should + // already have emitted the necessary barriers to publish the instantiated + // metadata to other threads, so we only need to expose the pointer. + // Worst case, another thread might race with us and reinstantiate the + // exact same metadata pointer. + auto resultWord = subIGF.Builder.CreatePtrToInt(call, IGM.SizeTy); + resultWord = subIGF.Builder.CreateZExtOrBitCast(resultWord, IGM.Int64Ty); + auto store = subIGF.Builder.CreateStore(resultWord, cacheWordAddr, + Alignment(8)); + store->setOrdering(llvm::AtomicOrdering::Monotonic); + subIGF.Builder.CreateBr(contBB); + + subIGF.Builder.SetInsertPoint(loadBB); + subIGF.Builder.emitBlock(contBB); + auto phi = subIGF.Builder.CreatePHI(IGM.Int64Ty, 2); + phi->addIncoming(load, loadBB); + phi->addIncoming(resultWord, isUnfilledBB); + + auto resultAddr = subIGF.Builder.CreateTruncOrBitCast(phi, IGM.SizeTy); + resultAddr = subIGF.Builder.CreateIntToPtr(resultAddr, + IGM.TypeMetadataPtrTy); + subIGF.Builder.CreateRet(resultAddr); + }; + auto instantiationFn = + IGM.getOrCreateHelperFunction(instantiationFnName, + IGF.IGM.TypeMetadataPtrTy, + cache->getType(), + generateInstantiationFn, + /*noinline*/true); auto call = IGF.Builder.CreateCall(instantiationFn, cache); call->setDoesNotThrow(); diff --git a/test/IRGen/casts.sil b/test/IRGen/casts.sil index 3458ef87cab62..fa2dbf9f2df85 100644 --- a/test/IRGen/casts.sil +++ b/test/IRGen/casts.sil @@ -54,7 +54,7 @@ entry(%n : $Builtin.NativeObject): // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { %objc_object*, i8** } @u_cast_to_class_existential(%objc_object* %0) // CHECK: call { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* {{%.*}}, %swift.type* {{%.*}}, {{.*}} @"$s5casts2CPMp" -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} private { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* %0, %swift.type* %1, %swift.protocol* %2) {{.*}} { +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* %0, %swift.type* %1, %swift.protocol* %2) {{.*}} { // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null // CHECK: br i1 [[IS_NULL]], label %fail, label %cont @@ -80,7 +80,7 @@ entry(%a : $@thick Any.Type): // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { %objc_object*, i8**, i8** } @u_cast_to_class_existential_2(%objc_object* %0) // CHECK: call { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* {{%.*}}, %swift.type* {{%.*}}, {{.*}} @"$s5casts2CPMp"{{[^,]*}}, {{.*}} @"$s5casts3CP2Mp" -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} private { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* %0, %swift.type* %1, %swift.protocol* %2, %swift.protocol* %3) +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* %0, %swift.type* %1, %swift.protocol* %2, %swift.protocol* %3) // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null // CHECK: br i1 [[IS_NULL]], label %fail, label %cont @@ -122,7 +122,7 @@ entry(%a : $@thick Any.Type): // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { %objc_object*, i8** } @c_cast_to_class_existential(%objc_object* %0) // CHECK: call { i8*, i8** } @dynamic_cast_existential_1_conditional(i8* {{.*}}, %swift.type* %.Type, {{.*}} @"$s5casts2CPMp" -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} private { i8*, i8** } @dynamic_cast_existential_1_conditional(i8* %0, %swift.type* %1, %swift.protocol* %2) +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden { i8*, i8** } @dynamic_cast_existential_1_conditional(i8* %0, %swift.type* %1, %swift.protocol* %2) // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null // CHECK: br i1 [[IS_NULL]], label %fail, label %cont @@ -152,7 +152,7 @@ nay: // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { %objc_object*, i8**, i8** } @c_cast_to_class_existential_2(%objc_object* %0) // CHECK: call { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* {{%.*}}, %swift.type* {{%.*}}, {{.*}} @"$s5casts2CPMp" {{[^,]*}}, {{.*}} @"$s5casts3CP2Mp" -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} private { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* %0, %swift.type* %1, %swift.protocol* %2, %swift.protocol* %3) +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* %0, %swift.type* %1, %swift.protocol* %2, %swift.protocol* %3) // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null // CHECK: br i1 [[IS_NULL]], label %fail, label %cont diff --git a/test/IRGen/default_function_ir_attributes.swift b/test/IRGen/default_function_ir_attributes.swift new file mode 100644 index 0000000000000..e41e97be4acc5 --- /dev/null +++ b/test/IRGen/default_function_ir_attributes.swift @@ -0,0 +1,175 @@ +// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK-%target-runtime --check-prefix=CHECK -DINT=i%target-ptrsize + +protocol P0 {} +protocol P1 {} +struct P0Conformer: P0, Hashable {} +protocol CP0 : AnyObject {} +protocol CP1 : AnyObject {} +class C {} + +struct S { + var stored: Int + var computed: Int { + get { stored } + set {} + } + subscript(t: T) -> Int { + get { 0 } + set {} + } +} + +enum SinglePayloadEnum { + case value(T) + case different + case otherwise +} + +struct OutlinedOperations { + var first: T + var second: T + var third: T + var fourth: T +} +struct StructHoldingOutlined { + var outlined: OutlinedOperations + var element: T +} + +// main +// CHECK-LABEL: define {{.*}} @main( +// CHECK-SAME: [[ATTRS_SIMPLE:#[0-9]+]] + +// class deinit +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes1CCfd"( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// outlined operation +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes18OutlinedOperationsVyxGlWOc"( +// CHECK-SAME: [[ATTRS_NOINLINE_NOUNWIND:#[0-9]+]] + +// normal function +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes3fooyyF"( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +func foo() {} + +// helper function: __swift_instantiateConcreteTypeFromMangledName +// CHECK-LABEL: define {{.*}} @__swift_instantiateConcreteTypeFromMangledName( +// CHECK-SAME: [[ATTRS_NOINLINE_READNONE_NOUNWIND_NOFRAME:#[0-9]+]] + +func use_metadata() -> Any.Type { + return ((C) -> Int).self +} + +// helper function: dynamic_cast_existential_1_unconditional +// CHECK-LABEL: define {{.*}} @dynamic_cast_existential_1_unconditional( +// CHECK-SAME: [[ATTRS_NOUNWIND:#[0-9]+]] + +func test_class_existential_cast_0(value: AnyObject) -> CP0 { + value as! CP0 +} + +// helper function: dynamic_cast_existential_2_unconditional +// CHECK-LABEL: define {{.*}} @dynamic_cast_existential_2_unconditional( +// CHECK-SAME: [[ATTRS_NOUNWIND]] + +func test_class_existential_cast_1(value: AnyObject) -> CP0 & CP1 { + value as! CP0 & CP1 +} + +// helper function: dynamic_cast_existential_2_conditional +// CHECK-LABEL: define {{.*}} @dynamic_cast_existential_2_conditional( +// CHECK-SAME: [[ATTRS_NOUNWIND]] + +func test_class_existential_cast_2(value: AnyObject) -> (CP0 & CP1)? { + value as? CP0 & CP1 +} + +// helper function: dynamic_cast_existential_1_superclass_unconditional +// CHECK-LABEL: define {{.*}} @dynamic_cast_existential_1_superclass_unconditional( +// CHECK-SAME: [[ATTRS_NOUNWIND]] + +func test_class_existential_cast_3(value: AnyObject) -> C & CP0 { + value as! C & CP0 +} + +// metadata accessor +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes1CCMa"( +// CHECK-SAME: [[ATTRS_NOINLINE_READNONE_NOUNWIND_NOFRAME]] + +// helper function: dynamic_cast_existential_1_superclass_conditional +// CHECK-LABEL: define {{.*}} @dynamic_cast_existential_1_superclass_conditional( +// CHECK-SAME: [[ATTRS_NOUNWIND]] + +func test_class_existential_cast_4(value: AnyObject) -> (C & CP0)? { + value as? C & CP0 +} + +// helper function: SIL-generated key path getter +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes1SV8computedSivpACTK"( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: SIL-generated key path setter +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes1SV8computedSivpACTk"( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +func test_computed_key_path_sil_thunks() -> KeyPath { + \S.computed +} + +// helper function: IR-generated key path getter +// CHECK-LABEL: define {{.*}} @keypath_get( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path setter +// CHECK-LABEL: define {{.*}} @keypath_set( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path arg layout accessor +// CHECK-LABEL: define {{.*}} @keypath_get_arg_layout( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path destroy function +// CHECK-LABEL: define {{.*}} @keypath_destroy( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path copy function +// CHECK-LABEL: define {{.*}} @keypath_copy( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path equals function +// CHECK-LABEL: define {{.*}} @keypath_equals( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path hash function +// CHECK-LABEL: define {{.*}} @keypath_hash( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path argument initializer +// CHECK-LABEL: define {{.*}} @keypath_arg_init( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +func test_computed_key_path_generic_thunks(value: T) -> KeyPath { + return \S[value] +} + +// helper function: __swift_get_extra_inhabitant_index( +// CHECK-LABEL: define {{.*}} @__swift_get_extra_inhabitant_index( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: __swift_store_extra_inhabitant_index( +// CHECK-LABEL: define {{.*}} @__swift_store_extra_inhabitant_index( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: __swift_instantiateGenericMetadata +// CHECK-LABEL: define {{.*}} @__swift_instantiateGenericMetadata( +// CHECK-SAME: [[ATTRS_NOINLINE_READNONE_NOUNWIND_NOFRAME]] + +// Use the presence of a target-cpu attribute as a litmus for +// whether constructInitialAttributes was called, since it's very +// unlikely that handrolled code generation would think to add one. +// CHECK: attributes [[ATTRS_SIMPLE]] = { [[CUSTOM_ATTRS:.*target-cpu.*]] }{{$}} +// CHECK-DAG: attributes [[ATTRS_NOINLINE_NOUNWIND]] = { noinline nounwind {{.*target-cpu.*}} } +// CHECK-DAG: attributes [[ATTRS_NOINLINE_READNONE_NOUNWIND_NOFRAME]] = { noinline nounwind readnone {{.*}}"frame-pointer"="none"{{.*target-cpu.*}} } +// CHECK-DAG: attributes [[ATTRS_NOUNWIND]] = { nounwind [[CUSTOM_ATTRS]] }{{$}} diff --git a/test/IRGen/keypaths_objc.sil b/test/IRGen/keypaths_objc.sil index 91c31c8055139..4e8cb200f4e6f 100644 --- a/test/IRGen/keypaths_objc.sil +++ b/test/IRGen/keypaths_objc.sil @@ -45,7 +45,7 @@ entry(%0 : $@objc_metatype C.Type): unreachable } -// CHECK: define private i8* [[SELECTOR_FN]] +// CHECK: define linkonce_odr hidden i8* [[SELECTOR_FN]] // CHECK-NEXT: entry: // CHECK-NEXT: %1 = load {{.*}}selector(x) // CHECK-NEXT: ret i8* %1 diff --git a/test/IRGen/subclass_existentials.sil b/test/IRGen/subclass_existentials.sil index 28295cc27dfa1..efbea61883f6b 100644 --- a/test/IRGen/subclass_existentials.sil +++ b/test/IRGen/subclass_existentials.sil @@ -109,7 +109,7 @@ bb0(%0 : @owned $C, %1 : @owned $C & P): return %result : $() } -// CHECK-LABEL: define private { i8*, i8** } @dynamic_cast_existential_1_superclass_unconditional(i8* %0, %swift.type* %1, %swift.type* +// CHECK-LABEL: define linkonce_odr hidden { i8*, i8** } @dynamic_cast_existential_1_superclass_unconditional(i8* %0, %swift.type* %1, %swift.type* // CHECK: entry: // CHECK-NEXT: [[RESULT:%.*]] = call %swift.type* @swift_dynamicCastMetatype(%swift.type* %1, %swift.type* %2) // CHECK-NEXT: [[IS_SUBCLASS:%.*]] = icmp ne %swift.type* [[RESULT]], null @@ -150,7 +150,7 @@ bb0(%0 : @owned $C): return %result : $() } -// CHECK-LABEL: define private { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* %0, %swift.type* +// CHECK-LABEL: define linkonce_odr hidden { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* %0, %swift.type* // CHECK: entry: // CHECK-NEXT: [[WTABLE:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, {{.*}} %2) // CHECK-NEXT: [[IS_NOT_CONFORMING:%.*]] = icmp eq i8** [[WTABLE]], null diff --git a/test/Serialization/autolinking.swift b/test/Serialization/autolinking.swift index 864bd8db62caf..fac766f844928 100644 --- a/test/Serialization/autolinking.swift +++ b/test/Serialization/autolinking.swift @@ -40,10 +40,10 @@ import someModule // NO-FORCE-LOAD-NOT: FORCE_LOAD // NO-FORCE-LOAD-NOT -lmodule // NO-FORCE-LOAD-NOT -lmagic -// FORCE-LOAD: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$_module"() {{(comdat )?}}{ +// FORCE-LOAD: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$_module"() {{(comdat )?(#[0-9]+ )?}}{ // FORCE-LOAD: ret void // FORCE-LOAD: } -// FORCE-LOAD-HEX: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$306d6f64756c65"() {{(comdat )?}}{ +// FORCE-LOAD-HEX: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$306d6f64756c65"() {{(comdat )?(#[0-9]+ )?}}{ // FORCE-LOAD-HEX: ret void // FORCE-LOAD-HEX: } From d01fed28de7980a9cf15f982d93094df6c5f610e Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Sat, 8 Aug 2020 20:13:13 -0300 Subject: [PATCH 084/123] [Sema] Implement tailored diagnostics for MissingMemberFailure with subscripts on tuple base types --- include/swift/AST/DiagnosticsSema.def | 8 ++++++ lib/Sema/CSDiagnostics.cpp | 39 +++++++++++++++++++++++++++ lib/Sema/CSDiagnostics.h | 8 ++++++ 3 files changed, 55 insertions(+) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 67d2f281c6ed0..e94ab432cc5a4 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -88,6 +88,14 @@ ERROR(could_not_find_subscript_member_did_you_mean,none, "did you mean to use the subscript operator?", (Type)) +ERROR(could_not_find_subscript_member_tuple, none, + "tuple type %0 element cannot be accessed using subscript", + (Type)) +ERROR(could_not_find_subscript_member_tuple_did_you_mean_use_dot, none, + "tuple type %0 element cannot be accessed using subscript; " + "did you mean to use '.' to access element?", + (Type)) + ERROR(could_not_find_enum_case,none, "enum type %0 has no case %1; did you mean %2?", (Type, DeclNameRef, DeclName)) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 64e41d6f52d71..c29c677b76d9c 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3212,6 +3212,9 @@ bool MissingMemberFailure::diagnoseAsError() { if (diagnoseInLiteralCollectionContext()) return true; + if (diagnoseForSubscriptMemberWithTupleBase()) + return true; + auto baseType = resolveType(getBaseType())->getWithoutSpecifierType(); DeclNameLoc nameLoc(::getLoc(anchor)); @@ -3428,6 +3431,42 @@ bool MissingMemberFailure::diagnoseInLiteralCollectionContext() const { return false; } +bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { + auto locator = getLocator(); + auto baseType = resolveType(getBaseType())->getWithoutSpecifierType(); + + if (!locator->isLastElement()) + return false; + + auto tupleType = baseType->getAs(); + // For non-tuple type or empty tuples, let's fallback to the general + // diagnostic logic. + if (!tupleType || tupleType->getNumElements() == 0) + return false; + + auto *SE = castToExpr(locator->getAnchor()); + auto *index = SE->getIndex(); + + if (SE->getNumArguments() == 1) { + auto *literal = + dyn_cast(index->getSemanticsProvidingExpr()); + if (literal && !literal->isNegative()) { + llvm::SmallString<4> dotAccess; + llvm::raw_svector_ostream OS(dotAccess); + OS << "." << literal->getDigitsText(); + + emitDiagnostic( + diag::could_not_find_subscript_member_tuple_did_you_mean_use_dot, + baseType) + .fixItReplace(index->getSourceRange(), OS.str()); + return true; + } + } + + emitDiagnostic(diag::could_not_find_subscript_member_tuple, baseType); + return true; +} + bool UnintendedExtraGenericParamMemberFailure::diagnoseAsError() { MissingMemberFailure::diagnoseAsError(); diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 4a5505a69a634..bd8803ddc573a 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -1075,6 +1075,14 @@ class MissingMemberFailure : public InvalidMemberRefFailure { /// that defaults the element type. e.g. _ = [.e] bool diagnoseInLiteralCollectionContext() const; + /// Tailored diagnostics for missing subscript member on a tuple base type. + /// e.g + /// ```swift + /// let tuple: (Int, Int) = (0, 0) + /// _ = tuple[0] + /// ``` + bool diagnoseForSubscriptMemberWithTupleBase() const; + static DeclName findCorrectEnumCaseName(Type Ty, TypoCorrectionResults &corrections, DeclNameRef memberName); From 0d5bfcbe01e8b0358f3e1cd87ce7b59e6ce986da Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Sat, 8 Aug 2020 21:41:31 -0300 Subject: [PATCH 085/123] [tests] Adding regression tests for SR-13359 --- test/Constraints/members.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index 3f35c02bf6b01..3064531aedf29 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -674,3 +674,18 @@ _ = [.e: 1] // expected-error {{reference to member 'e' cannot be resolved witho let _ : [Int: Any] = [1 : .e] // expected-error {{type 'Any' has no member 'e'}} let _ : (Int, Any) = (1, .e) // expected-error {{type 'Any' has no member 'e'}} _ = (1, .e) // expected-error {{cannot infer contextual base in reference to member 'e'}} + +// SR-13359 +typealias Pair = (Int, Int) +func testSR13359(_ pair: (Int, Int), _ alias: Pair, _ void: Void) { + _ = pair[0] // expected-error {{tuple type '(Int, Int)' element cannot be accessed using subscript; did you mean to use '.' to access element?}} {{11-14=.0}} + _ = pair["strting"] // expected-error {{tuple type '(Int, Int)' element cannot be accessed using subscript}} {{none}} + _ = pair[-1] // expected-error {{tuple type '(Int, Int)' element cannot be accessed using subscript}} {{none}} + _ = pair[1, 1] // expected-error {{tuple type '(Int, Int)' element cannot be accessed using subscript}} {{none}} + _ = void[0] // expected-error {{value of type 'Void' has no subscripts}} + + _ = alias[0] // expected-error {{tuple type 'Pair' (aka '(Int, Int)') element cannot be accessed using subscript; did you mean to use '.' to access element?}} {{12-15=.0}} + _ = alias["strting"] // expected-error {{tuple type 'Pair' (aka '(Int, Int)') element cannot be accessed using subscript}} {{none}} + _ = alias[-1] // expected-error {{tuple type 'Pair' (aka '(Int, Int)') element cannot be accessed using subscript}} {{none}} + _ = alias[1, 1] // expected-error {{tuple type 'Pair' (aka '(Int, Int)') element cannot be accessed using subscript}} {{none}} +} From 8431158e38c27e8934e2a66b4d9f9536d19078e4 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Sun, 9 Aug 2020 00:56:27 +0000 Subject: [PATCH 086/123] [AutoDiff] Temporarily disable failing test on tensorflow branch. --- test/AutoDiff/validation-test/optional.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/AutoDiff/validation-test/optional.swift b/test/AutoDiff/validation-test/optional.swift index c2fc0fac4a695..385d65c3c6d3c 100644 --- a/test/AutoDiff/validation-test/optional.swift +++ b/test/AutoDiff/validation-test/optional.swift @@ -1,6 +1,11 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test +// SWIFT_ENABLE_TENSORFLOW +// FIXME: This test currently crashes on tensorflow branch only, not master branch. +// XFAIL: * +// SWIFT_ENABLE_TENSORFLOW END + import StdlibUnittest import DifferentiationUnittest From 061e69bcc22b959d5afd9bf24f807ce96bd1f948 Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Sun, 9 Aug 2020 02:10:06 -0300 Subject: [PATCH 087/123] [Diagnostics] Adjusting SR-13359 diagnostic wording and add tests for labeled tuples --- include/swift/AST/DiagnosticsSema.def | 9 ++++----- lib/Sema/CSDiagnostics.cpp | 2 +- test/Constraints/members.swift | 24 +++++++++++++++--------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index e94ab432cc5a4..4e4632d2df4c4 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -89,12 +89,11 @@ ERROR(could_not_find_subscript_member_did_you_mean,none, (Type)) ERROR(could_not_find_subscript_member_tuple, none, - "tuple type %0 element cannot be accessed using subscript", - (Type)) + "cannot access element using subscript for tuple type %0; " + "use '.' notation instead", (Type)) ERROR(could_not_find_subscript_member_tuple_did_you_mean_use_dot, none, - "tuple type %0 element cannot be accessed using subscript; " - "did you mean to use '.' to access element?", - (Type)) + "cannot access element using subscript for tuple type %0; " + "did you mean to use '.%1'?", (Type, StringRef)) ERROR(could_not_find_enum_case,none, "enum type %0 has no case %1; did you mean %2?", diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index c29c677b76d9c..254fb7eb63612 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3457,7 +3457,7 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { emitDiagnostic( diag::could_not_find_subscript_member_tuple_did_you_mean_use_dot, - baseType) + baseType, literal->getDigitsText()) .fixItReplace(index->getSourceRange(), OS.str()); return true; } diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index 3064531aedf29..0df469778fd5c 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -677,15 +677,21 @@ _ = (1, .e) // expected-error {{cannot infer contextual base in reference to mem // SR-13359 typealias Pair = (Int, Int) -func testSR13359(_ pair: (Int, Int), _ alias: Pair, _ void: Void) { - _ = pair[0] // expected-error {{tuple type '(Int, Int)' element cannot be accessed using subscript; did you mean to use '.' to access element?}} {{11-14=.0}} - _ = pair["strting"] // expected-error {{tuple type '(Int, Int)' element cannot be accessed using subscript}} {{none}} - _ = pair[-1] // expected-error {{tuple type '(Int, Int)' element cannot be accessed using subscript}} {{none}} - _ = pair[1, 1] // expected-error {{tuple type '(Int, Int)' element cannot be accessed using subscript}} {{none}} +func testSR13359(_ pair: (Int, Int), _ alias: Pair, _ void: Void, labeled: (a: Int, b: Int)) { + _ = pair[0] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; did you mean to use '.0'?}} {{11-14=.0}} + _ = pair["strting"] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + _ = pair[-1] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + _ = pair[1, 1] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} _ = void[0] // expected-error {{value of type 'Void' has no subscripts}} - _ = alias[0] // expected-error {{tuple type 'Pair' (aka '(Int, Int)') element cannot be accessed using subscript; did you mean to use '.' to access element?}} {{12-15=.0}} - _ = alias["strting"] // expected-error {{tuple type 'Pair' (aka '(Int, Int)') element cannot be accessed using subscript}} {{none}} - _ = alias[-1] // expected-error {{tuple type 'Pair' (aka '(Int, Int)') element cannot be accessed using subscript}} {{none}} - _ = alias[1, 1] // expected-error {{tuple type 'Pair' (aka '(Int, Int)') element cannot be accessed using subscript}} {{none}} + _ = alias[0] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); did you mean to use '.0'?}} {{12-15=.0}} + _ = alias["strting"] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias[-1] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias[1, 1] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + + // Labeled tuple base + _ = labeled[0] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; did you mean to use '.0'?}} {{14-17=.0}} + _ = labeled["strting"] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[-1] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[1, 1] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} } From 72e6bbca9a7c95e329d4b6a1eca3f840f3b38290 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Sun, 9 Aug 2020 10:52:44 -0700 Subject: [PATCH 088/123] test: repair Serialization.autolinking after #33379 The order of attribution was swapped which failed on platforms which use `comdat` (i.e. Windows). --- test/Serialization/autolinking.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Serialization/autolinking.swift b/test/Serialization/autolinking.swift index fac766f844928..d30ae2e28826b 100644 --- a/test/Serialization/autolinking.swift +++ b/test/Serialization/autolinking.swift @@ -40,10 +40,10 @@ import someModule // NO-FORCE-LOAD-NOT: FORCE_LOAD // NO-FORCE-LOAD-NOT -lmodule // NO-FORCE-LOAD-NOT -lmagic -// FORCE-LOAD: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$_module"() {{(comdat )?(#[0-9]+ )?}}{ +// FORCE-LOAD: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$_module"() {{(#[0-9]+)?( comdat)?}} { // FORCE-LOAD: ret void // FORCE-LOAD: } -// FORCE-LOAD-HEX: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$306d6f64756c65"() {{(comdat )?(#[0-9]+ )?}}{ +// FORCE-LOAD-HEX: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$306d6f64756c65"() {{(#[0-9]+)?( comdat)?}} { // FORCE-LOAD-HEX: ret void // FORCE-LOAD-HEX: } From a3b801408b1292168472047e47c1da705ab47182 Mon Sep 17 00:00:00 2001 From: HassanElDesouky Date: Thu, 6 Aug 2020 21:13:19 +0200 Subject: [PATCH 089/123] [Localization] Make the serialization tool print the removed diagnostics --- include/swift/AST/LocalizationFormat.h | 17 +++++- lib/AST/LocalizationFormat.cpp | 58 ++++++++++--------- test/diagnostics/Localization/Inputs/en.yaml | 14 ++++- .../Localization/fr_localization.swift | 3 +- .../swift-serialize-diagnostics.cpp | 11 ++++ 5 files changed, 73 insertions(+), 30 deletions(-) diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/AST/LocalizationFormat.h index 0b0c524eef2d0..efd3d5345467f 100644 --- a/include/swift/AST/LocalizationFormat.h +++ b/include/swift/AST/LocalizationFormat.h @@ -18,6 +18,7 @@ #define SWIFT_LOCALIZATIONFORMAT_H #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitstreamReader.h" @@ -38,6 +39,7 @@ namespace swift { enum class DiagID : uint32_t; namespace diag { + using namespace llvm::support; class LocalizationWriterInfo { @@ -152,6 +154,8 @@ class YAMLLocalizationProducer final : public LocalizationProducer { std::vector diagnostics; public: + /// The diagnostics IDs that are no longer available in `.def` + std::vector unknownIDs; explicit YAMLLocalizationProducer(llvm::StringRef filePath); llvm::StringRef getMessageOr(swift::DiagID id, llvm::StringRef defaultMessage) const override; @@ -185,12 +189,23 @@ class LocalizationInput : public llvm::yaml::Input { template friend typename std::enable_if::value, void>::type - readYAML(llvm::yaml::IO &io, T &Seq, bool, Context &Ctx); + readYAML(llvm::yaml::IO &io, T &Seq, T &unknownIDs, bool, Context &Ctx); template friend typename std::enable_if::value, LocalizationInput &>::type operator>>(LocalizationInput &yin, T &diagnostics); + +public: + /// A vector that keeps track of the diagnostics IDs that are available in + /// YAML and not available in `.def` files. + std::vector unknownIDs; + + /// A diagnostic ID might be present in YAML and not in `.def` file, if that's + /// the case the `id` won't have a `DiagID` value. + /// If the `id` is available in `.def` file this method will return the `id`'s + /// value, otherwise this method won't return a value. + static llvm::Optional readID(llvm::yaml::IO &io); }; } // namespace diag diff --git a/lib/AST/LocalizationFormat.cpp b/lib/AST/LocalizationFormat.cpp index 4c8ead4d9729a..5bc4f46cf5e64 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/AST/LocalizationFormat.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "swift/AST/LocalizationFormat.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitstreamReader.h" @@ -28,16 +29,13 @@ #include namespace { + enum LocalDiagID : uint32_t { #define DIAG(KIND, ID, Options, Text, Signature) ID, #include "swift/AST/DiagnosticsAll.def" NumDiags }; -struct DiagnosticNode { - uint32_t id; - std::string msg; -}; } // namespace namespace llvm { @@ -55,15 +53,6 @@ template <> struct ScalarEnumerationTraits { } }; -template <> struct MappingTraits { - static void mapping(IO &io, DiagnosticNode &node) { - LocalDiagID diagID; - io.mapRequired("id", diagID); - io.mapRequired("msg", node.msg); - node.id = static_cast(diagID); - } -}; - } // namespace yaml } // namespace llvm @@ -121,6 +110,7 @@ YAMLLocalizationProducer::YAMLLocalizationProducer(llvm::StringRef filePath) { llvm::MemoryBuffer *document = FileBufOrErr->get(); diag::LocalizationInput yin(document->getBuffer()); yin >> diagnostics; + unknownIDs = std::move(yin.unknownIDs); } llvm::StringRef @@ -143,31 +133,45 @@ void YAMLLocalizationProducer::forEachAvailable( } } +llvm::Optional LocalizationInput::readID(llvm::yaml::IO &io) { + LocalDiagID diagID; + io.mapRequired("id", diagID); + if (diagID == LocalDiagID::NumDiags) + return llvm::None; + return static_cast(diagID); +} + template typename std::enable_if::value, void>::type -readYAML(llvm::yaml::IO &io, T &Seq, bool, Context &Ctx) { +readYAML(llvm::yaml::IO &io, T &Seq, T &unknownIDs, bool, Context &Ctx) { unsigned count = io.beginSequence(); - if (count) + if (count) { Seq.resize(LocalDiagID::NumDiags); + } + for (unsigned i = 0; i < count; ++i) { void *SaveInfo; if (io.preflightElement(i, SaveInfo)) { - DiagnosticNode current; - yamlize(io, current, true, Ctx); - io.postflightElement(SaveInfo); + io.beginMapping(); - // A diagnostic ID might be present in YAML and not in `.def` file, - // if that's the case ScalarEnumerationTraits will assign the diagnostic ID - // to `LocalDiagID::NumDiags`. Since the diagnostic ID isn't available - // in `.def` it shouldn't be stored in the diagnostics array. - if (current.id != LocalDiagID::NumDiags) { + // If the current diagnostic ID is available in YAML and in `.def`, add it + // to the diagnostics array. Otherwise, re-parse the current diagnnostic + // id as a string and store it in `unknownIDs` array. + if (auto id = LocalizationInput::readID(io)) { // YAML file isn't guaranteed to have diagnostics in order of their // declaration in `.def` files, to accommodate that we need to leave // holes in diagnostic array for diagnostics which haven't yet been - // localized and for the ones that have `DiagnosticNode::id` - // indicates their position. - Seq[static_cast(current.id)] = std::move(current.msg); + // localized and for the ones that have `id` indicates their position. + io.mapRequired("msg", Seq[*id]); + } else { + std::string unknownID, message; + // Read "raw" id since it doesn't exist in `.def` file. + io.mapRequired("id", unknownID); + io.mapRequired("msg", message); + unknownIDs.push_back(unknownID); } + io.endMapping(); + io.postflightElement(SaveInfo); } } io.endSequence(); @@ -181,7 +185,7 @@ operator>>(LocalizationInput &yin, T &diagnostics) { if (yin.setCurrentDocument()) { // If YAML file's format doesn't match the current format in // DiagnosticMessageFormat, will throw an error. - readYAML(yin, diagnostics, true, Ctx); + readYAML(yin, diagnostics, yin.unknownIDs, true, Ctx); } return yin; } diff --git a/test/diagnostics/Localization/Inputs/en.yaml b/test/diagnostics/Localization/Inputs/en.yaml index f84a604333226..b55d4f55cf88a 100644 --- a/test/diagnostics/Localization/Inputs/en.yaml +++ b/test/diagnostics/Localization/Inputs/en.yaml @@ -22,12 +22,24 @@ - id: "lex_unterminated_string" msg: "unterminated string literal" - + +- id: "not_available_in_def_2" + msg: "Shouldn't be produced" + - id: "var_init_self_referential" msg: "variable used within its own initial value" - id: "cannot_find_in_scope" msg: "cannot %select{find|find operator}1 %0 in scope" +- id: "not_available_in_def_3" + msg: "Shouldn't be produced" + - id: "warning_invalid_locale_code" msg: "unsupported locale code; supported locale codes are '%0'" + +- id: "not_available_in_def_4" + msg: "Shouldn't be produced" + +- id: "not_available_in_def_5" + msg: "Shouldn't be produced" diff --git a/test/diagnostics/Localization/fr_localization.swift b/test/diagnostics/Localization/fr_localization.swift index 27d8e29f8cda9..9caf88a529e37 100644 --- a/test/diagnostics/Localization/fr_localization.swift +++ b/test/diagnostics/Localization/fr_localization.swift @@ -1,8 +1,9 @@ // RUN: %empty-directory(%t) // RUN: swift-serialize-diagnostics --input-file-path=%S/Inputs/fr.yaml --output-directory=%t/ -// RUN: swift-serialize-diagnostics --input-file-path=%S/Inputs/en.yaml --output-directory=%t/ +// RUN: swift-serialize-diagnostics --input-file-path=%S/Inputs/en.yaml --output-directory=%t/ 2>&1 | %FileCheck %s // RUN: %target-typecheck-verify-swift -localization-path %t -locale fr +// CHECK: These diagnostic IDs are no longer availiable: 'not_available_in_def, not_available_in_def_2, not_available_in_def_3, not_available_in_def_4, not_available_in_def_5' _ = "HI! // expected-error@-1{{chaîne non terminée littérale}} var self1 = self1 // expected-error {{variable utilisée dans sa propre valeur initiale}} diff --git a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp index 14bda88c7a7f3..01ea696002637 100644 --- a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp +++ b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp @@ -16,6 +16,7 @@ #include "swift/AST/LocalizationFormat.h" #include "swift/Basic/LLVMInitialize.h" +#include "swift/Basic/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" @@ -82,5 +83,15 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } + // Print out the diagnostics IDs that are available in YAML but not available + // in `.def` + if (!yaml.unknownIDs.empty()) { + llvm::errs() << "These diagnostic IDs are no longer availiable: '"; + llvm::interleave( + yaml.unknownIDs, [&](std::string id) { llvm::errs() << id; }, + [&] { llvm::errs() << ", "; }); + llvm::errs() << "'\n"; + } + return EXIT_SUCCESS; } From b37491ad62dec2e2760fee5a37d6f11c6347aa56 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 17 Jul 2020 08:33:11 +0300 Subject: [PATCH 090/123] AssociatedTypeInference: Stop skipping the current protocol when looking for a fixed type witness --- lib/Sema/TypeCheckProtocolInference.cpp | 3 ++- test/IDE/complete_opaque_result.swift | 2 +- .../associated_type_inference_fixed_type.swift | 18 +++++++----------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index fe1066c5d534e..21fe9d350ff71 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -807,7 +807,8 @@ Type AssociatedTypeInference::computeFixedTypeWitness( // require a fixed type for this associated type. Type resultType; for (auto conformedProto : adoptee->getAnyNominal()->getAllProtocols()) { - if (!conformedProto->inheritsFrom(assocType->getProtocol())) + if (conformedProto != assocType->getProtocol() && + !conformedProto->inheritsFrom(assocType->getProtocol())) continue; const auto genericSig = conformedProto->getGenericSignature(); diff --git a/test/IDE/complete_opaque_result.swift b/test/IDE/complete_opaque_result.swift index 03a95395d1276..a760894b6828f 100644 --- a/test/IDE/complete_opaque_result.swift +++ b/test/IDE/complete_opaque_result.swift @@ -143,7 +143,7 @@ class TestClass : // OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConstraintAndDefault() -> ConcreteMyProtocol {|}; // OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithAnyObjectConstraint() -> some MyProtocol & AnyObject {|} // OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConstraintOnProto() -> some MyProtocol {|} -// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithSameTypeConstraint() -> AssocWithSameTypeConstraint {|} +// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithSameTypeConstraint() -> ConcreteMyProtocol {|} // OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConformanceConstraintGeneric(arg: T) -> AssocWithConformanceConstraintGeneric {|} // OVERRIDE: End completions } diff --git a/test/decl/protocol/req/associated_type_inference_fixed_type.swift b/test/decl/protocol/req/associated_type_inference_fixed_type.swift index 4b8f6c99b3289..67b4de6b4511b 100644 --- a/test/decl/protocol/req/associated_type_inference_fixed_type.swift +++ b/test/decl/protocol/req/associated_type_inference_fixed_type.swift @@ -1,10 +1,9 @@ // RUN: %target-typecheck-verify-swift protocol P1 where A == Never { - associatedtype A // expected-note {{protocol requires nested type 'A'}} + associatedtype A } -// FIXME: Should this infer A := Never? -struct S1: P1 {} // expected-error {{type 'S1' does not conform to protocol 'P1'}} +struct S1: P1 {} // OK, A := Never protocol P2a { associatedtype A @@ -54,22 +53,19 @@ protocol P7b: P7a where A == Bool {} struct S7: P7b {} protocol P8 where A == Bool { - associatedtype A // expected-note {{protocol requires nested type 'A'}} + associatedtype A } -// expected-error@+2 {{type 'S8' does not conform to protocol 'P7a'}} -// expected-error@+1 {{type 'S8' does not conform to protocol 'P8'}} +// expected-error@+2 {{'P7a' requires the types 'S8.A' (aka 'Bool') and 'Never' be equivalent}} +// expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S8]}} struct S8: P8, P7a {} protocol P9a where A == Never { associatedtype A } protocol P9b: P9a { - associatedtype A // expected-note {{protocol requires nested type 'A'}} + associatedtype A } -// FIXME: Associated type restatement sabotages the conformance. -// expected-error@+2 {{type 'S9a' does not conform to protocol 'P9a'}} -// expected-error@+1 {{type 'S9a' does not conform to protocol 'P9b'}} -struct S9a: P9b {} +struct S9a: P9b {} // OK, A := Never // expected-error@+2 {{'P9a' requires the types 'S9b.A' (aka 'Bool') and 'Never' be equivalent}} // expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S9b]}} struct S9b: P9b { From 82fe84a85a65de82cbc6d19c41576a1de16ae698 Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Sun, 9 Aug 2020 22:33:35 -0300 Subject: [PATCH 091/123] [Diagnostics] Restricting member subscript tailored diagnostics to literal within bounds of tuple elements --- lib/Sema/CSDiagnostics.cpp | 30 +++++++++++++++++++++--------- test/Constraints/members.swift | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 254fb7eb63612..de243c4cdd6a4 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3450,16 +3450,28 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { if (SE->getNumArguments() == 1) { auto *literal = dyn_cast(index->getSemanticsProvidingExpr()); - if (literal && !literal->isNegative()) { - llvm::SmallString<4> dotAccess; - llvm::raw_svector_ostream OS(dotAccess); - OS << "." << literal->getDigitsText(); - emitDiagnostic( - diag::could_not_find_subscript_member_tuple_did_you_mean_use_dot, - baseType, literal->getDigitsText()) - .fixItReplace(index->getSourceRange(), OS.str()); - return true; + llvm::Regex NumericRegex("^[0-9]+$"); + // Literal expressions may have other types of representations e.g. 0x01, + // 0b01. So let's make sure to only suggest this tailored literal fix-it for + // number only literals. + if (literal && NumericRegex.match(literal->getDigitsText())) { + unsigned int literalValue = 0; + literal->getDigitsText().getAsInteger(/*Radix*/ 0, literalValue); + + // Verify if the literal value is within the bounds of tuple elements. + if (!literal->isNegative() && + literalValue < tupleType->getNumElements()) { + llvm::SmallString<4> dotAccess; + llvm::raw_svector_ostream OS(dotAccess); + OS << "." << literalValue; + + emitDiagnostic( + diag::could_not_find_subscript_member_tuple_did_you_mean_use_dot, + baseType, literal->getDigitsText()) + .fixItReplace(index->getSourceRange(), OS.str()); + return true; + } } } diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index 0df469778fd5c..9d186dc72401c 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -675,23 +675,42 @@ let _ : [Int: Any] = [1 : .e] // expected-error {{type 'Any' has no member 'e'}} let _ : (Int, Any) = (1, .e) // expected-error {{type 'Any' has no member 'e'}} _ = (1, .e) // expected-error {{cannot infer contextual base in reference to member 'e'}} +// SR-13359 + // SR-13359 typealias Pair = (Int, Int) func testSR13359(_ pair: (Int, Int), _ alias: Pair, _ void: Void, labeled: (a: Int, b: Int)) { _ = pair[0] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; did you mean to use '.0'?}} {{11-14=.0}} + _ = pair[1] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; did you mean to use '.1'?}} {{11-14=.1}} + _ = pair[2] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + _ = pair[100] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} _ = pair["strting"] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} _ = pair[-1] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} _ = pair[1, 1] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} _ = void[0] // expected-error {{value of type 'Void' has no subscripts}} + // Other representations of literals + _ = pair[0x00] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + _ = pair[0b00] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} _ = alias[0] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); did you mean to use '.0'?}} {{12-15=.0}} + _ = alias[1] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); did you mean to use '.1'?}} {{12-15=.1}} + _ = alias[2] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias[100] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} _ = alias["strting"] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} _ = alias[-1] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} _ = alias[1, 1] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias[0x00] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias[0b00] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} // Labeled tuple base _ = labeled[0] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; did you mean to use '.0'?}} {{14-17=.0}} + _ = labeled[1] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; did you mean to use '.1'?}} {{14-17=.1}} + _ = labeled[2] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[100] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} _ = labeled["strting"] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} _ = labeled[-1] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} _ = labeled[1, 1] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[0x00] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[0b00] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + } From e8f17848585ee3ac6f3f6b5892dbda2429349e65 Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Sun, 9 Aug 2020 23:01:49 -0300 Subject: [PATCH 092/123] [Diagnostics] Adding member subscript tailored diagnostics fixit to string literals that matches a label of labeled tuples --- lib/Sema/CSDiagnostics.cpp | 23 ++++++++++++++++++++++- test/Constraints/members.swift | 8 ++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index de243c4cdd6a4..b1614a91bfe7b 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3457,7 +3457,7 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { // number only literals. if (literal && NumericRegex.match(literal->getDigitsText())) { unsigned int literalValue = 0; - literal->getDigitsText().getAsInteger(/*Radix*/ 0, literalValue); + literal->getDigitsText().getAsInteger(/*Radix=*/0, literalValue); // Verify if the literal value is within the bounds of tuple elements. if (!literal->isNegative() && @@ -3473,6 +3473,27 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { return true; } } + + // For subscript access on tuple base types where the subscript index is a + // string literal expression which value matches a tuple element label, + // let's suggest tuple label access. + auto stringLiteral = + dyn_cast(index->getSemanticsProvidingExpr()); + if (stringLiteral && !stringLiteral->getValue().empty() && + llvm::any_of(tupleType->getElements(), [&](TupleTypeElt element) { + return !element.getName().empty() && + element.getName().str() == stringLiteral->getValue(); + })) { + llvm::SmallString<16> dotAccess; + llvm::raw_svector_ostream OS(dotAccess); + OS << "." << stringLiteral->getValue(); + + emitDiagnostic( + diag::could_not_find_subscript_member_tuple_did_you_mean_use_dot, + baseType, stringLiteral->getValue()) + .fixItReplace(index->getSourceRange(), OS.str()); + return true; + } } emitDiagnostic(diag::could_not_find_subscript_member_tuple, baseType); diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index 9d186dc72401c..55ada2a99b4a6 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -675,8 +675,6 @@ let _ : [Int: Any] = [1 : .e] // expected-error {{type 'Any' has no member 'e'}} let _ : (Int, Any) = (1, .e) // expected-error {{type 'Any' has no member 'e'}} _ = (1, .e) // expected-error {{cannot infer contextual base in reference to member 'e'}} -// SR-13359 - // SR-13359 typealias Pair = (Int, Int) func testSR13359(_ pair: (Int, Int), _ alias: Pair, _ void: Void, labeled: (a: Int, b: Int)) { @@ -713,4 +711,10 @@ func testSR13359(_ pair: (Int, Int), _ alias: Pair, _ void: Void, labeled: (a: I _ = labeled[0x00] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} _ = labeled[0b00] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + // Suggesting use label access + _ = labeled["a"] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; did you mean to use '.a'?}} {{14-19=.a}} + _ = labeled["b"] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; did you mean to use '.b'?}} {{14-19=.b}} + _ = labeled["c"] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[""] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + } From 008cc3c2ea2baee91baf275f1cf8e70e7cc61edf Mon Sep 17 00:00:00 2001 From: Marcel Hlopko Date: Mon, 10 Aug 2020 08:50:05 +0200 Subject: [PATCH 093/123] Document conventions for constructing names in mangling docs (#33203) Co-authored-by: Robert Widmann Co-authored-by: Dmitri Gribenko --- docs/ABI/Mangling.rst | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index ee99f99911ba0..a65799b8c53cd 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -1047,3 +1047,63 @@ Some kinds need arguments, which precede ``Tf``. If the first character of the string literal is a digit ``[0-9]`` or an underscore ``_``, the identifier for the string literal is prefixed with an additional underscore ``_``. + +Conventions for foreign symbols +------------------------------- + +Swift interoperates with multiple other languages - C, C++, Objective-C, and +Objective-C++. Each of these languages defines their own mangling conventions, +so Swift must take care to follow them. However, these conventions do not cover +Swift-specific symbols like Swift type metadata for foreign types, so Swift uses +its own mangling scheme for those symbols. + +Importing C and C++ structs +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Types imported from C and C++ are imported as if they are located in the ``__C`` +module, regardless of the actual Clang module that they are coming from. This +can be observed when mangling a Swift function that accepts a C/C++ struct as a +parameter: + +C++ module ``CxxStructModule``: + +.. code-block:: c++ + + struct CxxStruct {}; + + inline void cxxFunction(CxxStruct s) {} + +Swift module ``main`` that imports ``CxxStructModule``: + +.. code-block:: swift + + import CxxStructModule + + public func swiftFunction(_ s: CxxStruct) {} + +Resulting symbols (showing only Itanium-mangled C++ symbols for brevity): + +.. code:: + + _Z11cxxFunction9CxxStruct // -> cxxFunction(CxxStruct) + s4main13swiftFunctionyySo9CxxStructVF // -> main.swiftFunction(__C.CxxStruct) -> () + +The reason for ignoring the Clang module and always putting C and C++ types into +``__C`` at the Swift ABI level is that the Clang module is not a part of the C +or C++ ABI. When owners of C and C++ Clang modules decide what changes are +ABI-compatible or not, they will likely take into account C and C++ ABI, but not +the Swift ABI. Therefore, Swift ABI can only encode information about a C or C++ +type that the C and C++ ABI already encodes in order to remain compatible with +future versions of libraries that evolve according to C and C++ ABI +compatibility principles. + +The C/C++ compiler does not generate Swift metadata symbols and value witness +tables for C and C++ types. To make a foreign type usable in Swift in the same +way as a native type, the Swift compiler must generate these symbols. +Specifically, each Swift module that uses a given C or C++ type generates the +necessary Swift symbols. For the example above the Swift compiler will generate following +nominal type descriptor symbol for ``CxxStruct`` while compiling the ``main`` module: + +.. code:: + + sSo9CxxStructVMn // -> nominal type descriptor for __C.CxxStruct From 038eae48f89c7f37e299092e8810b3933a295c8f Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Mon, 10 Aug 2020 08:40:04 -0300 Subject: [PATCH 094/123] Adding SR-13359 diagnostics to localization yaml files and minor comment --- lib/Sema/CSDiagnostics.h | 2 +- localization/diagnostics/en.yaml | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index bd8803ddc573a..30192dbc20fc4 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -1079,7 +1079,7 @@ class MissingMemberFailure : public InvalidMemberRefFailure { /// e.g /// ```swift /// let tuple: (Int, Int) = (0, 0) - /// _ = tuple[0] + /// _ = tuple[0] // -> tuple.0. /// ``` bool diagnoseForSubscriptMemberWithTupleBase() const; diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index 59f88017ae467..2bfd50fe0cad4 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -2967,6 +2967,16 @@ value of type %0 has no property or method named 'subscript'; did you mean to use the subscript operator? +- id: could_not_find_subscript_member_tuple + msg: >- + cannot access element using subscript for tuple type %0; + use '.' notation instead + +- id: could_not_find_subscript_member_tuple_did_you_mean_use_dot + msg: >- + cannot access element using subscript for tuple type %0; + did you mean to use '.%1'? + - id: could_not_find_enum_case msg: >- enum type %0 has no case %1; did you mean %2? From 792da109251054fa11816329cc2306ee7343c247 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Mon, 10 Aug 2020 15:40:07 +0300 Subject: [PATCH 095/123] Revert "Sema: Make type resolution for EnumElementPattern less eager" --- include/swift/AST/NameLookup.h | 8 ---- lib/AST/NameLookup.cpp | 38 +++++++-------- lib/Sema/CSGen.cpp | 26 ++++++---- lib/Sema/TypeCheckPattern.cpp | 85 ++++++++++++++++----------------- test/Constraints/patterns.swift | 10 ++-- 5 files changed, 80 insertions(+), 87 deletions(-) diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index 57e6c63740d5c..ea847ce01c1ba 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -512,14 +512,6 @@ void recordLookupOfTopLevelName(DeclContext *topLevelContext, DeclName name, } // end namespace namelookup -/// Retrieve the set of nominal type declarations that are directly -/// referenced in the given \c typeRepr, looking through typealiases. -/// -/// \param dc The \c DeclContext from which to perform lookup. -TinyPtrVector -getDirectlyReferencedNominalTypeDecls(ASTContext &ctx, TypeRepr *typeRepr, - DeclContext *dc, bool &anyObject); - /// Retrieve the set of nominal type declarations that are directly /// "inherited" by the given declaration at a particular position in the /// list of "inherited" types. diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index df94b8ea9a972..fdbfb119ebddb 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -861,13 +861,18 @@ SelfBounds SelfBoundsFromWhereClauseRequest::evaluate( continue; // Resolve the right-hand side. - if (auto *const typeRepr = req.getConstraintRepr()) { - const auto rhsNominals = getDirectlyReferencedNominalTypeDecls( - ctx, typeRepr, lookupDC, result.anyObject); - - result.decls.insert(result.decls.end(), rhsNominals.begin(), - rhsNominals.end()); + DirectlyReferencedTypeDecls rhsDecls; + if (auto typeRepr = req.getConstraintRepr()) { + rhsDecls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, lookupDC); } + + SmallVector modulesFound; + auto rhsNominals = resolveTypeDeclsToNominal(evaluator, ctx, rhsDecls, + modulesFound, + result.anyObject); + result.decls.insert(result.decls.end(), + rhsNominals.begin(), + rhsNominals.end()); } return result; @@ -2134,17 +2139,6 @@ static DirectlyReferencedTypeDecls directReferencesForType(Type type) { return { }; } -TinyPtrVector swift::getDirectlyReferencedNominalTypeDecls( - ASTContext &ctx, TypeRepr *typeRepr, DeclContext *dc, bool &anyObject) { - const auto referenced = - directReferencesForTypeRepr(ctx.evaluator, ctx, typeRepr, dc); - - // Resolve those type declarations to nominal type declarations. - SmallVector modulesFound; - return resolveTypeDeclsToNominal(ctx.evaluator, ctx, referenced, modulesFound, - anyObject); -} - DirectlyReferencedTypeDecls InheritedDeclsReferencedRequest::evaluate( Evaluator &evaluator, llvm::PointerUnion decl, @@ -2266,10 +2260,16 @@ ExtendedNominalRequest::evaluate(Evaluator &evaluator, // We must've seen 'extension { ... }' during parsing. return nullptr; + ASTContext &ctx = ext->getASTContext(); + DirectlyReferencedTypeDecls referenced = + directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext->getParent()); + // Resolve those type declarations to nominal type declarations. + SmallVector modulesFound; bool anyObject = false; - const auto nominalTypes = getDirectlyReferencedNominalTypeDecls( - ext->getASTContext(), typeRepr, ext->getParent(), anyObject); + auto nominalTypes + = resolveTypeDeclsToNominal(evaluator, ctx, referenced, modulesFound, + anyObject); // If there is more than 1 element, we will emit a warning or an error // elsewhere, so don't handle that case here. diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 6e91606d735bb..b4f0c1facc721 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2491,23 +2491,31 @@ namespace { if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) { // Resolve the parent type. Type parentType = [&]() -> Type { - if (const auto resolvedTy = enumPattern->getParentType()) { - assert(resolvedTy->hasUnboundGenericType() == false && - "A pre-resolved type must be fully bound"); - return resolvedTy; + if (auto preTy = enumPattern->getParentType()) { + return preTy; } return resolveTypeReferenceInExpression( enumPattern->getParentTypeRepr(), - TypeResolverContext::InExpression, - OpenUnboundGenericType( - CS, CS.getConstraintLocator( - locator, {LocatorPathElt::PatternMatch(pattern), - ConstraintLocator::ParentType}))); + TypeResolverContext::InExpression, [](auto unboundTy) { + // FIXME: We ought to pass an OpenUnboundGenericType object + // rather than calling CS.openUnboundGenericType below, but + // sometimes the parent type is resolved eagerly in + // ResolvePattern::visitUnresolvedDotExpr, letting unbound + // generics escape. + return unboundTy; + }); }(); if (!parentType) return Type(); + parentType = CS.openUnboundGenericTypes( + parentType, CS.getConstraintLocator( + locator, {LocatorPathElt::PatternMatch(pattern), + ConstraintLocator::ParentType})); + + assert(parentType); + // Perform member lookup into the parent's metatype. Type parentMetaType = MetatypeType::get(parentType); CS.addValueMemberConstraint( diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 91fe6781d56ef..6a5ec66b76cb1 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -467,26 +467,31 @@ class ResolvePattern : public ASTVisitorgetBase())) return nullptr; - auto *const repr = IdentTypeRepr::create(Context, components); + const auto options = + TypeResolutionOptions(None) | TypeResolutionFlags::SilenceErrors; - // See first if the repr unambiguously references an enum declaration. - bool anyObject = false; - const auto &referencedDecls = - getDirectlyReferencedNominalTypeDecls(Context, repr, DC, anyObject); - if (referencedDecls.size() != 1) - return nullptr; + auto *repr = IdentTypeRepr::create(Context, components); - auto *const enumDecl = dyn_cast(referencedDecls.front()); + // See if the repr resolves to a type. + const auto resolution = + TypeResolution::forContextual(DC, options, [](auto unboundTy) { + // FIXME: Don't let unbound generic types escape type resolution. + // For now, just return the unbound generic type. + return unboundTy; + }); + const auto ty = resolution.resolveType(repr); + auto *enumDecl = dyn_cast_or_null(ty->getAnyNominal()); if (!enumDecl) return nullptr; - EnumElementDecl *referencedElement = - lookupEnumMemberElement(DC, enumDecl->getDeclaredInterfaceType(), - ude->getName(), ude->getLoc()); + EnumElementDecl *referencedElement + = lookupEnumMemberElement(DC, ty, ude->getName(), ude->getLoc()); if (!referencedElement) return nullptr; - auto *const base = new (Context) TypeExpr(repr); + auto *base = + TypeExpr::createForMemberDecl(repr, ude->getNameLoc(), enumDecl); + base->setType(MetatypeType::get(ty)); return new (Context) EnumElementPattern(base, ude->getDotLoc(), ude->getNameLoc(), ude->getName(), referencedElement, nullptr); @@ -564,31 +569,37 @@ class ResolvePattern : public ASTVisitorgetDeclaredTypeInContext(), Context); } else { + const auto options = + TypeResolutionOptions(None) | TypeResolutionFlags::SilenceErrors; + // Otherwise, see whether we had an enum type as the penultimate // component, and look up an element inside it. - auto *const prefixRepr = IdentTypeRepr::create(Context, components); - - // See first if the repr unambiguously references an enum declaration. - bool anyObject = false; - const auto &referencedDecls = getDirectlyReferencedNominalTypeDecls( - Context, prefixRepr, DC, anyObject); - if (referencedDecls.size() != 1) - return nullptr; - - auto *const enumDecl = dyn_cast(referencedDecls.front()); + auto *prefixRepr = IdentTypeRepr::create(Context, components); + + // See first if the entire repr resolves to a type. + const Type enumTy = + TypeResolution::forContextual(DC, options, [](auto unboundTy) { + // FIXME: Don't let unbound generic types escape type resolution. + // For now, just return the unbound generic type. + return unboundTy; + }).resolveType(prefixRepr); + auto *enumDecl = dyn_cast_or_null(enumTy->getAnyNominal()); if (!enumDecl) return nullptr; - referencedElement = lookupEnumMemberElement( - DC, enumDecl->getDeclaredInterfaceType(), tailComponent->getNameRef(), - tailComponent->getLoc()); + referencedElement + = lookupEnumMemberElement(DC, enumTy, + tailComponent->getNameRef(), + tailComponent->getLoc()); if (!referencedElement) return nullptr; - baseTE = new (Context) TypeExpr(prefixRepr); + baseTE = TypeExpr::createForMemberDecl( + prefixRepr, tailComponent->getNameLoc(), enumDecl); + baseTE->setType(MetatypeType::get(enumTy)); } - assert(baseTE && "Didn't initialize base expression?"); + assert(baseTE && baseTE->getType() && "Didn't initialize base expression?"); assert(!isa(tailComponent) && "should be handled above"); @@ -1426,25 +1437,11 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern, enumTy = type; } else { - // Validate the parent type if we haven't done so yet. - if (EEP->getParentType().isNull()) { - const auto resolution = - TypeResolution::forContextual(dc, options, [](auto unboundTy) { - // FIXME: Don't let unbound generic types escape type resolution. - // For now, just return the unbound generic type. - return unboundTy; - }); - const auto ty = resolution.resolveType(EEP->getParentTypeRepr()); - EEP->setParentType(ty); - - if (ty->hasError()) { - return nullptr; - } - } - // Check if the explicitly-written enum type matches the type we're // coercing to. - const Type parentTy = EEP->getParentType(); + assert(!EEP->getParentType().isNull() + && "enum with resolved element doesn't specify parent type?!"); + auto parentTy = EEP->getParentType(); // If the type matches exactly, use it. if (parentTy->isEqual(type)) { enumTy = type; diff --git a/test/Constraints/patterns.swift b/test/Constraints/patterns.swift index c79fc2195c719..a709fb5f8096e 100644 --- a/test/Constraints/patterns.swift +++ b/test/Constraints/patterns.swift @@ -339,14 +339,10 @@ func rdar32241441() { // SR-6100 struct One { // expected-note{{'Two' declared as parameter to type 'One'}} - public enum E: Error { - // if you remove associated value, everything works - case SomeError(String) - - static func foo(error: Error) { - if case SomeError = error {} + public enum E: Error { + // if you remove associated value, everything works + case SomeError(String) } - } } func testOne() { From a3340e80b39baba560f805e93693a2066e8e86b8 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Mon, 10 Aug 2020 16:22:13 +0300 Subject: [PATCH 096/123] [NFC] Add a test where a contextual type is necessary to resolve an EnumElementPattern --- test/Constraints/enum_cases.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/Constraints/enum_cases.swift b/test/Constraints/enum_cases.swift index 392104bdbd681..e567f89496070 100644 --- a/test/Constraints/enum_cases.swift +++ b/test/Constraints/enum_cases.swift @@ -153,3 +153,21 @@ func rdar_49159472() { func baz(e: E) {} } } + +struct EnumElementPatternFromContextualType { + enum E { + case plain + case payload(T) + } + + func foo(x: Any) where T == EnumElementPatternFromContextualType.E { + switch x { + case T.plain: // Ok + break + case T.payload(true): // Ok + break + default: + break + } + } +} From ccd82a0589a9549f09a5ac845e555229dc6b4b81 Mon Sep 17 00:00:00 2001 From: Gabriel Igliozzi Date: Mon, 10 Aug 2020 11:31:48 -0400 Subject: [PATCH 097/123] [Gardening] Fixed 404 in SIL and SIL Optimizations -> HighLevelSILOptimizations.rst (#33384) --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index cc4c4815bc9a9..b3e2c3f976d4d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -117,7 +117,7 @@ documentation, please create a thread on the Swift forums under the Provides an overview of the implementation of SIL in the compiler. - [OptimizerDesign.md](/docs/OptimizerDesign.md): Describes the design of the optimizer pipeline. - - [HighLevelSILOptimizations.rst](docs/HighLevelSILOptimizations.rst): + - [HighLevelSILOptimizations.rst](/docs/HighLevelSILOptimizations.rst): Describes how the optimizer understands the semantics of high-level operations on currency data types and optimizes accordingly. Includes a thorough discussion of the `@_semantics` attribute. From 63875e9e8fa64ce964f7fa4c008fa805747274af Mon Sep 17 00:00:00 2001 From: Zoe Carver Date: Mon, 10 Aug 2020 10:41:21 -0700 Subject: [PATCH 098/123] [cxx-interop] [IRGen] TypeInfo for address-only types. (#32973) The current "ClangRecordTypeInfo" derives from "LoadableTypeInfo" and is only meant for loadable types. While we have not yet run into problems, this may cause issues in the future and as more logic is needed around copying, moving, and destroying C++ objects, this needs to be fixed. --- lib/IRGen/GenStruct.cpp | 113 +++++++--- .../Cxx/class/Inputs/type-classification.h | 18 ++ ...ype-classification-non-trivial-irgen.swift | 99 +++++++++ ...pe-classification-non-trivial-silgen.swift | 195 +++++++++++++++++- .../type-classification-non-trivial.swift | 35 ++++ 5 files changed, 432 insertions(+), 28 deletions(-) create mode 100644 test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift create mode 100644 test/Interop/Cxx/class/type-classification-non-trivial.swift diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index b8c647fbefc6d..3f1961f80664b 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -53,6 +53,7 @@ enum class StructTypeInfoKind { LoadableStructTypeInfo, FixedStructTypeInfo, LoadableClangRecordTypeInfo, + AddressOnlyClangRecordTypeInfo, NonFixedStructTypeInfo, ResilientStructTypeInfo }; @@ -83,6 +84,12 @@ namespace { /// A field-info implementation for fields of Clang types. class ClangFieldInfo : public RecordField { public: + ClangFieldInfo(VarDecl *swiftField, const ElementLayout &layout, + const TypeInfo &typeInfo) + : RecordField(typeInfo), Field(swiftField) { + completeFrom(layout); + } + ClangFieldInfo(VarDecl *swiftField, const ElementLayout &layout, unsigned explosionBegin, unsigned explosionEnd) : RecordField(layout, explosionBegin, explosionEnd), @@ -290,7 +297,7 @@ namespace { } } }; - + /// A type implementation for loadable record types imported from Clang. class LoadableClangRecordTypeInfo final : public StructTypeInfoBase { + const clang::RecordDecl *ClangDecl; + + public: + AddressOnlyClangRecordTypeInfo(ArrayRef fields, + llvm::Type *storageType, Size size, + Alignment align, + const clang::RecordDecl *clangDecl) + : StructTypeInfoBase(StructTypeInfoKind::AddressOnlyClangRecordTypeInfo, + fields, storageType, size, + // We can't assume any spare bits in a C++ type + // with user-defined special member functions. + SpareBitVector(llvm::Optional{ + llvm::APInt(size.getValueInBits(), 0)}), + align, IsPOD, IsNotBitwiseTakable, IsFixedSize), + ClangDecl(clangDecl) { + (void)ClangDecl; + } + + TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM, + SILType T) const override { + return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T); + } + + void initializeFromParams(IRGenFunction &IGF, Explosion ¶ms, + Address addr, SILType T, + bool isOutlined) const override { + llvm_unreachable("Address-only C++ types must be created by C++ special " + "member functions."); + } + + llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF) const { return None; } + llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF, SILType T) const { + return None; + } + MemberAccessStrategy + getNonFixedFieldAccessStrategy(IRGenModule &IGM, SILType T, + const ClangFieldInfo &field) const { + llvm_unreachable("non-fixed field in Clang type?"); + } + }; + /// A type implementation for loadable struct types. class LoadableStructTypeInfo final : public StructTypeInfoBase { @@ -680,6 +731,10 @@ class ClangRecordLowering { const TypeInfo *createTypeInfo(llvm::StructType *llvmType) { llvmType->setBody(LLVMFields, /*packed*/ true); + if (SwiftType.getStructOrBoundGenericStruct()->isCxxNonTrivial()) { + return AddressOnlyClangRecordTypeInfo::create( + FieldInfos, llvmType, TotalStride, TotalAlignment, ClangDecl); + } return LoadableClangRecordTypeInfo::create(FieldInfos, NextExplosionIndex, llvmType, TotalStride, std::move(SpareBits), TotalAlignment, @@ -773,7 +828,7 @@ class ClangRecordLowering { // If we have a Swift import of this type, use our lowered information. if (swiftField) { - auto &fieldTI = cast(IGM.getTypeInfo( + auto &fieldTI = cast(IGM.getTypeInfo( SwiftType.getFieldType(swiftField, IGM.getSILModule(), IGM.getMaximalTypeExpansionContext()))); addField(swiftField, offset, fieldTI); @@ -812,7 +867,7 @@ class ClangRecordLowering { /// Add storage for an (optional) Swift field at the given offset. void addField(VarDecl *swiftField, Size offset, - const LoadableTypeInfo &fieldType) { + const FixedTypeInfo &fieldType) { assert(offset >= NextOffset && "adding fields out of order"); // Add a padding field if required. @@ -823,8 +878,11 @@ class ClangRecordLowering { } /// Add information to track a value field at the current offset. - void addFieldInfo(VarDecl *swiftField, const LoadableTypeInfo &fieldType) { - unsigned explosionSize = fieldType.getExplosionSize(); + void addFieldInfo(VarDecl *swiftField, const FixedTypeInfo &fieldType) { + bool isLoadableField = isa(fieldType); + unsigned explosionSize = 0; + if (isLoadableField) + explosionSize = cast(fieldType).getExplosionSize(); unsigned explosionBegin = NextExplosionIndex; NextExplosionIndex += explosionSize; unsigned explosionEnd = NextExplosionIndex; @@ -838,9 +896,12 @@ class ClangRecordLowering { layout.completeFixed(fieldType.isPOD(ResilienceExpansion::Maximal), NextOffset, LLVMFields.size()); - FieldInfos.push_back( - ClangFieldInfo(swiftField, layout, explosionBegin, explosionEnd)); - + if (isLoadableField) + FieldInfos.push_back( + ClangFieldInfo(swiftField, layout, explosionBegin, explosionEnd)); + else + FieldInfos.push_back(ClangFieldInfo(swiftField, layout, fieldType)); + if (!isEmpty) { LLVMFields.push_back(fieldType.getStorageType()); NextOffset += fieldType.getFixedSize(); @@ -862,22 +923,26 @@ class ClangRecordLowering { /// A convenient macro for delegating an operation to all of the /// various struct implementations. -#define FOR_STRUCT_IMPL(IGF, type, op, ...) do { \ - auto &structTI = IGF.getTypeInfo(type); \ - switch (getStructTypeInfoKind(structTI)) { \ - case StructTypeInfoKind::LoadableClangRecordTypeInfo: \ - return structTI.as().op(IGF, __VA_ARGS__); \ - case StructTypeInfoKind::LoadableStructTypeInfo: \ - return structTI.as().op(IGF, __VA_ARGS__); \ - case StructTypeInfoKind::FixedStructTypeInfo: \ - return structTI.as().op(IGF, __VA_ARGS__); \ - case StructTypeInfoKind::NonFixedStructTypeInfo: \ - return structTI.as().op(IGF, __VA_ARGS__); \ - case StructTypeInfoKind::ResilientStructTypeInfo: \ - llvm_unreachable("resilient structs are opaque"); \ - } \ - llvm_unreachable("bad struct type info kind!"); \ -} while (0) +#define FOR_STRUCT_IMPL(IGF, type, op, ...) \ + do { \ + auto &structTI = IGF.getTypeInfo(type); \ + switch (getStructTypeInfoKind(structTI)) { \ + case StructTypeInfoKind::LoadableClangRecordTypeInfo: \ + return structTI.as().op(IGF, __VA_ARGS__); \ + case StructTypeInfoKind::AddressOnlyClangRecordTypeInfo: \ + return structTI.as().op(IGF, \ + __VA_ARGS__); \ + case StructTypeInfoKind::LoadableStructTypeInfo: \ + return structTI.as().op(IGF, __VA_ARGS__); \ + case StructTypeInfoKind::FixedStructTypeInfo: \ + return structTI.as().op(IGF, __VA_ARGS__); \ + case StructTypeInfoKind::NonFixedStructTypeInfo: \ + return structTI.as().op(IGF, __VA_ARGS__); \ + case StructTypeInfoKind::ResilientStructTypeInfo: \ + llvm_unreachable("resilient structs are opaque"); \ + } \ + llvm_unreachable("bad struct type info kind!"); \ + } while (0) Address irgen::projectPhysicalStructMemberAddress(IRGenFunction &IGF, Address base, diff --git a/test/Interop/Cxx/class/Inputs/type-classification.h b/test/Interop/Cxx/class/Inputs/type-classification.h index 785c5ef278a73..09322bb5d0d1e 100644 --- a/test/Interop/Cxx/class/Inputs/type-classification.h +++ b/test/Interop/Cxx/class/Inputs/type-classification.h @@ -155,4 +155,22 @@ struct StructDeletedDestructor { ~StructDeletedDestructor() = delete; }; +struct StructWithCopyConstructorAndValue { + int value; + StructWithCopyConstructorAndValue( + const StructWithCopyConstructorAndValue &other) + : value(other.value) {} +}; + +struct StructWithSubobjectCopyConstructorAndValue { + StructWithCopyConstructorAndValue member; +}; + +struct StructWithCopyConstructorAndSubobjectCopyConstructorAndValue { + StructWithCopyConstructorAndValue member; + StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( + const StructWithCopyConstructorAndSubobjectCopyConstructorAndValue &other) + : member(other.member) {} +}; + #endif diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift new file mode 100644 index 0000000000000..fcbf32cff73d5 --- /dev/null +++ b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift @@ -0,0 +1,99 @@ +// RUN: %target-swift-frontend -enable-cxx-interop -I %S/Inputs %s -emit-ir | %FileCheck %s + +// Verify that non-trival/address-only C++ classes are constructed and accessed +// correctly. Make sure that we correctly IRGen functions that construct +// non-trivial C++ classes, take those classes as a parameter, and access those +// classes members. + +import TypeClassification + +// TODO: C++ objects with destructors should be tested here once we fully +// support them. + +// CHECK-LABEL: define {{.*}}i1 @"$s4main37testStructWithCopyConstructorAndValueSbyF" +// CHECK: [[OBJ:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[VAL_ELEMENT:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 +// CHECK: [[VAL_INT:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[VAL_ELEMENT]], i32 0, i32 0 +// CHECK: store i32 42, i32* [[VAL_INT]] +// CHECK: ret i1 true +public func testStructWithCopyConstructorAndValue() -> Bool { + let obj = StructWithCopyConstructorAndValue(value: 42) + return obj.value == 42 +} + +// CHECK-LABEL: define {{.*}}i1 @"$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF"() +// CHECK: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[OBJ:%.*]] = alloca %TSo42StructWithSubobjectCopyConstructorAndValueV +// CHECK: alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[TMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[MEMBER_ELEMENT:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], i32 0, i32 0 +// CHECK: [[MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[MEMBER_ELEMENT]], i32 0, i32 0 +// CHECK: store i32 42, i32* [[MEMBER_VALUE]] +// CHECK: %obj.member = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 +// CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TMP]], i32 0, i32 0 +// CHECK: [[TEMP_MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 +// CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VALUE]] +// CHECK: [[OUT:%.*]] = icmp eq i32 [[LHS]], 42 +// CHECK: ret i1 [[OUT]] +public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithSubobjectCopyConstructorAndValue(member: member) + return obj.member.value == 42 +} + +// CHECK-LABEL: define {{.*}}i1 @"$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF"() +// CHECK: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: alloca %TSo037StructWithCopyConstructorAndSubobjectcdE5ValueV +// CHECK: alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[TEMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[MEMBER_VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], i32 0, i32 0 +// CHECK: [[MEMBER_VAL_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[MEMBER_VAL]], i32 0, i32 0 +// CHECK: store i32 42, i32* [[MEMBER_VAL_VAL]] +// CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TEMP]], i32 0, i32 0 +// CHECK: [[TEMP_MEMBER_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 +// CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VAL]] +// CHECK: [[OUT:%.*]] = icmp eq i32 [[LHS]], 42 +// CHECK: ret i1 [[OUT]] +public func testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() +-> Bool { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( + member: member + ) + return obj.member.value == 42 +} + +// CHECK-LABEL: define {{.*}}i1 @"$s4main4test3objSbSo33StructWithCopyConstructorAndValueV_tF"(%TSo33StructWithCopyConstructorAndValueV* noalias nocapture dereferenceable(4) %0) +// CHECK: [[VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* %0, i32 0, i32 0 +// CHECK: [[VAL_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[VAL]], i32 0, i32 0 +// CHECK: [[LHS:%.*]] = load i32, i32* [[VAL_VAL]] +// CHECK: [[OUT:%.*]] = icmp eq i32 %1, 42 +// CHECK: ret i1 [[OUT]] +public func test(obj: StructWithCopyConstructorAndValue) -> Bool { + return obj.value == 42 +} + +// CHECK-LABEL: define {{.*}}i1 @"$s4main4test3objSbSo42StructWithSubobjectCopyConstructorAndValueV_tF"(%TSo42StructWithSubobjectCopyConstructorAndValueV* noalias nocapture dereferenceable(4) %0) +// CHECK: [[TMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[MEMBER:%.*]] = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* %0, i32 0, i32 0 +// CHECK: [[VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TMP]], i32 0, i32 0 +// CHECK: [[VAL_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[VAL]], i32 0, i32 0 +// CHECK: [[LHS:%.*]] = load i32, i32* [[VAL_VAL]] +// CHECK: [[OUT:%.*]] = icmp eq i32 [[LHS]], 42 +// CHECK: ret i1 [[OUT]] +public func test(obj: StructWithSubobjectCopyConstructorAndValue) -> Bool { + return obj.member.value == 42 +} + +// CHECK-LABEL: define {{.*}}i1 @"$s4main4test3objSbSo037StructWithCopyConstructorAndSubobjectfgH5ValueV_tF"(%TSo037StructWithCopyConstructorAndSubobjectcdE5ValueV* noalias nocapture dereferenceable(4) %0) +// CHECK:[[TEMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK:[[VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TEMP]], i32 0, i32 0 +// CHECK:[[VAL_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[VAL]], i32 0, i32 0 +// CHECK:[[LHS:%.*]] = load i32, i32* [[VAL_VAL]] +// CHECK:[[OUT:%.*]] = icmp eq i32 [[LHS]], 42 +// CHECK:ret i1 [[OUT]] +public func test( + obj: StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +) -> Bool { + return obj.member.value == 42 +} diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift index 3ed07447a4cfe..87766b5a01bdb 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift @@ -1,25 +1,212 @@ -// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-sil %s | %FileCheck %s +// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-silgen %s | %FileCheck %s import TypeClassification // Make sure that "StructWithDestructor" is marked as non-trivial by checking for a // "destroy_addr". -// CHECK-LABEL: @$s4main24testStructWithDestructoryyF +// CHECK-LABEL: sil [ossa] @$s4main24testStructWithDestructoryyF // CHECK: [[AS:%.*]] = alloc_stack $StructWithDestructor +// CHECK: [[META:%.*]] = metatype $@thin StructWithDestructor.Type +// CHECK: [[FN:%.*]] = function_ref @$sSo20StructWithDestructorVABycfC : $@convention(method) (@thin StructWithDestructor.Type) -> @out StructWithDestructor +// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(method) (@thin StructWithDestructor.Type) -> @out StructWithDestructor // CHECK: destroy_addr [[AS]] +// CHECK: dealloc_stack %0 : $*StructWithDestructor // CHECK-LABEL: end sil function '$s4main24testStructWithDestructoryyF' public func testStructWithDestructor() { let d = StructWithDestructor() } -// Make sure that "StructWithSubobjectDestructor" is marked as non-trivial by checking +// StructWithDestructor.init() +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo20StructWithDestructorVABycfC : $@convention(method) (@thin StructWithDestructor.Type) -> @out StructWithDestructor +// CHECK: [[BOX:%.*]] = alloc_box ${ var StructWithDestructor } +// CHECK: [[UBOX:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var StructWithDestructor } +// CHECK: [[BOX_ADDR:%.*]] = project_box [[UBOX]] : ${ var StructWithDestructor }, 0 +// CHECK: [[SA:%.*]] = alloc_stack $StructWithDestructor +// CHECK: builtin "zeroInitializer"([[SA]] : $*StructWithDestructor) : $() +// CHECK: [[BA:%.*]] = begin_access [modify] [unknown] [[BOX_ADDR]] : $*StructWithDestructor +// CHECK: copy_addr [take] [[SA]] to [[BA]] : $*StructWithDestructor +// CHECK: copy_addr [[BOX_ADDR]] to [initialization] %0 : $*StructWithDestructor +// CHECK: destroy_value [[UBOX]] : ${ var StructWithDestructor } +// CHECK-LABEL: end sil function '$sSo20StructWithDestructorVABycfC' + +// Make sure that "HasMemberWithDestructor" is marked as non-trivial by checking // for a "destroy_addr". -// CHECK-LABEL: @$s4main33testStructWithSubobjectDestructoryyF +// CHECK-LABEL: sil [ossa] @$s4main33testStructWithSubobjectDestructoryyF // CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectDestructor +// CHECK: [[META:%.*]] = metatype $@thin StructWithSubobjectDestructor.Type +// CHECK: [[FN:%.*]] = function_ref @$sSo29StructWithSubobjectDestructorVABycfC : $@convention(method) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor +// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(method) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor // CHECK: destroy_addr [[AS]] // CHECK-LABEL: end sil function '$s4main33testStructWithSubobjectDestructoryyF' public func testStructWithSubobjectDestructor() { let d = StructWithSubobjectDestructor() } +// StructWithSubobjectDestructor.init() +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo29StructWithSubobjectDestructorVABycfC : $@convention(method) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor +// CHECK: [[BOX:%.*]] = alloc_box ${ var StructWithSubobjectDestructor } +// CHECK: [[UBOX:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var StructWithSubobjectDestructor } +// CHECK: [[ADDR:%.*]] = project_box [[UBOX]] : ${ var StructWithSubobjectDestructor }, 0 +// CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectDestructor +// CHECK: builtin "zeroInitializer"([[AS]] : $*StructWithSubobjectDestructor) : $() +// CHECK: [[BA:%.*]] = begin_access [modify] [unknown] [[ADDR]] : $*StructWithSubobjectDestructor +// CHECK: copy_addr [take] [[AS]] to [[BA]] : $*StructWithSubobjectDestructor +// CHECK: copy_addr [[ADDR]] to [initialization] %0 : $*StructWithSubobjectDestructor +// CHECK: destroy_value [[UBOX]] : ${ var StructWithSubobjectDestructor } +// CHECK-LABEL: end sil function '$sSo29StructWithSubobjectDestructorVABycfC' + +// CHECK-LABLE: sil [ossa] @$s4main37testStructWithCopyConstructorAndValueSbyF +// CHECK: [[AS:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: [[META:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type +// CHECK: [[FN:%.*]] = function_ref @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], %{{.*}}, [[META]]) : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[OBJ_VAL_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_VAL:%.*]] = load [trivial] [[OBJ_VAL_ADDR]] : $*Int32 +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[MAKE_INT_FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT_FN]]([[IL_42]], %{{.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[CMP_FN:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[CMP_FN]]([[OBJ_VAL]], [[INT_42]], %{{.*}}) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: destroy_addr [[AS]] : $*StructWithCopyConstructorAndValue +// CHECK: return [[OUT]] : $Bool +// CHECK-LABLE: end sil function '$s4main37testStructWithCopyConstructorAndValueSbyF' +public func testStructWithCopyConstructorAndValue() -> Bool { + let obj = StructWithCopyConstructorAndValue(value: 42) + return obj.value == 42 +} + +// StructWithCopyConstructorAndValue.init(value:) +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[VAL:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: store %1 to [trivial] [[VAL]] : $*Int32 +// CHECK-LABEL: end sil function '$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC' + +// CHECK-LABEL: sil [ossa] @$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF : $@convention(thin) () -> Bool +// CHECK: [[MEMBER_0:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: [[MEMBER_META:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type +// CHECK: [[MAKE_MEMBER_FN:%.*]] = function_ref @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[MAKE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}, [[MEMBER_META]]) : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectCopyConstructorAndValue +// CHECK: [[META:%.*]] = metatype $@thin StructWithSubobjectCopyConstructorAndValue.Type +// CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr %0 to [initialization] [[MEMBER_1]] : $*StructWithCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @$sSo42StructWithSubobjectCopyConstructorAndValueV6memberABSo0abdefG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithSubobjectCopyConstructorAndValue.Type) -> @out StructWithSubobjectCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]], [[META]]) : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithSubobjectCopyConstructorAndValue.Type) -> @out StructWithSubobjectCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER:%.*]] = struct_element_addr [[AS]] : $*StructWithSubobjectCopyConstructorAndValue, #StructWithSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_2:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER]] to [initialization] [[MEMBER_2]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_VALUE_ADDR:%.*]] = struct_element_addr [[MEMBER_2]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_VALUE:%.*]] = load [trivial] [[OBJ_VALUE_ADDR]] : $*Int32 +// CHECK: [[MAKE_INT:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT]]({{.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[ICMP:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[ICMP]]([[OBJ_VALUE]], [[INT_42]], %{{.*}}) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF' +public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithSubobjectCopyConstructorAndValue(member: member) + return obj.member.value == 42 +} + +// StructWithSubobjectCopyConstructorAndValue.init(member:) +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo42StructWithSubobjectCopyConstructorAndValueV6memberABSo0abdefG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithSubobjectCopyConstructorAndValue.Type) -> @out StructWithSubobjectCopyConstructorAndValue +// CHECK: [[MEMBER:%.*]] = struct_element_addr %0 : $*StructWithSubobjectCopyConstructorAndValue, #StructWithSubobjectCopyConstructorAndValue.member +// CHECK: copy_addr [take] %1 to [initialization] [[MEMBER]] : $*StructWithCopyConstructorAndValue +// CHECK-LABEL: end sil function '$sSo42StructWithSubobjectCopyConstructorAndValueV6memberABSo0abdefG0V_tcfC' +// testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() +// CHECK-LABEL: sil [ossa] @$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF : $@convention(thin) () -> Bool +// CHECK: [[MEMBER_0:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: [[META_MEMBER:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type +// CHECK: [[CREATE_MEMBER_FN:%.*]] = function_ref @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[CREATE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}, [[META_MEMBER]]) : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[AS:%.*]] = alloc_stack $StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[META:%.*]] = metatype $@thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type +// CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[MEMBER_0]] to [initialization] [[MEMBER_1]] : $*StructWithCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @$sSo037StructWithCopyConstructorAndSubobjectcdE5ValueV6memberABSo0abcdeG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]], [[META]]) : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_2:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER_ADDR]] to [initialization] [[MEMBER_2]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_VALUE_ADDR:%.*]] = struct_element_addr [[MEMBER_2]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_MEMBER_VALUE:%.*]] = load [trivial] [[OBJ_MEMBER_VALUE_ADDR]] : $*Int32 +// CHECK: [[ICMP:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[ICMP]]([[OBJ_MEMBER_VALUE]], %{{.*}}) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF' +public func testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() +-> Bool { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( + member: member + ) + return obj.member.value == 42 +} + +// StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.init(member:) +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo037StructWithCopyConstructorAndSubobjectcdE5ValueV6memberABSo0abcdeG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[MEMBER:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member +// CHECK: copy_addr [take] %1 to [initialization] [[MEMBER]] : $*StructWithCopyConstructorAndValue +// CHECK-LABEL: end sil function '$sSo037StructWithCopyConstructorAndSubobjectcdE5ValueV6memberABSo0abcdeG0V_tcfC' + +// CHECK-LABEL: sil [ossa] @$s4main4test3objSbSo33StructWithCopyConstructorAndValueV_tF : $@convention(thin) (@in_guaranteed StructWithCopyConstructorAndValue) -> Bool +// CHECK: [[META_1:%.*]] = metatype $@thin Int32.Type +// CHECK: [[OBJ_VAL_ADDR:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_VAL:%.*]] = load [trivial] [[OBJ_VAL_ADDR]] : $*Int32 +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[META_2:%.*]] = metatype $@thin Int32.Type +// CHECK: [[FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT:%.*]] = apply [[FN]]([[IL_42]], [[META_2]]) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[FN_2:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[FN_2]]([[OBJ_VAL]], [[INT]], [[META_1]]) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main4test3objSbSo33StructWithCopyConstructorAndValueV_tF' +public func test(obj: StructWithCopyConstructorAndValue) -> Bool { + return obj.value == 42 +} + +// CHECK-LABEL: sil [ossa] @$s4main4test3objSbSo42StructWithSubobjectCopyConstructorAndValueV_tF : $@convention(thin) (@in_guaranteed StructWithSubobjectCopyConstructorAndValue) -> Bool +// CHECK: [[INT_META:%.*]] = metatype $@thin Int32.Type +// CHECK: [[OBJ_MEMBER:%.*]] = struct_element_addr %0 : $*StructWithSubobjectCopyConstructorAndValue, #StructWithSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_TMP:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER]] to [initialization] [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_VALUE_ADDR:%.*]] = struct_element_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_MEMBER_VALUE:%.*]] = load [trivial] [[OBJ_MEMBER_VALUE_ADDR]] : $*Int32 +// CHECK: destroy_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[INT_META_2:%.*]] = metatype $@thin Int32.Type +// CHECK: [[MAKE_INT_FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT_FN]]([[IL_42]], [[INT_META_2]]) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[FN:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[FN]]([[OBJ_MEMBER_VALUE]], [[INT_42]], [[INT_META]]) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: dealloc_stack [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main4test3objSbSo42StructWithSubobjectCopyConstructorAndValueV_tF' +public func test(obj: StructWithSubobjectCopyConstructorAndValue) -> Bool { + return obj.member.value == 42 +} + +// CHECK-LABEL: sil [ossa] @$s4main4test3objSbSo037StructWithCopyConstructorAndSubobjectfgH5ValueV_tF +// CHECK: [[META_INT_1:%.*]] = metatype $@thin Int32.Type +// CHECK: [[OBJ_MEMBER:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_TMP:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER]] to [initialization] [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_VAL_ADDR:%.*]] = struct_element_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_MEMBER_VAL:%.*]] = load [trivial] [[OBJ_MEMBER_VAL_ADDR]] : $*Int32 +// CHECK: destroy_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[META_INT_2:%.*]] = metatype $@thin Int32.Type +// CHECK: [[MAKE_INT_FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT_FN]]([[IL_42]], [[META_INT_2]]) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[ICMP_FN:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[ICMP_FN]]([[OBJ_MEMBER_VAL]], [[INT_42]], [[META_INT_1]]) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: dealloc_stack [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main4test3objSbSo037StructWithCopyConstructorAndSubobjectfgH5ValueV_tF' +public func test( + obj: StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +) -> Bool { + return obj.member.value == 42 +} diff --git a/test/Interop/Cxx/class/type-classification-non-trivial.swift b/test/Interop/Cxx/class/type-classification-non-trivial.swift new file mode 100644 index 0000000000000..489e6f71c7a40 --- /dev/null +++ b/test/Interop/Cxx/class/type-classification-non-trivial.swift @@ -0,0 +1,35 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -I %S/Inputs -o %t/address_only -Xfrontend -enable-cxx-interop +// RUN: %target-codesign %t/address_only +// RUN: %target-run %t/address_only 2&>1 + +// REQUIRES: executable_test + +import TypeClassification +import StdlibUnittest + +var AddressOnlyTestSuite = TestSuite("Address Only Types") + +AddressOnlyTestSuite.test("Test struct with copy constructor") { + let obj = StructWithCopyConstructorAndValue(value: 42) + expectEqual(obj.value, 42) +} + +AddressOnlyTestSuite.test("Test struct with member with copy constructor") { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithSubobjectCopyConstructorAndValue(member: member) + expectEqual(obj.member.value, 42) +} + +AddressOnlyTestSuite.test( + "Test struct with copy constructor and member with copy constructor" +) { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( + member: member + ) + expectEqual(obj.member.value, 42) +} + +runAllTests() + From 457b9990e9d98714ecd675d5b730ab5d1926e015 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Mon, 10 Aug 2020 14:06:46 -0400 Subject: [PATCH 099/123] Add checks that the endpoints of partial ranges are not-NaN. (#33378) We can't actually check for NaN (because the notion doesn't exist for Comparable), but we can require that the endpoint is non-exceptional by checking if it equals itself. --- stdlib/public/core/ClosedRange.swift | 4 ++- stdlib/public/core/Range.swift | 16 ++++++++++- test/stdlib/RangeTraps.swift | 40 ++++++++++++++++++++++++++ validation-test/stdlib/Range.swift.gyb | 2 +- 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/stdlib/public/core/ClosedRange.swift b/stdlib/public/core/ClosedRange.swift index a1fdac018e23e..b368c64ac64fc 100644 --- a/stdlib/public/core/ClosedRange.swift +++ b/stdlib/public/core/ClosedRange.swift @@ -330,10 +330,12 @@ extension Comparable { /// - Parameters: /// - minimum: The lower bound for the range. /// - maximum: The upper bound for the range. + /// + /// - Precondition: `minimum <= maximum`. @_transparent public static func ... (minimum: Self, maximum: Self) -> ClosedRange { _precondition( - minimum <= maximum, "Can't form Range with upperBound < lowerBound") + minimum <= maximum, "Range requires lowerBound <= upperBound") return ClosedRange(uncheckedBounds: (lower: minimum, upper: maximum)) } } diff --git a/stdlib/public/core/Range.swift b/stdlib/public/core/Range.swift index 85e7db7b7c9c2..4bcde92bf8153 100644 --- a/stdlib/public/core/Range.swift +++ b/stdlib/public/core/Range.swift @@ -723,10 +723,12 @@ extension Comparable { /// - Parameters: /// - minimum: The lower bound for the range. /// - maximum: The upper bound for the range. + /// + /// - Precondition: `minimum <= maximum`. @_transparent public static func ..< (minimum: Self, maximum: Self) -> Range { _precondition(minimum <= maximum, - "Can't form Range with upperBound < lowerBound") + "Range requires lowerBound <= upperBound") return Range(uncheckedBounds: (lower: minimum, upper: maximum)) } @@ -752,8 +754,12 @@ extension Comparable { /// // Prints "[10, 20, 30]" /// /// - Parameter maximum: The upper bound for the range. + /// + /// - Precondition: `maximum` must compare equal to itself (i.e. cannot be NaN). @_transparent public static prefix func ..< (maximum: Self) -> PartialRangeUpTo { + _precondition(maximum == maximum, + "Range cannot have an unordered upper bound.") return PartialRangeUpTo(maximum) } @@ -779,8 +785,12 @@ extension Comparable { /// // Prints "[10, 20, 30, 40]" /// /// - Parameter maximum: The upper bound for the range. + /// + /// - Precondition: `maximum` must compare equal to itself (i.e. cannot be NaN). @_transparent public static prefix func ... (maximum: Self) -> PartialRangeThrough { + _precondition(maximum == maximum, + "Range cannot have an unordered upper bound.") return PartialRangeThrough(maximum) } @@ -806,8 +816,12 @@ extension Comparable { /// // Prints "[40, 50, 60, 70]" /// /// - Parameter minimum: The lower bound for the range. + /// + /// - Precondition: `minimum` must compare equal to itself (i.e. cannot be NaN). @_transparent public static postfix func ... (minimum: Self) -> PartialRangeFrom { + _precondition(minimum == minimum, + "Range cannot have an unordered lower bound.") return PartialRangeFrom(minimum) } } diff --git a/test/stdlib/RangeTraps.swift b/test/stdlib/RangeTraps.swift index bf9e5e06e6291..c8e265416ef66 100644 --- a/test/stdlib/RangeTraps.swift +++ b/test/stdlib/RangeTraps.swift @@ -74,7 +74,47 @@ RangeTraps.test("CountablePartialRangeFrom") _ = it.next() } +RangeTraps.test("nanLowerBound") + .code { + expectCrashLater() + _ = Double.nan ... 0 +} + +RangeTraps.test("nanUpperBound") + .code { + expectCrashLater() + _ = 0 ... Double.nan +} + +RangeTraps.test("nanLowerBoundPartial") + .code { + expectCrashLater() + _ = Double.nan ..< 0 +} + +RangeTraps.test("nanUpperBoundPartial") + .code { + expectCrashLater() + _ = 0 ..< Double.nan +} +RangeTraps.test("fromNaN") + .code { + expectCrashLater() + _ = Double.nan... +} + +RangeTraps.test("toNaN") + .code { + expectCrashLater() + _ = .. Date: Mon, 10 Aug 2020 12:33:39 -0700 Subject: [PATCH 100/123] Serialization: add an option to allow deserializing @_implementationOnly dependencies In theory, we shouldn't need to deserialize @_implementationOnly dependencies. However, potential decl recovery issues may bring down lldb if we insist on not importing these dependencies, resulting in bad user experience as a result. This patch adds an internal option to allow importing them and it should only be set by lldb and other tools. rdar://65570721 --- include/swift/Basic/LangOptions.h | 6 ++++++ lib/Serialization/Deserialization.cpp | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 0dee7442f16c6..6531ecdf0e5c8 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -385,6 +385,12 @@ namespace swift { /// Load swiftmodule files in memory as volatile and avoid mmap. bool EnableVolatileModules = false; + /// Allow deserializing implementation only dependencies. This should only + /// be set true by lldb and other tooling, so that deserilization + /// recovery issues won't bring down the debugger. + /// TODO: remove this when @_implementationOnly modules are robust enough. + bool AllowDeserializingImplementationOnly = false; + /// Sets the target we are building for and updates platform conditions /// to match. /// diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 8e4d8fa7f0b87..ddbc8f9a513d0 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2006,7 +2006,8 @@ ModuleDecl *ModuleFile::getModule(ModuleID MID) { llvm_unreachable("implementation detail only"); } } - return getModule(getIdentifier(MID)); + return getModule(getIdentifier(MID), + getContext().LangOpts.AllowDeserializingImplementationOnly); } ModuleDecl *ModuleFile::getModule(ArrayRef name, From 9da6d9269c566d4e67ebe0fa685c3bf5cfada4ed Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 10 Aug 2020 13:28:59 -0700 Subject: [PATCH 101/123] [Gardening] Reflow codable_non_decoded_property_here --- include/swift/AST/DiagnosticsSema.def | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 67d2f281c6ed0..56d695d138e1d 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2818,7 +2818,8 @@ NOTE(codable_extraneous_codingkey_case_here,none, NOTE(codable_non_conforming_property_here,none, "cannot automatically synthesize %0 because %1 does not conform to %0", (Type, TypeLoc)) NOTE(codable_non_decoded_property_here,none, - "cannot automatically synthesize %0 because %1 does not have a matching CodingKey and does not have a default value", (Type, Identifier)) + "cannot automatically synthesize %0 because %1 does not have a matching " + "CodingKey and does not have a default value", (Type, Identifier)) NOTE(codable_codingkeys_type_is_not_an_enum_here,none, "cannot automatically synthesize %0 because 'CodingKeys' is not an enum", (Type)) NOTE(codable_codingkeys_type_does_not_conform_here,none, From c0774557563c9a03b3e15bb370cf491d560adaa0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 10 Aug 2020 13:30:38 -0700 Subject: [PATCH 102/123] Use a SmallMapVector instead of a SmallDenseMap validateCodingKeysEnum cannot iterate over a hashed collection without ordering guarantees. --- lib/Sema/DerivedConformanceCodable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index cc455dfdc6f40..2c5fb8ae6018c 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -143,7 +143,7 @@ static bool validateCodingKeysEnum(DerivedConformance &derived, // Here we'll hold on to properties by name -- when we've validated a property // against its CodingKey entry, it will get removed. - llvm::SmallDenseMap properties; + llvm::SmallMapVector properties; for (auto *varDecl : derived.Nominal->getStoredProperties()) { if (!varDecl->isUserAccessible()) continue; From 52591ef9822b90f7f02994cee6baab7f4f8ad5db Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 13:41:24 -0700 Subject: [PATCH 103/123] [Sema] Rename error-handling code to effects-handling code. The error-handling code is getting generalized for 'async' handling as well, so rename the various entry points to talk about "effects" instead. --- lib/Sema/CMakeLists.txt | 2 +- lib/Sema/PCMacro.cpp | 4 +- lib/Sema/PlaygroundTransform.cpp | 6 +-- lib/Sema/TypeCheckDecl.cpp | 2 +- lib/Sema/TypeCheckDeclPrimary.cpp | 4 +- ...ypeCheckError.cpp => TypeCheckEffects.cpp} | 52 +++++++++---------- lib/Sema/TypeCheckStmt.cpp | 4 +- lib/Sema/TypeCheckStorage.cpp | 2 +- lib/Sema/TypeChecker.h | 10 ++-- 9 files changed, 43 insertions(+), 43 deletions(-) rename lib/Sema/{TypeCheckError.cpp => TypeCheckEffects.cpp} (97%) diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 3c0e373e81c6b..be48c2a9918e4 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -46,7 +46,7 @@ add_swift_host_library(swiftSema STATIC TypeCheckDeclObjC.cpp TypeCheckDeclOverride.cpp TypeCheckDeclPrimary.cpp - TypeCheckError.cpp + TypeCheckEffects.cpp TypeCheckExpr.cpp TypeCheckExprObjC.cpp TypeCheckGeneric.cpp diff --git a/lib/Sema/PCMacro.cpp b/lib/Sema/PCMacro.cpp index 5d6075ef5b031..0ce8b28ac54a9 100644 --- a/lib/Sema/PCMacro.cpp +++ b/lib/Sema/PCMacro.cpp @@ -354,7 +354,7 @@ class Instrumenter : InstrumenterBase { if (NB != B) { FD->setBody(NB); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } } } else if (auto *NTD = dyn_cast(D)) { @@ -695,7 +695,7 @@ void swift::performPCMacro(SourceFile &SF) { BraceStmt *NewBody = I.transformBraceStmt(Body, true); if (NewBody != Body) { TLCD->setBody(NewBody); - TypeChecker::checkTopLevelErrorHandling(TLCD); + TypeChecker::checkTopLevelEffects(TLCD); TypeChecker::contextualizeTopLevelCode(TLCD); } return false; diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp index 7c7e9dcd1e39b..f36294ff47240 100644 --- a/lib/Sema/PlaygroundTransform.cpp +++ b/lib/Sema/PlaygroundTransform.cpp @@ -294,7 +294,7 @@ class Instrumenter : InstrumenterBase { BraceStmt *NB = transformBraceStmt(B); if (NB != B) { FD->setBody(NB); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } } } else if (auto *NTD = dyn_cast(D)) { @@ -893,7 +893,7 @@ void swift::performPlaygroundTransform(SourceFile &SF, bool HighPerformance) { BraceStmt *NewBody = I.transformBraceStmt(Body); if (NewBody != Body) { FD->setBody(NewBody); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } return false; } @@ -905,7 +905,7 @@ void swift::performPlaygroundTransform(SourceFile &SF, bool HighPerformance) { BraceStmt *NewBody = I.transformBraceStmt(Body, true); if (NewBody != Body) { TLCD->setBody(NewBody); - TypeChecker::checkTopLevelErrorHandling(TLCD); + TypeChecker::checkTopLevelEffects(TLCD); } return false; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index d8fb606a5c388..c364de02f8eb0 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1066,7 +1066,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, if (TypeChecker::typeCheckExpression(exprToCheck, ED, rawTy, CTP_EnumCaseRawValue)) { - TypeChecker::checkEnumElementErrorHandling(elt, exprToCheck); + TypeChecker::checkEnumElementEffects(elt, exprToCheck); } } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index c307cca174ce5..7c4881e8d2305 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -881,7 +881,7 @@ Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator, return new (ctx) ErrorExpr(initExpr->getSourceRange(), ErrorType::get(ctx)); } - TypeChecker::checkInitializerErrorHandling(dc, initExpr); + TypeChecker::checkInitializerEffects(dc, initExpr); // Walk the checked initializer and contextualize any closures // we saw there. @@ -1657,7 +1657,7 @@ class DeclChecker : public DeclVisitor { PBD->getInitContext(i)); if (initContext) { // Check safety of error-handling in the declaration, too. - TypeChecker::checkInitializerErrorHandling(initContext, init); + TypeChecker::checkInitializerEffects(initContext, init); TypeChecker::contextualizeInitializer(initContext, init); } } diff --git a/lib/Sema/TypeCheckError.cpp b/lib/Sema/TypeCheckEffects.cpp similarity index 97% rename from lib/Sema/TypeCheckError.cpp rename to lib/Sema/TypeCheckEffects.cpp index 92819337f75dc..26e96a73c12c6 100644 --- a/lib/Sema/TypeCheckError.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -1,4 +1,4 @@ -//===--- TypeCheckError.cpp - Type Checking for Error Coverage ------------===// +//===--- TypeCheckEffects.cpp - Type Checking for Effects Coverage --------===// // // This source file is part of the Swift.org open source project // @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// // -// This file implements semantic analysis to ensure that errors are -// caught. +// This file implements semantic analysis to ensure that various effects (such +// as throwing and async) are properly handled. // //===----------------------------------------------------------------------===// @@ -184,9 +184,9 @@ enum ShouldRecurse_t : bool { }; /// A CRTP ASTWalker implementation that looks for interesting -/// nodes for error handling. +/// nodes for effects handling. template -class ErrorHandlingWalker : public ASTWalker { +class EffectsHandlingWalker : public ASTWalker { Impl &asImpl() { return *static_cast(this); } public: bool walkToDeclPre(Decl *D) override { @@ -221,7 +221,7 @@ class ErrorHandlingWalker : public ASTWalker { } else if (auto interpolated = dyn_cast(E)) { recurse = asImpl().checkInterpolatedStringLiteral(interpolated); } - // Error handling validation (via checkTopLevelErrorHandling) happens after + // Error handling validation (via checkTopLevelEffects) happens after // type checking. If an unchecked expression is still around, the code was // invalid. #define UNCHECKED_EXPR(KIND, BASE) \ @@ -580,7 +580,7 @@ class ApplyClassifier { } class FunctionBodyClassifier - : public ErrorHandlingWalker { + : public EffectsHandlingWalker { ApplyClassifier &Self; public: bool IsInvalid = false; @@ -1221,8 +1221,8 @@ class Context { /// A class to walk over a local context and validate the correctness /// of its error coverage. -class CheckErrorCoverage : public ErrorHandlingWalker { - friend class ErrorHandlingWalker; +class CheckEffectsCoverage : public EffectsHandlingWalker { + friend class EffectsHandlingWalker; ASTContext &Ctx; @@ -1288,13 +1288,13 @@ class CheckErrorCoverage : public ErrorHandlingWalker { /// An RAII object for restoring all the interesting state in an /// error-coverage. class ContextScope { - CheckErrorCoverage &Self; + CheckEffectsCoverage &Self; Context OldContext; DeclContext *OldRethrowsDC; ContextFlags OldFlags; ThrowingKind OldMaxThrowingKind; public: - ContextScope(CheckErrorCoverage &self, Optional newContext) + ContextScope(CheckEffectsCoverage &self, Optional newContext) : Self(self), OldContext(self.CurContext), OldRethrowsDC(self.Classifier.RethrowsDC), OldFlags(self.Flags), @@ -1379,7 +1379,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { }; public: - CheckErrorCoverage(ASTContext &ctx, Context initialContext) + CheckEffectsCoverage(ASTContext &ctx, Context initialContext) : Ctx(ctx), CurContext(initialContext), MaxThrowingKind(ThrowingKind::None) { @@ -1528,8 +1528,8 @@ class CheckErrorCoverage : public ErrorHandlingWalker { // Check the inactive regions of a #if block to disable warnings that may // be due to platform specific code. struct ConservativeThrowChecker : public ASTWalker { - CheckErrorCoverage &CEC; - ConservativeThrowChecker(CheckErrorCoverage &CEC) : CEC(CEC) {} + CheckEffectsCoverage &CEC; + ConservativeThrowChecker(CheckEffectsCoverage &CEC) : CEC(CEC) {} Expr *walkToExprPost(Expr *E) override { if (isa(E)) @@ -1694,9 +1694,9 @@ class CheckErrorCoverage : public ErrorHandlingWalker { } // end anonymous namespace -void TypeChecker::checkTopLevelErrorHandling(TopLevelCodeDecl *code) { +void TypeChecker::checkTopLevelEffects(TopLevelCodeDecl *code) { auto &ctx = code->getDeclContext()->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forTopLevelCode(code)); + CheckEffectsCoverage checker(ctx, Context::forTopLevelCode(code)); // In some language modes, we allow top-level code to omit 'try' marking. if (ctx.LangOpts.EnableThrowWithoutTry) @@ -1705,16 +1705,16 @@ void TypeChecker::checkTopLevelErrorHandling(TopLevelCodeDecl *code) { code->getBody()->walk(checker); } -void TypeChecker::checkFunctionErrorHandling(AbstractFunctionDecl *fn) { +void TypeChecker::checkFunctionEffects(AbstractFunctionDecl *fn) { #ifndef NDEBUG - PrettyStackTraceDecl debugStack("checking error handling for", fn); + PrettyStackTraceDecl debugStack("checking effects handling for", fn); #endif auto isDeferBody = isa(fn) && cast(fn)->isDeferBody(); auto context = isDeferBody ? Context::forDeferBody() : Context::forFunction(fn); auto &ctx = fn->getASTContext(); - CheckErrorCoverage checker(ctx, context); + CheckEffectsCoverage checker(ctx, context); // If this is a debugger function, suppress 'try' marking at the top level. if (fn->getAttrs().hasAttribute()) @@ -1728,14 +1728,14 @@ void TypeChecker::checkFunctionErrorHandling(AbstractFunctionDecl *fn) { superInit->walk(checker); } -void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx, +void TypeChecker::checkInitializerEffects(Initializer *initCtx, Expr *init) { auto &ctx = initCtx->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forInitializer(initCtx)); + CheckEffectsCoverage checker(ctx, Context::forInitializer(initCtx)); init->walk(checker); } -/// Check the correctness of error handling within the given enum +/// Check the correctness of effects within the given enum /// element's raw value expression. /// /// The syntactic restrictions on such expressions should make it @@ -1743,15 +1743,15 @@ void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx, /// ensures correctness if those restrictions are ever loosened, /// perhaps accidentally, and (2) allows the verifier to assert that /// all calls have been checked. -void TypeChecker::checkEnumElementErrorHandling(EnumElementDecl *elt, Expr *E) { +void TypeChecker::checkEnumElementEffects(EnumElementDecl *elt, Expr *E) { auto &ctx = elt->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forEnumElementInitializer(elt)); + CheckEffectsCoverage checker(ctx, Context::forEnumElementInitializer(elt)); E->walk(checker); } -void TypeChecker::checkPropertyWrapperErrorHandling( +void TypeChecker::checkPropertyWrapperEffects( PatternBindingDecl *binding, Expr *expr) { auto &ctx = binding->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forPatternBinding(binding)); + CheckEffectsCoverage checker(ctx, Context::forPatternBinding(binding)); expr->walk(checker); } diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 5de97e3012634..9b8af8759bab2 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1698,7 +1698,7 @@ static Type getFunctionBuilderType(FuncDecl *FD) { bool TypeChecker::typeCheckAbstractFunctionBody(AbstractFunctionDecl *AFD) { auto res = evaluateOrDefault(AFD->getASTContext().evaluator, TypeCheckFunctionBodyRequest{AFD}, true); - TypeChecker::checkFunctionErrorHandling(AFD); + TypeChecker::checkFunctionEffects(AFD); TypeChecker::computeCaptures(AFD); return res; } @@ -2152,7 +2152,7 @@ void TypeChecker::typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD) { BraceStmt *Body = TLCD->getBody(); StmtChecker(TLCD).typeCheckStmt(Body); TLCD->setBody(Body); - checkTopLevelErrorHandling(TLCD); + checkTopLevelEffects(TLCD); performTopLevelDeclDiagnostics(TLCD); } diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index eca917211a065..01c82f7583890 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -2491,7 +2491,7 @@ static void typeCheckSynthesizedWrapperInitializer( dyn_cast_or_null(pbd->getInitContext(i))) { TypeChecker::contextualizeInitializer(initializerContext, initializer); } - TypeChecker::checkPropertyWrapperErrorHandling(pbd, initializer); + TypeChecker::checkPropertyWrapperEffects(pbd, initializer); } static PropertyWrapperMutability::Value diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index cefdf503fc1f6..f551fda552249 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1147,11 +1147,11 @@ void diagnoseIfDeprecated(SourceRange SourceRange, void checkForForbiddenPrefix(ASTContext &C, DeclBaseName Name); /// Check error handling in the given type-checked top-level code. -void checkTopLevelErrorHandling(TopLevelCodeDecl *D); -void checkFunctionErrorHandling(AbstractFunctionDecl *D); -void checkInitializerErrorHandling(Initializer *I, Expr *E); -void checkEnumElementErrorHandling(EnumElementDecl *D, Expr *expr); -void checkPropertyWrapperErrorHandling(PatternBindingDecl *binding, +void checkTopLevelEffects(TopLevelCodeDecl *D); +void checkFunctionEffects(AbstractFunctionDecl *D); +void checkInitializerEffects(Initializer *I, Expr *E); +void checkEnumElementEffects(EnumElementDecl *D, Expr *expr); +void checkPropertyWrapperEffects(PatternBindingDecl *binding, Expr *expr); /// If an expression references 'self.init' or 'super.init' in an From a2dc034184ba8a2396a6208331a593d60e4ddc51 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 14:00:09 -0700 Subject: [PATCH 104/123] [Effects handling] Stop storing an ApplyClassifier as an instance. --- lib/Sema/TypeCheckEffects.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 26e96a73c12c6..b7d8fcbaae788 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -1226,8 +1226,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ASTContext &Ctx; - ApplyClassifier Classifier; - + DeclContext *RethrowsDC = nullptr; Context CurContext; class ContextFlags { @@ -1296,7 +1295,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker public: ContextScope(CheckEffectsCoverage &self, Optional newContext) : Self(self), OldContext(self.CurContext), - OldRethrowsDC(self.Classifier.RethrowsDC), + OldRethrowsDC(self.RethrowsDC), OldFlags(self.Flags), OldMaxThrowingKind(self.MaxThrowingKind) { if (newContext) self.CurContext = *newContext; @@ -1306,7 +1305,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ContextScope &operator=(const ContextScope &) = delete; void enterSubFunction() { - Self.Classifier.RethrowsDC = nullptr; + Self.RethrowsDC = nullptr; } void enterTry() { @@ -1372,7 +1371,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ~ContextScope() { Self.CurContext = OldContext; - Self.Classifier.RethrowsDC = OldRethrowsDC; + Self.RethrowsDC = OldRethrowsDC; Self.Flags = OldFlags; Self.MaxThrowingKind = OldMaxThrowingKind; } @@ -1384,7 +1383,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker MaxThrowingKind(ThrowingKind::None) { if (auto rethrowsDC = initialContext.getRethrowsDC()) { - Classifier.RethrowsDC = rethrowsDC; + RethrowsDC = rethrowsDC; } } @@ -1494,7 +1493,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ShouldRecurse_t checkApply(ApplyExpr *E) { // An apply expression is a potential throw site if the function throws. // But if the expression didn't type-check, suppress diagnostics. - auto classification = Classifier.classifyApply(E); + ApplyClassifier classifier; + classifier.RethrowsDC = RethrowsDC; + auto classification = classifier.classifyApply(E); checkThrowAsyncSite(E, /*requiresTry*/ true, classification); From 8083b2dcecc4ece284eaf5856e8124c6bb86ec39 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 14:03:50 -0700 Subject: [PATCH 105/123] [Effects handling] Rename PotentialReason -> PotentialThrowsReason. --- lib/Sema/TypeCheckEffects.cpp | 72 +++++++++++++++++------------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index b7d8fcbaae788..15a3fb40feaab 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -253,7 +253,7 @@ class EffectsHandlingWalker : public ASTWalker { }; /// A potential reason why something might throw. -class PotentialReason { +class PotentialThrowReason { public: enum class Kind : uint8_t { /// The function throws unconditionally. @@ -275,21 +275,21 @@ class PotentialReason { Expr *TheExpression; Kind TheKind; - explicit PotentialReason(Kind kind) : TheKind(kind) {} + explicit PotentialThrowReason(Kind kind) : TheKind(kind) {} public: - static PotentialReason forRethrowsArgument(Expr *E) { - PotentialReason result(Kind::CallRethrowsWithExplicitThrowingArgument); + static PotentialThrowReason forRethrowsArgument(Expr *E) { + PotentialThrowReason result(Kind::CallRethrowsWithExplicitThrowingArgument); result.TheExpression = E; return result; } - static PotentialReason forDefaultArgument() { - return PotentialReason(Kind::CallRethrowsWithDefaultThrowingArgument); + static PotentialThrowReason forDefaultArgument() { + return PotentialThrowReason(Kind::CallRethrowsWithDefaultThrowingArgument); } - static PotentialReason forThrowingApply() { - return PotentialReason(Kind::CallThrows); + static PotentialThrowReason forThrowingApply() { + return PotentialThrowReason(Kind::CallThrows); } - static PotentialReason forThrow() { - return PotentialReason(Kind::Throw); + static PotentialThrowReason forThrow() { + return PotentialThrowReason(Kind::Throw); } Kind getKind() const { return TheKind; } @@ -321,16 +321,16 @@ enum class ThrowingKind { }; /// A type expressing the result of classifying whether a call or function -/// throws. +/// throws or is async. class Classification { bool IsInvalid = false; // The AST is malformed. Don't diagnose. bool IsAsync = false; ThrowingKind Result = ThrowingKind::None; - Optional Reason; + Optional Reason; public: Classification() : Result(ThrowingKind::None) {} - explicit Classification(ThrowingKind result, PotentialReason reason, + explicit Classification(ThrowingKind result, PotentialThrowReason reason, bool isAsync) : IsAsync(isAsync), Result(result) { if (result == ThrowingKind::Throws || @@ -341,7 +341,7 @@ class Classification { /// Return a classification saying that there's an unconditional /// throw site. - static Classification forThrow(PotentialReason reason, bool isAsync) { + static Classification forThrow(PotentialThrowReason reason, bool isAsync) { Classification result; result.Result = ThrowingKind::Throws; result.Reason = reason; @@ -363,7 +363,7 @@ class Classification { return result; } - static Classification forRethrowingOnly(PotentialReason reason) { + static Classification forRethrowingOnly(PotentialThrowReason reason) { Classification result; result.Result = ThrowingKind::RethrowingOnly; result.Reason = reason; @@ -378,7 +378,7 @@ class Classification { bool isInvalid() const { return IsInvalid; } ThrowingKind getResult() const { return Result; } - PotentialReason getThrowsReason() const { + PotentialThrowReason getThrowsReason() const { assert(getResult() == ThrowingKind::Throws || getResult() == ThrowingKind::RethrowingOnly); return *Reason; @@ -446,7 +446,7 @@ class ApplyClassifier { assert(args.size() > fnRef.getNumArgumentsForFullApply() && "partial application was throwing?"); - return Classification::forThrow(PotentialReason::forThrowingApply(), + return Classification::forThrow(PotentialThrowReason::forThrowingApply(), isAsync); } @@ -476,7 +476,7 @@ class ApplyClassifier { // Try to classify the implementation of functions that we have // local knowledge of. Classification result = - classifyThrowingFunctionBody(fnRef, PotentialReason::forThrowingApply()); + classifyThrowingFunctionBody(fnRef, PotentialThrowReason::forThrowingApply()); assert(result.getResult() != ThrowingKind::None && "body classification decided function was no-throw"); @@ -496,7 +496,7 @@ class ApplyClassifier { /// if the function is an autoclosure that simply doesn't throw at all. Classification classifyThrowingFunctionBody(const AbstractFunction &fn, - PotentialReason reason) { + PotentialThrowReason reason) { // If we're not checking a 'rethrows' context, we don't need to // distinguish between 'throws' and 'rethrows'. But don't even // trust 'throws' for autoclosures. @@ -517,7 +517,7 @@ class ApplyClassifier { } Classification classifyThrowingParameterBody(ParamDecl *param, - PotentialReason reason) { + PotentialThrowReason reason) { assert(param->getType() ->lookThroughAllOptionalTypes() ->castTo() @@ -542,7 +542,7 @@ class ApplyClassifier { } Classification classifyThrowingFunctionBody(AbstractFunctionDecl *fn, - PotentialReason reason) { + PotentialThrowReason reason) { // Functions can't be rethrowing-only unless they're defined // within the rethrows context. if (!isLocallyDefinedInRethrowsContext(fn) || !fn->hasBody()) @@ -556,7 +556,7 @@ class ApplyClassifier { } Classification classifyThrowingFunctionBody(AbstractClosureExpr *closure, - PotentialReason reason) { + PotentialThrowReason reason) { bool isAutoClosure = isa(closure); // Closures can't be rethrowing-only unless they're defined @@ -705,7 +705,7 @@ class ApplyClassifier { if (isa(arg)) { return classifyArgumentByType(arg->getType(), - PotentialReason::forDefaultArgument()); + PotentialThrowReason::forDefaultArgument()); } // If this argument is `nil` literal, it doesn't cause the call to throw. @@ -736,7 +736,7 @@ class ApplyClassifier { // parameter type included a throwing function type. return classifyArgumentByType( paramType, - PotentialReason::forRethrowsArgument(arg)); + PotentialThrowReason::forRethrowsArgument(arg)); } // FIXME: There's a case where we can end up with an ApplyExpr that @@ -751,7 +751,7 @@ class ApplyClassifier { if (!paramFnType || !paramFnType->isThrowing()) return Classification(); - PotentialReason reason = PotentialReason::forRethrowsArgument(arg); + PotentialThrowReason reason = PotentialThrowReason::forRethrowsArgument(arg); // TODO: partial applications? @@ -793,7 +793,7 @@ class ApplyClassifier { /// a throwing function in a way that is permitted to cause a /// 'rethrows' function to throw. static Classification classifyArgumentByType(Type paramType, - PotentialReason reason) { + PotentialThrowReason reason) { if (!paramType || paramType->hasError()) return Classification::forInvalidCode(); if (auto fnType = paramType->getAs()) { @@ -1022,18 +1022,18 @@ class Context { } static void maybeAddRethrowsNote(DiagnosticEngine &Diags, SourceLoc loc, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { switch (reason.getKind()) { - case PotentialReason::Kind::Throw: + case PotentialThrowReason::Kind::Throw: llvm_unreachable("should already have been covered"); - case PotentialReason::Kind::CallThrows: + case PotentialThrowReason::Kind::CallThrows: // Already fully diagnosed. return; - case PotentialReason::Kind::CallRethrowsWithExplicitThrowingArgument: + case PotentialThrowReason::Kind::CallRethrowsWithExplicitThrowingArgument: Diags.diagnose(reason.getThrowingArgument()->getLoc(), diag::because_rethrows_argument_throws); return; - case PotentialReason::Kind::CallRethrowsWithDefaultThrowingArgument: + case PotentialThrowReason::Kind::CallRethrowsWithDefaultThrowingArgument: Diags.diagnose(loc, diag::because_rethrows_default_argument_throws); return; } @@ -1041,7 +1041,7 @@ class Context { } void diagnoseUncoveredThrowSite(ASTContext &ctx, ASTNode E, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { auto &Diags = ctx.Diags; auto message = diag::throwing_call_without_try; auto loc = E.getStartLoc(); @@ -1077,7 +1077,7 @@ class Context { // // Let's suggest couple of alternative fix-its // because complete context is unavailable. - if (reason.getKind() != PotentialReason::Kind::CallThrows) + if (reason.getKind() != PotentialThrowReason::Kind::CallThrows) return; Diags.diagnose(loc, diag::note_forgot_try) @@ -1090,7 +1090,7 @@ class Context { void diagnoseThrowInLegalContext(DiagnosticEngine &Diags, ASTNode node, bool isTryCovered, - const PotentialReason &reason, + const PotentialThrowReason &reason, Diag<> diagForThrow, Diag<> diagForThrowingCall, Diag<> diagForTrylessThrowingCall) { @@ -1119,7 +1119,7 @@ class Context { void diagnoseUnhandledThrowSite(DiagnosticEngine &Diags, ASTNode E, bool isTryCovered, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { switch (getKind()) { case Kind::Handled: llvm_unreachable("throw site is handled!"); @@ -1558,7 +1558,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ShouldRecurse_t checkThrow(ThrowStmt *S) { checkThrowAsyncSite(S, /*requiresTry*/ false, - Classification::forThrow(PotentialReason::forThrow(), + Classification::forThrow(PotentialThrowReason::forThrow(), /*async*/false)); return ShouldRecurse; } From 05f418a025d9395d2d2efc7b76ad3b91a3daf184 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 10 Aug 2020 13:31:40 -0700 Subject: [PATCH 106/123] Remove CodableConformanceType This complexity is due to the implementation constraints of Codable synthesis at a time when the type checker could return partially-validated results. This is no longer the case, so all of this code is just technical debt. --- lib/Sema/DerivedConformanceCodable.cpp | 150 +++++-------------------- 1 file changed, 31 insertions(+), 119 deletions(-) diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index 2c5fb8ae6018c..bf6bc6d14cb7d 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -61,59 +61,6 @@ static bool superclassIsDecodable(ClassDecl *target) { C.getProtocol(KnownProtocolKind::Decodable)); } -/// Represents the possible outcomes of checking whether a decl conforms to -/// Encodable or Decodable. -enum CodableConformanceType { - TypeNotValidated, - DoesNotConform, - Conforms -}; - -/// Returns whether the given type conforms to the given {En,De}codable -/// protocol. -/// -/// \param context The \c DeclContext the var declarations belong to. -/// -/// \param target The \c Type to validate. -/// -/// \param proto The \c ProtocolDecl to check conformance to. -static CodableConformanceType typeConformsToCodable(DeclContext *context, - Type target, bool isIUO, - ProtocolDecl *proto) { - target = context->mapTypeIntoContext(target); - - if (isIUO) - target = target->lookThroughSingleOptionalType(); - - auto conf = TypeChecker::conformsToProtocol(target, proto, context); - return conf.isInvalid() ? DoesNotConform : Conforms; -} - -/// Returns whether the given variable conforms to the given {En,De}codable -/// protocol. -/// -/// \param DC The \c DeclContext in which to check conformance. -/// -/// \param varDecl The \c VarDecl to validate. -/// -/// \param proto The \c ProtocolDecl to check conformance to. -static CodableConformanceType -varConformsToCodable(DeclContext *DC, VarDecl *varDecl, ProtocolDecl *proto) { - // If the decl doesn't yet have a type, we may be seeing it before the type - // checker has gotten around to evaluating its type. For example: - // - // func foo() { - // let b = Bar(from: decoder) // <- evaluates Bar conformance to Codable, - // // forcing derivation - // } - // - // struct Bar : Codable { - // var x: Int // <- we get to valuate x's var decl here, but its type - // // hasn't yet been evaluated - // } - bool isIUO = varDecl->isImplicitlyUnwrappedOptional(); - return typeConformsToCodable(DC, varDecl->getValueInterfaceType(), isIUO, - proto); } /// Retrieve the variable name for the purposes of encoding/decoding. @@ -164,34 +111,20 @@ static bool validateCodingKeysEnum(DerivedConformance &derived, } // We have a property to map to. Ensure it's {En,De}codable. - auto conformance = - varConformsToCodable(conformanceDC, it->second, derived.Protocol); - switch (conformance) { - case Conforms: - // The property was valid. Remove it from the list. - properties.erase(it); - break; - - case DoesNotConform: { - // We use a TypeLoc here so diagnostics can show the type - // as written by the user in source if possible. This is useful - // when the user has written an IUO type for example, since - // diagnostics would show the type as 'T?' instead of 'T!' if - // we use a Type instead. - TypeLoc typeLoc = { - it->second->getTypeReprOrParentPatternTypeRepr(), - it->second->getType(), - }; - it->second->diagnose(diag::codable_non_conforming_property_here, - derived.getProtocolType(), typeLoc); - LLVM_FALLTHROUGH; - } - - case TypeNotValidated: - // We don't produce a diagnostic for a type which failed to validate. - // This will produce a diagnostic elsewhere anyway. - propertiesAreValid = false; - continue; + auto target = + conformanceDC->mapTypeIntoContext(it->second->getValueInterfaceType()); + if (TypeChecker::conformsToProtocol(target, derived.Protocol, conformanceDC) + .isInvalid()) { + TypeLoc typeLoc = { + it->second->getTypeReprOrParentPatternTypeRepr(), + it->second->getType(), + }; + it->second->diagnose(diag::codable_non_conforming_property_here, + derived.getProtocolType(), typeLoc); + propertiesAreValid = false; + } else { + // The property was valid. Remove it from the list. + properties.erase(it); } } @@ -344,44 +277,23 @@ static EnumDecl *synthesizeCodingKeysEnum(DerivedConformance &derived) { if (!varDecl->isUserAccessible()) continue; - // Despite creating the enum in the context of the type, we're - // concurrently checking the variables for the current protocol - // conformance being synthesized, for which we use the conformance - // context, not the type. - auto conformance = varConformsToCodable(derived.getConformanceContext(), - varDecl, derived.Protocol); - switch (conformance) { - case Conforms: - { - auto *elt = new (C) EnumElementDecl(SourceLoc(), - getVarNameForCoding(varDecl), - nullptr, SourceLoc(), nullptr, - enumDecl); - elt->setImplicit(); - enumDecl->addMember(elt); - break; - } - - case DoesNotConform: { - // We use a TypeLoc here so diagnostics can show the type - // as written by the user in source if possible. This is useful - // when the user has written an IUO type for example, since - // diagnostics would show the type as 'T?' instead of 'T!' if - // we use a Type instead. - TypeLoc typeLoc = { - varDecl->getTypeReprOrParentPatternTypeRepr(), - varDecl->getType(), - }; - varDecl->diagnose(diag::codable_non_conforming_property_here, - derived.getProtocolType(), typeLoc); - LLVM_FALLTHROUGH; - } - - case TypeNotValidated: - // We don't produce a diagnostic for a type which failed to validate. - // This will produce a diagnostic elsewhere anyway. - allConform = false; - continue; + auto target = + conformanceDC->mapTypeIntoContext(varDecl->getValueInterfaceType()); + if (TypeChecker::conformsToProtocol(target, derived.Protocol, conformanceDC) + .isInvalid()) { + TypeLoc typeLoc = { + varDecl->getTypeReprOrParentPatternTypeRepr(), + varDecl->getType(), + }; + varDecl->diagnose(diag::codable_non_conforming_property_here, + derived.getProtocolType(), typeLoc); + allConform = false; + } else { + auto *elt = + new (C) EnumElementDecl(SourceLoc(), getVarNameForCoding(varDecl), + nullptr, SourceLoc(), nullptr, enumDecl); + elt->setImplicit(); + enumDecl->addMember(elt); } } From 3b9b5400c297fd7368bff3ebd9b1214e0f9e5e24 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 10 Aug 2020 14:29:22 -0700 Subject: [PATCH 107/123] Clean up modeling of CodingKeysValidity The quad-state here is completely superfluous. Break it down into an enum class that encodes the relevant cases we care about and clean up its sole caller. --- lib/Sema/DerivedConformanceCodable.cpp | 49 ++++++++++++++------------ 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index bf6bc6d14cb7d..29648cc0445fa 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -75,7 +75,7 @@ static Identifier getVarNameForCoding(VarDecl *var) { /// match with the stored vars of the given type. /// /// \param codingKeysDecl The \c CodingKeys enum decl to validate. -static bool validateCodingKeysEnum(DerivedConformance &derived, +static bool validateCodingKeysEnum(const DerivedConformance &derived, EnumDecl *codingKeysDecl) { auto conformanceDC = derived.getConformanceContext(); @@ -160,11 +160,14 @@ static bool validateCodingKeysEnum(DerivedConformance &derived, } /// A type which has information about the validity of an encountered -/// CodingKeys type. -struct CodingKeysValidity { - bool hasType; - bool isValid; - CodingKeysValidity(bool ht, bool iv) : hasType(ht), isValid(iv) {} +/// \c CodingKeys type. +enum class CodingKeysClassification { + /// A \c CodingKeys declaration was found, but it is invalid. + Invalid, + /// No \c CodingKeys declaration was found, so it must be synthesized. + NeedsSynthesizedCodingKeys, + /// A valid \c CodingKeys declaration was found. + Valid, }; /// Returns whether the given type has a valid nested \c CodingKeys enum. @@ -176,12 +179,14 @@ struct CodingKeysValidity { /// enum. /// /// \returns A \c CodingKeysValidity value representing the result of the check. -static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) { +static CodingKeysClassification +classifyCodingKeys(const DerivedConformance &derived) { auto &C = derived.Context; auto codingKeysDecls = derived.Nominal->lookupDirect(DeclName(C.Id_CodingKeys)); - if (codingKeysDecls.empty()) - return CodingKeysValidity(/*hasType=*/false, /*isValid=*/true); + if (codingKeysDecls.empty()) { + return CodingKeysClassification::NeedsSynthesizedCodingKeys; + } // Only ill-formed code would produce multiple results for this lookup. // This would get diagnosed later anyway, so we're free to only look at the @@ -192,7 +197,7 @@ static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) { if (!codingKeysTypeDecl) { result->diagnose(diag::codable_codingkeys_type_is_not_an_enum_here, derived.getProtocolType()); - return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); + return CodingKeysClassification::Invalid; } // CodingKeys may be a typealias. If so, follow the alias to its canonical @@ -216,7 +221,7 @@ static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) { C.Diags.diagnose(loc, diag::codable_codingkeys_type_does_not_conform_here, derived.getProtocolType()); - return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); + return CodingKeysClassification::Invalid; } // CodingKeys must be an enum for synthesized conformance. @@ -225,11 +230,12 @@ static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) { codingKeysTypeDecl->diagnose( diag::codable_codingkeys_type_is_not_an_enum_here, derived.getProtocolType()); - return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); + return CodingKeysClassification::Invalid; } - bool valid = validateCodingKeysEnum(derived, codingKeysEnum); - return CodingKeysValidity(/*hasType=*/true, /*isValid=*/valid); + return validateCodingKeysEnum(derived, codingKeysEnum) + ? CodingKeysClassification::Valid + : CodingKeysClassification::Invalid; } /// Synthesizes a new \c CodingKeys enum based on the {En,De}codable members of @@ -1071,19 +1077,18 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) { // If the target already has a valid CodingKeys enum, we won't need to // synthesize one. - auto validity = hasValidCodingKeysEnum(derived); - - // We found a type, but it wasn't valid. - if (!validity.isValid) + switch (classifyCodingKeys(derived)) { + case CodingKeysClassification::Invalid: return false; - - // We can try to synthesize a type here. - if (!validity.hasType) { + case CodingKeysClassification::NeedsSynthesizedCodingKeys: { auto *synthesizedEnum = synthesizeCodingKeysEnum(derived); if (!synthesizedEnum) return false; + } + LLVM_FALLTHROUGH; + case CodingKeysClassification::Valid: + return true; } - return true; } From aada983ceb4f43cc23f2bbd4fef62eeaab1f6d23 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 10 Aug 2020 14:29:34 -0700 Subject: [PATCH 108/123] Replace supersuperclassConformsTo This more powerful primitive is capable of 1) Detecting invalid classes 2) Detecting invalid superclasses 3) Detecting circularity in inheritance hierarchies The attached crasher demonstrates the reason we need to validate all of these predicates. Simply put, a circular class hierarchy is always going to report the superclass conforms to any protocol with a declaration in the source. Leveraging this, one could construct any circular class hierarchy, and a conformance to Codable would immediately crash because we got as far as trying to build a CodingKeys enum with an absolutely nonsensical structure. This also has the added benefit of de-complecting an enormous amount of codable conformance code. rdar://66588925 --- lib/Sema/DerivedConformanceCodable.cpp | 85 +++++++------------ .../rdar66588925.swift | 4 + 2 files changed, 34 insertions(+), 55 deletions(-) create mode 100644 validation-test/compiler_crashers_2_fixed/rdar66588925.swift diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index 29648cc0445fa..701189126dc34 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -29,38 +29,15 @@ using namespace swift; /// Returns whether the type represented by the given ClassDecl inherits from a /// type which conforms to the given protocol. -/// -/// \param target The \c ClassDecl whose superclass to look up. -/// -/// \param proto The protocol to check conformance for. -static bool inheritsConformanceTo(ClassDecl *target, ProtocolDecl *proto) { - if (!target->hasSuperclass()) +static bool superclassConformsTo(ClassDecl *target, KnownProtocolKind kpk) { + if (!target || !target->getSuperclass() || target->hasCircularInheritance()) { return false; - - auto *superclassDecl = target->getSuperclassDecl(); - auto *superclassModule = superclassDecl->getModuleContext(); - return (bool)superclassModule->lookupConformance(target->getSuperclass(), - proto); -} - -/// Returns whether the superclass of the given class conforms to Encodable. -/// -/// \param target The \c ClassDecl whose superclass to check. -static bool superclassIsEncodable(ClassDecl *target) { - auto &C = target->getASTContext(); - return inheritsConformanceTo(target, - C.getProtocol(KnownProtocolKind::Encodable)); -} - -/// Returns whether the superclass of the given class conforms to Decodable. -/// -/// \param target The \c ClassDecl whose superclass to check. -static bool superclassIsDecodable(ClassDecl *target) { - auto &C = target->getASTContext(); - return inheritsConformanceTo(target, - C.getProtocol(KnownProtocolKind::Decodable)); -} - + } + return !target->getSuperclassDecl() + ->getModuleContext() + ->lookupConformance(target->getSuperclass(), + target->getASTContext().getProtocol(kpk)) + .isInvalid(); } /// Retrieve the variable name for the purposes of encoding/decoding. @@ -134,25 +111,22 @@ static bool validateCodingKeysEnum(const DerivedConformance &derived, // If there are any remaining properties which the CodingKeys did not cover, // we can skip them on encode. On decode, though, we can only skip them if // they have a default value. - if (!properties.empty() && - derived.Protocol->isSpecificProtocol(KnownProtocolKind::Decodable)) { - for (auto it = properties.begin(); it != properties.end(); ++it) { - // If the var is default initializable, then it need not have an explicit - // initial value. - auto *varDecl = it->second; - if (auto pbd = varDecl->getParentPatternBinding()) { - if (pbd->isDefaultInitializable()) - continue; + if (derived.Protocol->isSpecificProtocol(KnownProtocolKind::Decodable)) { + for (auto &entry : properties) { + const auto *pbd = entry.second->getParentPatternBinding(); + if (pbd && pbd->isDefaultInitializable()) { + continue; } - if (varDecl->isParentInitialized()) + if (entry.second->isParentInitialized()) { continue; + } // The var was not default initializable, and did not have an explicit // initial value. propertiesAreValid = false; - it->second->diagnose(diag::codable_non_decoded_property_here, - derived.getProtocolType(), it->first); + entry.second->diagnose(diag::codable_non_decoded_property_here, + derived.getProtocolType(), entry.first); } } @@ -265,8 +239,8 @@ static EnumDecl *synthesizeCodingKeysEnum(DerivedConformance &derived) { // For classes which inherit from something Encodable or Decodable, we // provide case `super` as the first key (to be used in encoding super). auto *classDecl = dyn_cast(target); - if (classDecl && - (superclassIsEncodable(classDecl) || superclassIsDecodable(classDecl))) { + if (superclassConformsTo(classDecl, KnownProtocolKind::Encodable) || + superclassConformsTo(classDecl, KnownProtocolKind::Decodable)) { // TODO: Ensure the class doesn't already have or inherit a variable named // "`super`"; otherwise we will generate an invalid enum. In that case, // diagnose and bail. @@ -279,9 +253,11 @@ static EnumDecl *synthesizeCodingKeysEnum(DerivedConformance &derived) { // Each of these vars needs a case in the enum. For each var decl, if the type // conforms to {En,De}codable, add it to the enum. bool allConform = true; + auto *conformanceDC = derived.getConformanceContext(); for (auto *varDecl : target->getStoredProperties()) { - if (!varDecl->isUserAccessible()) + if (!varDecl->isUserAccessible()) { continue; + } auto target = conformanceDC->mapTypeIntoContext(varDecl->getValueInterfaceType()); @@ -578,8 +554,8 @@ deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl, void *) { } // Classes which inherit from something Codable should encode super as well. - auto *classDecl = dyn_cast(targetDecl); - if (classDecl && superclassIsEncodable(classDecl)) { + if (superclassConformsTo(dyn_cast(targetDecl), + KnownProtocolKind::Encodable)) { // Need to generate `try super.encode(to: container.superEncoder())` // superEncoder() @@ -661,8 +637,8 @@ static FuncDecl *deriveEncodable_encode(DerivedConformance &derived) { // This method should be marked as 'override' for classes inheriting Encodable // conformance from a parent class. - auto *classDecl = dyn_cast(derived.Nominal); - if (classDecl && superclassIsEncodable(classDecl)) { + if (superclassConformsTo(dyn_cast(derived.Nominal), + KnownProtocolKind::Encodable)) { auto *attr = new (C) OverrideAttr(/*IsImplicit=*/true); encodeDecl->getAttrs().add(attr); } @@ -869,7 +845,7 @@ deriveBodyDecodable_init(AbstractFunctionDecl *initDecl, void *) { // superclass is Decodable, or super.init() if it is not. if (auto *classDecl = dyn_cast(targetDecl)) { if (auto *superclassDecl = classDecl->getSuperclassDecl()) { - if (superclassIsDecodable(classDecl)) { + if (superclassConformsTo(classDecl, KnownProtocolKind::Decodable)) { // Need to generate `try super.init(from: container.superDecoder())` // container.superDecoder @@ -903,7 +879,8 @@ deriveBodyDecodable_init(AbstractFunctionDecl *initDecl, void *) { statements.push_back(tryExpr); } else { // The explicit constructor name is a compound name taking no arguments. - DeclName initName(C, DeclBaseName::createConstructor(), ArrayRef()); + DeclName initName(C, DeclBaseName::createConstructor(), + ArrayRef()); // We need to look this up in the superclass to see if it throws. auto result = superclassDecl->lookupDirect(initName); @@ -1075,8 +1052,6 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) { } } - // If the target already has a valid CodingKeys enum, we won't need to - // synthesize one. switch (classifyCodingKeys(derived)) { case CodingKeysClassification::Invalid: return false; @@ -1084,7 +1059,7 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) { auto *synthesizedEnum = synthesizeCodingKeysEnum(derived); if (!synthesizedEnum) return false; - } + } LLVM_FALLTHROUGH; case CodingKeysClassification::Valid: return true; diff --git a/validation-test/compiler_crashers_2_fixed/rdar66588925.swift b/validation-test/compiler_crashers_2_fixed/rdar66588925.swift new file mode 100644 index 0000000000000..ac94cbceb3c1e --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar66588925.swift @@ -0,0 +1,4 @@ +// RUN: not %target-swift-frontend -typecheck %s + +class DataType: DataType {} +extension DataType: Encodable {} From fbbb2bb2eeb8ca25ca5a5dedeefd68a26c3cdec4 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 15:25:48 -0700 Subject: [PATCH 109/123] [Effects handling] Eliminate Context::Kind::NonExhaustiveCatch. This kind was too specific to error handling; use a bit instead. --- lib/Sema/TypeCheckEffects.cpp | 48 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 15a3fb40feaab..9fe57f11448a0 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -816,7 +816,7 @@ class ApplyClassifier { } }; -/// An error-handling context. +/// An context in which effects might be handled. class Context { public: enum class Kind : uint8_t { @@ -832,9 +832,6 @@ class Context { /// A non-throwing autoclosure. NonThrowingAutoClosure, - /// A non-exhaustive catch within a non-throwing function. - NonExhaustiveCatch, - /// A default argument expression. DefaultArgument, @@ -887,6 +884,7 @@ class Context { } Kind TheKind; + bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; DeclContext *RethrowsDC = nullptr; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; @@ -956,10 +954,6 @@ class Context { return Context(kind); } - static Context forNonExhaustiveCatch(DoCatchStmt *S) { - return Context(Kind::NonExhaustiveCatch); - } - static Context forCatchPattern(CaseStmt *S) { return Context(Kind::CatchPattern); } @@ -1006,6 +1000,10 @@ class Context { return InterpolatedString; } + void setNonExhaustiveCatch(bool value) { + IsNonExhaustiveCatch = value; + } + static void diagnoseThrowInIllegalContext(DiagnosticEngine &Diags, ASTNode node, StringRef description) { @@ -1103,8 +1101,7 @@ class Context { // Allow the diagnostic to fire on the 'try' if we don't have // anything else to say. if (isTryCovered && !reason.isRethrowsCall() && - (getKind() == Kind::NonThrowingFunction || - getKind() == Kind::NonExhaustiveCatch)) { + getKind() == Kind::NonThrowingFunction) { DiagnoseErrorOnTry = true; return; } @@ -1136,6 +1133,14 @@ class Context { return; case Kind::NonThrowingFunction: + if (IsNonExhaustiveCatch) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_nonexhaustive_catch, + diag::throwing_call_in_nonexhaustive_catch, + diag::tryless_throwing_call_in_nonexhaustive_catch); + return; + } + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, diag::throw_in_nonthrowing_function, diag::throwing_call_unhandled, @@ -1149,13 +1154,6 @@ class Context { diag::tryless_throwing_call_in_nonthrowing_autoclosure); return; - case Kind::NonExhaustiveCatch: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_nonexhaustive_catch, - diag::throwing_call_in_nonexhaustive_catch, - diag::tryless_throwing_call_in_nonexhaustive_catch); - return; - case Kind::EnumElementInitializer: diagnoseThrowInIllegalContext(Diags, E, "an enum case raw value"); return; @@ -1193,14 +1191,12 @@ class Context { llvm_unreachable("try is handled!"); case Kind::NonThrowingFunction: - if (DiagnoseErrorOnTry) - Diags.diagnose(E->getTryLoc(), diag::try_unhandled); - return; - - case Kind::NonExhaustiveCatch: - if (DiagnoseErrorOnTry) - Diags.diagnose(E->getTryLoc(), - diag::try_unhandled_in_nonexhaustive_catch); + if (DiagnoseErrorOnTry) { + Diags.diagnose( + E->getTryLoc(), + IsNonExhaustiveCatch ? diag::try_unhandled_in_nonexhaustive_catch + : diag::try_unhandled); + } return; case Kind::NonThrowingAutoClosure: @@ -1441,7 +1437,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker // If the enclosing context doesn't handle anything, use a // specialized diagnostic about non-exhaustive catches. if (CurContext.handlesNothing()) { - scope.refineLocalContext(Context::forNonExhaustiveCatch(S)); + CurContext.setNonExhaustiveCatch(true); } S->getBody()->walk(*this); From f24b7636f9866ba74866de2f1a4c64424e7bb85e Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 15:37:35 -0700 Subject: [PATCH 110/123] [Effects handling] Simplify away getKindForFunctionBody(). Determining whether a given function or closure is throwing got a lot simpler since this code was written. Do the obvious thing. --- lib/Sema/TypeCheckEffects.cpp | 37 +++++++++++------------------------ 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 9fe57f11448a0..c76e0a4891203 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -855,26 +855,6 @@ class Context { }; private: - static Kind getKindForFunctionBody(Type type, unsigned numArgs) { - /// Determine whether calling a function of the specified type with the - /// specified number of arguments would throw. - if (!type) return Kind::Handled; - - assert(numArgs > 0); - while (true) { - auto fnType = type->getAs(); - if (!fnType) return Kind::Handled; - - if (fnType->getExtInfo().isThrowing()) - return Kind::Handled; - - if (--numArgs == 0) - return Kind::NonThrowingFunction; - - type = fnType->getResult(); - } - } - static Context getContextForPatternBinding(PatternBindingDecl *pbd) { if (!pbd->isStatic() && pbd->getDeclContext()->isTypeContext()) { return Context(Kind::IVarInitializer); @@ -924,8 +904,7 @@ class Context { } } - return Context(getKindForFunctionBody( - D->getInterfaceType(), D->getNumCurryLevels())); + return Context(D->hasThrows() ? Kind::Handled : Kind::NonThrowingFunction); } static Context forDeferBody() { @@ -948,10 +927,16 @@ class Context { } static Context forClosure(AbstractClosureExpr *E) { - auto kind = getKindForFunctionBody(E->getType(), 1); - if (kind != Kind::Handled && isa(E)) - kind = Kind::NonThrowingAutoClosure; - return Context(kind); + // Determine whether the closure has throwing function type. + bool closureTypeThrows = true; + if (auto closureType = E->getType()) { + if (auto fnType = closureType->getAs()) + closureTypeThrows = fnType->isThrowing(); + } + + return Context(closureTypeThrows ? Kind::Handled + : isa(E) ? Kind::NonThrowingAutoClosure + : Kind::NonThrowingFunction); } static Context forCatchPattern(CaseStmt *S) { From f40de805c66cf3182008d7bff83b76d256db90a7 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 15:58:55 -0700 Subject: [PATCH 111/123] [Effects handling] Eliminate Context::Kind::NonThrowingAutoClosure. --- lib/Sema/TypeCheckEffects.cpp | 47 ++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index c76e0a4891203..7b691fec8c6fd 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -829,9 +829,6 @@ class Context { /// A rethrowing function. RethrowingFunction, - /// A non-throwing autoclosure. - NonThrowingAutoClosure, - /// A default argument expression. DefaultArgument, @@ -864,12 +861,26 @@ class Context { } Kind TheKind; + Optional Function; bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; DeclContext *RethrowsDC = nullptr; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; - explicit Context(Kind kind) : TheKind(kind) {} + explicit Context(Kind kind, Optional function = None) + : TheKind(kind), Function(function) {} + + /// Whether this is an autoclosure. + bool isAutoClosure() const { + if (!Function) + return false; + + auto closure = Function->getAbstractClosureExpr(); + if (!closure) + return false; + + return isa(closure); + } public: static Context getHandled() { @@ -883,7 +894,7 @@ class Context { static Context forFunction(AbstractFunctionDecl *D) { if (D->getAttrs().hasAttribute()) { - Context result(Kind::RethrowingFunction); + Context result(Kind::RethrowingFunction, AnyFunctionRef(D)); result.RethrowsDC = D; return result; } @@ -904,7 +915,8 @@ class Context { } } - return Context(D->hasThrows() ? Kind::Handled : Kind::NonThrowingFunction); + return Context(D->hasThrows() ? Kind::Handled : Kind::NonThrowingFunction, + AnyFunctionRef(D)); } static Context forDeferBody() { @@ -935,8 +947,8 @@ class Context { } return Context(closureTypeThrows ? Kind::Handled - : isa(E) ? Kind::NonThrowingAutoClosure - : Kind::NonThrowingFunction); + : Kind::NonThrowingFunction, + AnyFunctionRef(E)); } static Context forCatchPattern(CaseStmt *S) { @@ -1086,7 +1098,8 @@ class Context { // Allow the diagnostic to fire on the 'try' if we don't have // anything else to say. if (isTryCovered && !reason.isRethrowsCall() && - getKind() == Kind::NonThrowingFunction) { + getKind() == Kind::NonThrowingFunction && + !isAutoClosure()) { DiagnoseErrorOnTry = true; return; } @@ -1126,19 +1139,20 @@ class Context { return; } + if (isAutoClosure()) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_nonthrowing_autoclosure, + diag::throwing_call_in_nonthrowing_autoclosure, + diag::tryless_throwing_call_in_nonthrowing_autoclosure); + return; + } + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, diag::throw_in_nonthrowing_function, diag::throwing_call_unhandled, diag::tryless_throwing_call_unhandled); return; - case Kind::NonThrowingAutoClosure: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_nonthrowing_autoclosure, - diag::throwing_call_in_nonthrowing_autoclosure, - diag::tryless_throwing_call_in_nonthrowing_autoclosure); - return; - case Kind::EnumElementInitializer: diagnoseThrowInIllegalContext(Diags, E, "an enum case raw value"); return; @@ -1184,7 +1198,6 @@ class Context { } return; - case Kind::NonThrowingAutoClosure: case Kind::EnumElementInitializer: case Kind::GlobalVarInitializer: case Kind::IVarInitializer: From 7cee2bf4877d240546c2fa9fdc1d6114e0c16422 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 10 Aug 2020 16:23:56 -0700 Subject: [PATCH 112/123] Windows: include `direct.h` in `sys.stat` module On Unicies `sys/stat.h` will provide `mkdir`. Windows provides the POSIX requirement through the portable name `_mkdir` which is declared in the `direct.h` header. This adds the additional header to the `ucrt` module to allow access to this function. --- stdlib/public/Platform/ucrt.modulemap | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/public/Platform/ucrt.modulemap b/stdlib/public/Platform/ucrt.modulemap index 03fe87bf74451..2d88621038f4a 100644 --- a/stdlib/public/Platform/ucrt.modulemap +++ b/stdlib/public/Platform/ucrt.modulemap @@ -95,6 +95,7 @@ module ucrt [system] { module stat { header "sys/stat.h" + header "direct.h" export * } From d62e9ddd9ec2b1b622cb898ea7e3fa4ab66821e6 Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Mon, 10 Aug 2020 20:27:56 -0300 Subject: [PATCH 113/123] [Diagnostics] Minor adjustments on MissingMember tuple base and yaml message --- lib/Sema/CSDiagnostics.cpp | 8 +++----- localization/diagnostics/en.yaml | 6 ++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index b1614a91bfe7b..4791518b68816 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3435,7 +3435,8 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { auto locator = getLocator(); auto baseType = resolveType(getBaseType())->getWithoutSpecifierType(); - if (!locator->isLastElement()) + auto *SE = getAsExpr(locator->getAnchor()); + if (!SE) return false; auto tupleType = baseType->getAs(); @@ -3444,9 +3445,7 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { if (!tupleType || tupleType->getNumElements() == 0) return false; - auto *SE = castToExpr(locator->getAnchor()); auto *index = SE->getIndex(); - if (SE->getNumArguments() == 1) { auto *literal = dyn_cast(index->getSemanticsProvidingExpr()); @@ -3481,8 +3480,7 @@ bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { dyn_cast(index->getSemanticsProvidingExpr()); if (stringLiteral && !stringLiteral->getValue().empty() && llvm::any_of(tupleType->getElements(), [&](TupleTypeElt element) { - return !element.getName().empty() && - element.getName().str() == stringLiteral->getValue(); + return element.getName().is(stringLiteral->getValue()); })) { llvm::SmallString<16> dotAccess; llvm::raw_svector_ostream OS(dotAccess); diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index 2bfd50fe0cad4..8c3be67b2c0db 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -2969,13 +2969,11 @@ - id: could_not_find_subscript_member_tuple msg: >- - cannot access element using subscript for tuple type %0; - use '.' notation instead + cannot access element using subscript for tuple type %0; use '.' notation instead - id: could_not_find_subscript_member_tuple_did_you_mean_use_dot msg: >- - cannot access element using subscript for tuple type %0; - did you mean to use '.%1'? + cannot access element using subscript for tuple type %0; did you mean to use '.%1'? - id: could_not_find_enum_case msg: >- From ac6683994a4b1016701a7743b6b28fc14a4539b2 Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Mon, 10 Aug 2020 17:22:26 -0700 Subject: [PATCH 114/123] [Disable] SILOptimizer test (66807959) --- validation-test/SILOptimizer/large_string_array.swift.gyb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validation-test/SILOptimizer/large_string_array.swift.gyb b/validation-test/SILOptimizer/large_string_array.swift.gyb index 6285e4b97c75b..91280bd424040 100644 --- a/validation-test/SILOptimizer/large_string_array.swift.gyb +++ b/validation-test/SILOptimizer/large_string_array.swift.gyb @@ -12,6 +12,8 @@ // REQUIRES: long_test // REQUIRES: CPU=arm64 || CPU=x86_64 +// REQUIRES: rdar66807959 + // Check if the optimizer can optimize the whole array into a statically // initialized global From 7de957362e05ff5960b39cd0739923e8d9c88bc9 Mon Sep 17 00:00:00 2001 From: tbkka Date: Mon, 10 Aug 2020 18:40:57 -0700 Subject: [PATCH 115/123] Don't verify exact NaN text for .debugDescription (#33391) This specific check has never worked on all processors (because some FP HW mangles NaNs) and recent LLVM changes have broken it on the remaining platforms. Resolves SR-13354 --- test/stdlib/PrintFloat.swift.gyb | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/test/stdlib/PrintFloat.swift.gyb b/test/stdlib/PrintFloat.swift.gyb index 8556d875368d9..2795a1c8a3473 100644 --- a/test/stdlib/PrintFloat.swift.gyb +++ b/test/stdlib/PrintFloat.swift.gyb @@ -442,21 +442,20 @@ fileprivate func expectNaN(_ expected: String, _ object: T, message(), stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)) - // debugDescription prints full details about NaNs, which is tricky to test - // because NaNs often get truncated: various implementations force all NaNs - // quiet, discard payloads, or clear sign bits. In some cases, just passing a - // NaN into a function (via an FP register) is enough to mangle the value. - -#if arch(x86_64) - // Verify the exact debugDescription value only on x86_64, where we - // know the exact expected String: + // debugDescription tries to print details about NaNs, which is tricky to test. + +/* + // We cannot reliably test the exact expected string, because various + // implementations force all NaNs quiet, discard payloads, or clear sign bits. + // In some cases, just passing a NaN into a function (via an FP register) is + // enough to mangle the value. expectEqual(expected, object.debugDescription, message(), stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)) -#endif +*/ - // On all platforms, we verify that the generated debugDescription text - // follows the expected format, even when we can't verify the exact value. + // We can verify that the generated debugDescription text + // follows the expected general format, even when we can't verify the exact value. var actual = object.debugDescription // Optional leading "-" From 524887bb009735c3c5889b7eba16706c6d387df3 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 21:27:56 -0700 Subject: [PATCH 116/123] [Effects handling] Eliminate Context::Kind::RethrowingFunction. We can determine whether we have a rethrowing function based on the function declaration itself. --- lib/Sema/TypeCheckEffects.cpp | 67 +++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 7b691fec8c6fd..36bce683caca3 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -826,9 +826,6 @@ class Context { /// A non-throwing function. NonThrowingFunction, - /// A rethrowing function. - RethrowingFunction, - /// A default argument expression. DefaultArgument, @@ -864,12 +861,27 @@ class Context { Optional Function; bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; - DeclContext *RethrowsDC = nullptr; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; explicit Context(Kind kind, Optional function = None) : TheKind(kind), Function(function) {} +public: + /// Whether this is a function that rethrows. + bool isRethrows() const { + if (getKind() != Kind::Handled) + return false; + + if (!Function) + return false; + + auto fn = Function->getAbstractFunctionDecl(); + if (!fn) + return false; + + return fn->getAttrs().hasAttribute(); + } + /// Whether this is an autoclosure. bool isAutoClosure() const { if (!Function) @@ -882,7 +894,6 @@ class Context { return isa(closure); } -public: static Context getHandled() { return Context(Kind::Handled); } @@ -893,12 +904,6 @@ class Context { } static Context forFunction(AbstractFunctionDecl *D) { - if (D->getAttrs().hasAttribute()) { - Context result(Kind::RethrowingFunction, AnyFunctionRef(D)); - result.RethrowsDC = D; - return result; - } - // HACK: If the decl is the synthesized getter for a 'lazy' property, then // treat the context as a property initializer in order to produce a better // diagnostic; the only code we should be diagnosing on is within the @@ -972,8 +977,7 @@ class Context { Kind getKind() const { return TheKind; } bool handlesNothing() const { - return getKind() != Kind::Handled && - getKind() != Kind::RethrowingFunction; + return getKind() != Kind::Handled; } bool handles(ThrowingKind errorKind) const { switch (errorKind) { @@ -982,17 +986,23 @@ class Context { // A call that's rethrowing-only can be handled by 'rethrows'. case ThrowingKind::RethrowingOnly: - return !handlesNothing(); + return getKind() == Kind::Handled; // An operation that always throws can only be handled by an // all-handling context. case ThrowingKind::Throws: - return getKind() == Kind::Handled; + return getKind() == Kind::Handled && !isRethrows(); } llvm_unreachable("bad error kind"); } - DeclContext *getRethrowsDC() const { return RethrowsDC; } + DeclContext *getRethrowsDC() const { + if (!isRethrows()) + return nullptr; + + return Function->getAbstractFunctionDecl(); + } + InterpolatedStringLiteralExpr * getInterpolatedString() const { return InterpolatedString; } @@ -1098,8 +1108,7 @@ class Context { // Allow the diagnostic to fire on the 'try' if we don't have // anything else to say. if (isTryCovered && !reason.isRethrowsCall() && - getKind() == Kind::NonThrowingFunction && - !isAutoClosure()) { + !isRethrows() && !isAutoClosure()) { DiagnoseErrorOnTry = true; return; } @@ -1117,18 +1126,15 @@ class Context { const PotentialThrowReason &reason) { switch (getKind()) { case Kind::Handled: - llvm_unreachable("throw site is handled!"); - - // TODO: Doug suggested that we could generate one error per - // non-throwing function with throw sites within it, possibly with - // notes for the throw sites. + if (isRethrows()) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_rethrows_function, + diag::throwing_call_in_rethrows_function, + diag::tryless_throwing_call_in_rethrows_function); + return; + } - case Kind::RethrowingFunction: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_rethrows_function, - diag::throwing_call_in_rethrows_function, - diag::tryless_throwing_call_in_rethrows_function); - return; + llvm_unreachable("throw site is handled!"); case Kind::NonThrowingFunction: if (IsNonExhaustiveCatch) { @@ -1186,7 +1192,6 @@ class Context { void diagnoseUnhandledTry(DiagnosticEngine &Diags, TryExpr *E) { switch (getKind()) { case Kind::Handled: - case Kind::RethrowingFunction: llvm_unreachable("try is handled!"); case Kind::NonThrowingFunction: @@ -1471,7 +1476,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker auto savedContext = CurContext; if (doThrowingKind != ThrowingKind::Throws && - CurContext.getKind() == Context::Kind::RethrowingFunction) { + CurContext.isRethrows()) { // If this catch clause is reachable at all, it's because a function // parameter throws. So let's temporarily set our context to Handled so // the catch body is allowed to throw. From ea8217ad7eae8b259d914c27edaf38cefd613604 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 21:50:06 -0700 Subject: [PATCH 117/123] [Effects handling] Collapse "Handled" and "NonThrowingFunction" kinds. Finish eliminating error-handling-specific information from the "kind" of the effects-handling context, so that it only distinguishes between "potentially handles effects" and "never handles effects". Use queries for specific issues (e.g., "handles errors") instead. --- lib/Sema/TypeCheckEffects.cpp | 66 ++++++++++++++++------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 36bce683caca3..c291217d99270 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -820,11 +820,8 @@ class ApplyClassifier { class Context { public: enum class Kind : uint8_t { - /// A context that handles errors. - Handled, - - /// A non-throwing function. - NonThrowingFunction, + /// A context that potentially handles errors or async calls. + PotentiallyHandled, /// A default argument expression. DefaultArgument, @@ -859,17 +856,24 @@ class Context { Kind TheKind; Optional Function; + bool HandlesErrors = false; bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; - explicit Context(Kind kind, Optional function = None) - : TheKind(kind), Function(function) {} + explicit Context(Kind kind) + : TheKind(kind), Function(None), HandlesErrors(false) { + assert(TheKind != Kind::PotentiallyHandled); + } + + explicit Context(bool handlesErrors, Optional function) + : TheKind(Kind::PotentiallyHandled), Function(function), + HandlesErrors(handlesErrors) { } public: /// Whether this is a function that rethrows. bool isRethrows() const { - if (getKind() != Kind::Handled) + if (!HandlesErrors) return false; if (!Function) @@ -895,12 +899,12 @@ class Context { } static Context getHandled() { - return Context(Kind::Handled); + return Context(/*handlesErrors=*/true, None); } static Context forTopLevelCode(TopLevelCodeDecl *D) { - // Top-level code implicitly handles errors. - return Context(Kind::Handled); + // Top-level code implicitly handles errors and 'async' calls. + return Context(/*handlesErrors=*/true, None); } static Context forFunction(AbstractFunctionDecl *D) { @@ -920,8 +924,8 @@ class Context { } } - return Context(D->hasThrows() ? Kind::Handled : Kind::NonThrowingFunction, - AnyFunctionRef(D)); + bool handlesErrors = D->hasThrows(); + return Context(handlesErrors, AnyFunctionRef(D)); } static Context forDeferBody() { @@ -951,9 +955,7 @@ class Context { closureTypeThrows = fnType->isThrowing(); } - return Context(closureTypeThrows ? Kind::Handled - : Kind::NonThrowingFunction, - AnyFunctionRef(E)); + return Context(closureTypeThrows, AnyFunctionRef(E)); } static Context forCatchPattern(CaseStmt *S) { @@ -977,7 +979,7 @@ class Context { Kind getKind() const { return TheKind; } bool handlesNothing() const { - return getKind() != Kind::Handled; + return !HandlesErrors; } bool handles(ThrowingKind errorKind) const { switch (errorKind) { @@ -986,12 +988,12 @@ class Context { // A call that's rethrowing-only can be handled by 'rethrows'. case ThrowingKind::RethrowingOnly: - return getKind() == Kind::Handled; + return HandlesErrors; // An operation that always throws can only be handled by an // all-handling context. case ThrowingKind::Throws: - return getKind() == Kind::Handled && !isRethrows(); + return HandlesErrors && !isRethrows(); } llvm_unreachable("bad error kind"); } @@ -1125,18 +1127,7 @@ class Context { bool isTryCovered, const PotentialThrowReason &reason) { switch (getKind()) { - case Kind::Handled: - if (isRethrows()) { - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_rethrows_function, - diag::throwing_call_in_rethrows_function, - diag::tryless_throwing_call_in_rethrows_function); - return; - } - - llvm_unreachable("throw site is handled!"); - - case Kind::NonThrowingFunction: + case Kind::PotentiallyHandled: if (IsNonExhaustiveCatch) { diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, diag::throw_in_nonexhaustive_catch, @@ -1153,6 +1144,14 @@ class Context { return; } + if (isRethrows()) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_rethrows_function, + diag::throwing_call_in_rethrows_function, + diag::tryless_throwing_call_in_rethrows_function); + return; + } + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, diag::throw_in_nonthrowing_function, diag::throwing_call_unhandled, @@ -1191,10 +1190,7 @@ class Context { void diagnoseUnhandledTry(DiagnosticEngine &Diags, TryExpr *E) { switch (getKind()) { - case Kind::Handled: - llvm_unreachable("try is handled!"); - - case Kind::NonThrowingFunction: + case Kind::PotentiallyHandled: if (DiagnoseErrorOnTry) { Diags.diagnose( E->getTryLoc(), From 90e42bbcd67a31771b301246f4a92c1ffc8fafd6 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 22:11:56 -0700 Subject: [PATCH 118/123] [Effects handling] Eliminate Context::getHandled(). We don't want to expose the notion of "handles everything", because that's a honeypot for messing up 'async' checking when making a context change for error-handling, and vice versa. Instead, provide an API to produce a derived context where all errors are handled, and use it for (e.g.) try/try!/try? and exhaustive do-catches. --- lib/Sema/TypeCheckEffects.cpp | 37 ++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index c291217d99270..bd8b3eeda3f20 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -857,6 +857,10 @@ class Context { Kind TheKind; Optional Function; bool HandlesErrors = false; + + /// Whether error-handling queries should ignore the function context, e.g., + /// for autoclosure and rethrows checks. + bool ErrorHandlingIgnoresFunction = false; bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; @@ -876,6 +880,9 @@ class Context { if (!HandlesErrors) return false; + if (ErrorHandlingIgnoresFunction) + return false; + if (!Function) return false; @@ -891,6 +898,9 @@ class Context { if (!Function) return false; + if (ErrorHandlingIgnoresFunction) + return false; + auto closure = Function->getAbstractClosureExpr(); if (!closure) return false; @@ -898,10 +908,6 @@ class Context { return isa(closure); } - static Context getHandled() { - return Context(/*handlesErrors=*/true, None); - } - static Context forTopLevelCode(TopLevelCodeDecl *D) { // Top-level code implicitly handles errors and 'async' calls. return Context(/*handlesErrors=*/true, None); @@ -976,6 +982,15 @@ class Context { return copy; } + /// Form a subcontext that handles all errors, e.g., for the body of a + /// do-catch with exhaustive catch clauses. + Context withHandlesErrors() const { + Context copy = *this; + copy.HandlesErrors = true; + copy.ErrorHandlingIgnoresFunction = true; + return copy; + } + Kind getKind() const { return TheKind; } bool handlesNothing() const { @@ -1416,8 +1431,8 @@ class CheckEffectsCoverage : public EffectsHandlingWalker } ThrowingKind checkExhaustiveDoBody(DoCatchStmt *S) { - // This is a handled context. - ContextScope scope(*this, Context::getHandled()); + // This is a context where errors are handled. + ContextScope scope(*this, CurContext.withHandlesErrors()); assert(!Flags.has(ContextFlags::IsInTry) && "do/catch within try?"); scope.resetCoverageForDoCatch(); @@ -1474,9 +1489,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker if (doThrowingKind != ThrowingKind::Throws && CurContext.isRethrows()) { // If this catch clause is reachable at all, it's because a function - // parameter throws. So let's temporarily set our context to Handled so - // the catch body is allowed to throw. - CurContext = Context::getHandled(); + // parameter throws. So let's temporarily state that the body is allowed + // to throw. + CurContext = CurContext.withHandlesErrors(); } // The catch body just happens in the enclosing context. @@ -1661,7 +1676,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ShouldRecurse_t checkForceTry(ForceTryExpr *E) { // Walk the operand. 'try!' handles errors. - ContextScope scope(*this, Context::getHandled()); + ContextScope scope(*this, CurContext.withHandlesErrors()); scope.enterTry(); E->getSubExpr()->walk(*this); @@ -1675,7 +1690,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker ShouldRecurse_t checkOptionalTry(OptionalTryExpr *E) { // Walk the operand. 'try?' handles errors. - ContextScope scope(*this, Context::getHandled()); + ContextScope scope(*this, CurContext.withHandlesErrors()); scope.enterTry(); E->getSubExpr()->walk(*this); From 462e37bbf527d6436f6b44f59862ae178603c618 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Aug 2020 22:26:51 -0700 Subject: [PATCH 119/123] [Effects handling] Move "illegal context" strings into diagnostic text. The "illegal context" diagnostics were passing strings from the C++ code directly into diagnostic text for things like "a default argument". That causes a bunch of duplicated code and defeats localization of diagnostics, so move to a %select in the diagnostic. --- include/swift/AST/DiagnosticsSema.def | 9 ++++++--- lib/Sema/TypeCheckEffects.cpp | 26 +++++--------------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index fc9b7f98dd2a0..f4364f6438b1e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4008,10 +4008,13 @@ ERROR(throw_in_nonexhaustive_catch,none, "error is not handled because the enclosing catch is not exhaustive", ()) ERROR(throwing_call_in_illegal_context,none, - "call can throw, but errors cannot be thrown out of %0", - (StringRef)) + "call can throw, but errors cannot be thrown out of " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) ERROR(throw_in_illegal_context,none, - "errors cannot be thrown out of %0", (StringRef)) + "errors cannot be thrown out of " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) ERROR(throwing_operator_without_try,none, "operator can throw but expression is not marked with 'try'", ()) diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index bd8b3eeda3f20..69e7d578fee17 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -1030,17 +1030,17 @@ class Context { static void diagnoseThrowInIllegalContext(DiagnosticEngine &Diags, ASTNode node, - StringRef description) { + Kind kind) { if (auto *e = node.dyn_cast()) { if (isa(e)) { Diags.diagnose(e->getLoc(), diag::throwing_call_in_illegal_context, - description); + static_cast(kind)); return; } } Diags.diagnose(node.getStartLoc(), diag::throw_in_illegal_context, - description); + static_cast(kind)); } static void maybeAddRethrowsNote(DiagnosticEngine &Diags, SourceLoc loc, @@ -1174,31 +1174,15 @@ class Context { return; case Kind::EnumElementInitializer: - diagnoseThrowInIllegalContext(Diags, E, "an enum case raw value"); - return; - case Kind::GlobalVarInitializer: - diagnoseThrowInIllegalContext(Diags, E, "a global variable initializer"); - return; - case Kind::IVarInitializer: - diagnoseThrowInIllegalContext(Diags, E, "a property initializer"); - return; - case Kind::DefaultArgument: - diagnoseThrowInIllegalContext(Diags, E, "a default argument"); - return; - case Kind::CatchPattern: - diagnoseThrowInIllegalContext(Diags, E, "a catch pattern"); - return; - case Kind::CatchGuard: - diagnoseThrowInIllegalContext(Diags, E, "a catch guard expression"); - return; case Kind::DeferBody: - diagnoseThrowInIllegalContext(Diags, E, "a defer body"); + diagnoseThrowInIllegalContext(Diags, E, getKind()); return; + } llvm_unreachable("bad context kind"); } From 4391f4264ecaa17365a0823562d157eabece7b1b Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Tue, 11 Aug 2020 09:14:12 -0700 Subject: [PATCH 120/123] [AutoDiff] Fix `Optional` differentiation crash. (#33386) Fix `Optional` differentiation crash for non-resilient `Wrapped` reference type. Add `NonresilientTracked` type to `DifferentiationUnittest` for testing. Resolves SR-13377. --- .../Differentiation/PullbackCloner.cpp | 13 +- .../DifferentiationUnittest/CMakeLists.txt | 2 +- ...wift => DifferentiationUnittest.swift.gyb} | 206 +++++++----- test/AutoDiff/validation-test/optional.swift | 295 +++++++++++++++--- 4 files changed, 387 insertions(+), 129 deletions(-) rename stdlib/private/DifferentiationUnittest/{DifferentiationUnittest.swift => DifferentiationUnittest.swift.gyb} (50%) diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index 79611c38eaaf4..aa40f16f53d91 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -2056,8 +2056,8 @@ void PullbackCloner::Implementation::accumulateAdjointForOptional( // Find `Optional.some` EnumElementDecl. auto someEltDecl = builder.getASTContext().getOptionalSomeDecl(); - // Initialize a `Optional` buffer from `wrappedAdjoint`as the - // input for `Optional.TangentVector.init`. + // Initialize an `Optional` buffer from `wrappedAdjoint` as + // the input for `Optional.TangentVector.init`. auto *optArgBuf = builder.createAllocStack(pbLoc, optionalOfWrappedTanType); if (optionalOfWrappedTanType.isLoadableOrOpaque(builder.getFunction())) { // %enum = enum $Optional, #Optional.some!enumelt, @@ -2066,7 +2066,7 @@ void PullbackCloner::Implementation::accumulateAdjointForOptional( optionalOfWrappedTanType); // store %enum to %optArgBuf builder.emitStoreValueOperation(pbLoc, enumInst, optArgBuf, - StoreOwnershipQualifier::Trivial); + StoreOwnershipQualifier::Init); } else { // %enumAddr = init_enum_data_addr %optArgBuf $Optional, // #Optional.some!enumelt @@ -2279,14 +2279,15 @@ void PullbackCloner::Implementation::visitSILBasicBlock(SILBasicBlock *bb) { for (auto pair : incomingValues) { auto *predBB = std::get<0>(pair); auto incomingValue = std::get<1>(pair); - blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); // Handle `switch_enum` on `Optional`. auto termInst = bbArg->getSingleTerminator(); - if (isSwitchEnumInstOnOptional(termInst)) + if (isSwitchEnumInstOnOptional(termInst)) { accumulateAdjointForOptional(bb, incomingValue, concreteBBArgAdjCopy); - else + } else { + blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); setAdjointValue(predBB, incomingValue, makeConcreteAdjointValue(concreteBBArgAdjCopy)); + } } break; } diff --git a/stdlib/private/DifferentiationUnittest/CMakeLists.txt b/stdlib/private/DifferentiationUnittest/CMakeLists.txt index bb6284b191310..33da12b9b766a 100644 --- a/stdlib/private/DifferentiationUnittest/CMakeLists.txt +++ b/stdlib/private/DifferentiationUnittest/CMakeLists.txt @@ -1,6 +1,6 @@ add_swift_target_library(swiftDifferentiationUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB # This file should be listed first. Module name is inferred from the filename. - DifferentiationUnittest.swift + GYB_SOURCES DifferentiationUnittest.swift.gyb SWIFT_MODULE_DEPENDS _Differentiation StdlibUnittest INSTALL_IN_COMPONENT stdlib-experimental diff --git a/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift b/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb similarity index 50% rename from stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift rename to stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb index f24dd18a7925e..282f89f93324f 100644 --- a/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift +++ b/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb @@ -1,4 +1,4 @@ -//===--- DifferentiationUnittest.swift ------------------------------------===// +//===--- DifferentiationUnittest.swift.gyb --------------------------------===// // // This source file is part of the Swift.org open source project // @@ -43,19 +43,21 @@ public extension TestSuite { _ testFunction: @escaping () -> Void ) { test(name, file: file, line: line) { - withLeakChecking(expectedLeakCount: expectedLeakCount, file: file, - line: line, testFunction) + withLeakChecking( + expectedLeakCount: expectedLeakCount, file: file, + line: line, testFunction) } } } -/// A type that tracks the number of live instances of a wrapped value type. +/// A resilient type that tracks the number of live instances of a wrapped +/// value type. /// /// `Tracked` is used to check for memory leaks in functions created via /// automatic differentiation. public struct Tracked { - fileprivate class Box { - fileprivate var value : T + internal class Box { + fileprivate var value: T init(_ value: T) { self.value = value _GlobalLeakCount.count += 1 @@ -64,71 +66,109 @@ public struct Tracked { _GlobalLeakCount.count -= 1 } } - private var handle: Box + internal var handle: Box - @differentiable(where T : Differentiable, T == T.TangentVector) + @differentiable(where T: Differentiable, T == T.TangentVector) public init(_ value: T) { self.handle = Box(value) } - @differentiable(where T : Differentiable, T == T.TangentVector) + @differentiable(where T: Differentiable, T == T.TangentVector) public var value: T { get { handle.value } set { handle.value = newValue } } } -extension Tracked : ExpressibleByFloatLiteral where T : ExpressibleByFloatLiteral { +/// A non-resilient type that tracks the number of live instances of a wrapped +/// value type. +/// +/// `NonresilientTracked` is used to check for memory leaks in functions +/// created via automatic differentiation. +@frozen +public struct NonresilientTracked { + @usableFromInline + internal class Box { + fileprivate var value: T + init(_ value: T) { + self.value = value + _GlobalLeakCount.count += 1 + } + deinit { + _GlobalLeakCount.count -= 1 + } + } + @usableFromInline + internal var handle: Box + + @differentiable(where T: Differentiable, T == T.TangentVector) + public init(_ value: T) { + self.handle = Box(value) + } + + @differentiable(where T: Differentiable, T == T.TangentVector) + public var value: T { + get { handle.value } + set { handle.value = newValue } + } +} + +% for Self in ['Tracked', 'NonresilientTracked']: + +extension ${Self}: ExpressibleByFloatLiteral +where T: ExpressibleByFloatLiteral { public init(floatLiteral value: T.FloatLiteralType) { self.handle = Box(T(floatLiteral: value)) } } -extension Tracked : CustomStringConvertible { - public var description: String { return "Tracked(\(value))" } +extension ${Self}: CustomStringConvertible { + public var description: String { return "${Self}(\(value))" } } -extension Tracked : ExpressibleByIntegerLiteral where T : ExpressibleByIntegerLiteral { +extension ${Self}: ExpressibleByIntegerLiteral +where T: ExpressibleByIntegerLiteral { public init(integerLiteral value: T.IntegerLiteralType) { self.handle = Box(T(integerLiteral: value)) } } -extension Tracked : Comparable where T : Comparable { - public static func < (lhs: Tracked, rhs: Tracked) -> Bool { +extension ${Self}: Comparable where T: Comparable { + public static func < (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value < rhs.value } - public static func <= (lhs: Tracked, rhs: Tracked) -> Bool { + public static func <= (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value <= rhs.value } - public static func > (lhs: Tracked, rhs: Tracked) -> Bool { + public static func > (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value > rhs.value } - public static func >= (lhs: Tracked, rhs: Tracked) -> Bool { + public static func >= (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value >= rhs.value } } -extension Tracked : AdditiveArithmetic where T : AdditiveArithmetic { - public static var zero: Tracked { return Tracked(T.zero) } - public static func + (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value + rhs.value) +extension ${Self}: AdditiveArithmetic where T: AdditiveArithmetic { + public static var zero: ${Self} { return ${Self}(T.zero) } + public static func + (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value + rhs.value) } - public static func - (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value - rhs.value) + public static func - (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value - rhs.value) } } -extension Tracked : Equatable where T : Equatable { - public static func == (lhs: Tracked, rhs: Tracked) -> Bool { +extension ${Self}: Equatable where T: Equatable { + public static func == (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value == rhs.value } } -extension Tracked : SignedNumeric & Numeric where T : SignedNumeric, T == T.Magnitude { - public typealias Magnitude = Tracked +extension ${Self}: SignedNumeric & Numeric +where T: SignedNumeric, T == T.Magnitude { + public typealias Magnitude = ${Self} - public init?(exactly source: U) where U : BinaryInteger { + public init?(exactly source: U) where U: BinaryInteger { if let t = T(exactly: source) { self.init(t) } @@ -136,169 +176,191 @@ extension Tracked : SignedNumeric & Numeric where T : SignedNumeric, T == T.Magn } public var magnitude: Magnitude { return Magnitude(value.magnitude) } - public static func * (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value * rhs.value) + public static func * (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value * rhs.value) } - public static func *= (lhs: inout Tracked, rhs: Tracked) { + public static func *= (lhs: inout ${Self}, rhs: ${Self}) { lhs = lhs * rhs } } -extension Tracked where T : FloatingPoint { - public static func / (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value / rhs.value) +extension ${Self} where T: FloatingPoint { + public static func / (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value / rhs.value) } - public static func /= (lhs: inout Tracked, rhs: Tracked) { + public static func /= (lhs: inout ${Self}, rhs: ${Self}) { lhs = lhs / rhs } } -extension Tracked : Strideable where T : Strideable, T.Stride == T.Stride.Magnitude { - public typealias Stride = Tracked +extension ${Self}: Strideable +where T: Strideable, T.Stride == T.Stride.Magnitude { + public typealias Stride = ${Self} - public func distance(to other: Tracked) -> Stride { + public func distance(to other: ${Self}) -> Stride { return Stride(value.distance(to: other.value)) } - public func advanced(by n: Stride) -> Tracked { - return Tracked(value.advanced(by: n.value)) + public func advanced(by n: Stride) -> ${Self} { + return ${Self}(value.advanced(by: n.value)) } } // For now, `T` must be restricted to trivial types (like `Float` or `Tensor`). -extension Tracked : Differentiable where T : Differentiable, T == T.TangentVector { - public typealias TangentVector = Tracked +extension ${Self}: Differentiable +where T: Differentiable, T == T.TangentVector { + public typealias TangentVector = ${Self} } -extension Tracked where T : Differentiable, T == T.TangentVector { +extension ${Self} where T: Differentiable, T == T.TangentVector { @usableFromInline @derivative(of: init) internal static func _vjpInit(_ value: T) - -> (value: Self, pullback: (Self.TangentVector) -> (T.TangentVector)) { - return (Tracked(value), { v in v.value }) + -> (value: Self, pullback: (Self.TangentVector) -> (T.TangentVector)) + { + return (${Self}(value), { v in v.value }) } @usableFromInline @derivative(of: init) internal static func _jvpInit(_ value: T) - -> (value: Self, differential: (T.TangentVector) -> (Self.TangentVector)) { - return (Tracked(value), { v in Tracked(v) }) + -> (value: Self, differential: (T.TangentVector) -> (Self.TangentVector)) + { + return (${Self}(value), { v in ${Self}(v) }) } @usableFromInline @derivative(of: value) - internal func _vjpValue() -> (value: T, pullback: (T.TangentVector) -> Self.TangentVector) { - return (value, { v in Tracked(v) }) + internal func _vjpValue() -> ( + value: T, pullback: (T.TangentVector) -> Self.TangentVector + ) { + return (value, { v in ${Self}(v) }) } @usableFromInline @derivative(of: value) - internal func _jvpValue() -> (value: T, differential: (Self.TangentVector) -> T.TangentVector) { + internal func _jvpValue() -> ( + value: T, differential: (Self.TangentVector) -> T.TangentVector + ) { return (value, { v in v.value }) } } -extension Tracked where T : Differentiable, T == T.TangentVector { +extension ${Self} where T: Differentiable, T == T.TangentVector { @usableFromInline @derivative(of: +) internal static func _vjpAdd(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs + rhs, { v in (v, v) }) } @usableFromInline @derivative(of: +) internal static func _jvpAdd(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> Self) { + -> (value: Self, differential: (Self, Self) -> Self) + { return (lhs + rhs, { $0 + $1 }) } @usableFromInline @derivative(of: -) internal static func _vjpSubtract(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs - rhs, { v in (v, .zero - v) }) } @usableFromInline @derivative(of: -) internal static func _jvpSubtract(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> Self) { + -> (value: Self, differential: (Self, Self) -> Self) + { return (lhs - rhs, { $0 - $1 }) } } -extension Tracked where T : Differentiable & SignedNumeric, T == T.Magnitude, - T == T.TangentVector { +extension ${Self} +where + T: Differentiable & SignedNumeric, T == T.Magnitude, + T == T.TangentVector +{ @usableFromInline @derivative(of: *) internal static func _vjpMultiply(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs * rhs, { v in (v * rhs, v * lhs) }) } @usableFromInline @derivative(of: *) internal static func _jvpMultiply(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> (Self)) { + -> (value: Self, differential: (Self, Self) -> (Self)) + { return (lhs * rhs, { (dx, dy) in dx * rhs + dy * lhs }) } } -extension Tracked where T : Differentiable & FloatingPoint, T == T.TangentVector { +extension ${Self} +where T: Differentiable & FloatingPoint, T == T.TangentVector { @usableFromInline @derivative(of: /) internal static func _vjpDivide(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs / rhs, { v in (v / rhs, -lhs / (rhs * rhs) * v) }) } @usableFromInline @derivative(of: /) internal static func _jvpDivide(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> (Self)) { + -> (value: Self, differential: (Self, Self) -> (Self)) + { return (lhs / rhs, { (dx, dy) in dx / rhs - lhs / (rhs * rhs) * dy }) } } -// Differential operators for `Tracked`. +// Differential operators for `${Self}`. public func gradient( - at x: T, in f: @differentiable (T) -> Tracked + at x: T, in f: @differentiable (T) -> ${Self} ) -> T.TangentVector where R.TangentVector == R { return pullback(at: x, in: f)(1) } public func gradient( - at x: T, _ y: U, in f: @differentiable (T, U) -> Tracked + at x: T, _ y: U, in f: @differentiable (T, U) -> ${Self} ) -> (T.TangentVector, U.TangentVector) where R.TangentVector == R { return pullback(at: x, y, in: f)(1) } public func derivative( - at x: Tracked, in f: @differentiable (Tracked) -> R + at x: ${Self}, in f: @differentiable (${Self}) -> R ) -> R.TangentVector where T.TangentVector == T { return differential(at: x, in: f)(1) } public func derivative( - at x: Tracked, _ y: Tracked, - in f: @differentiable (Tracked, Tracked) -> R + at x: ${Self}, _ y: ${Self}, + in f: @differentiable (${Self}, ${Self}) -> R ) -> R.TangentVector where T.TangentVector == T, U.TangentVector == U { return differential(at: x, y, in: f)(1, 1) } public func valueWithGradient( - at x: T, in f: @differentiable (T) -> Tracked -) -> (value: Tracked, gradient: T.TangentVector) { + at x: T, in f: @differentiable (T) -> ${Self} +) -> (value: ${Self}, gradient: T.TangentVector) { let (y, pullback) = valueWithPullback(at: x, in: f) return (y, pullback(1)) } public func valueWithDerivative( - at x: Tracked, in f: @differentiable (Tracked) -> R + at x: ${Self}, in f: @differentiable (${Self}) -> R ) -> (value: R, derivative: R.TangentVector) { let (y, differential) = valueWithDifferential(at: x, in: f) return (y, differential(1)) } + +% end diff --git a/test/AutoDiff/validation-test/optional.swift b/test/AutoDiff/validation-test/optional.swift index c2fc0fac4a695..4aeb60ba42762 100644 --- a/test/AutoDiff/validation-test/optional.swift +++ b/test/AutoDiff/validation-test/optional.swift @@ -1,8 +1,8 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test -import StdlibUnittest import DifferentiationUnittest +import StdlibUnittest var OptionalTests = TestSuite("OptionalDifferentiation") @@ -23,7 +23,7 @@ OptionalTests.test("Let") { @differentiable func optional_let(_ maybeX: Float?) -> Float { if let x = maybeX { - return x * x + return x * x } return 10 } @@ -33,13 +33,27 @@ OptionalTests.test("Let") { @differentiable func optional_let_tracked(_ maybeX: Tracked?) -> Tracked { if let x = maybeX { - return x * x + return x * x } return 10 } expectEqual(gradient(at: 10, in: optional_let_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_let_tracked), .init(0.0)) + @differentiable + func optional_let_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_let_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_let_nonresilient_tracked), .init(0.0)) + @differentiable func optional_let_nested(_ nestedMaybeX: Float??) -> Float { if let maybeX = nestedMaybeX { @@ -54,7 +68,26 @@ OptionalTests.test("Let") { expectEqual(gradient(at: nil, in: optional_let_nested), .init(.init(0.0))) @differentiable - func optional_let_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_let_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked< + Float + > { + if let maybeX = nestedMaybeX { + if let x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_let_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_let_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_let_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { if let maybeX = nestedMaybeX { if let x = maybeX { return x * x @@ -63,24 +96,38 @@ OptionalTests.test("Let") { } return 10 } - expectEqual(gradient(at: 10, in: optional_let_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_let_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_let_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_let_nested_nonresilient_tracked), + .init(.init(0.0))) @differentiable - func optional_let_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_let_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { if let x = maybeX { - return x + return x } return defaultValue } expectEqual(gradient(at: 10, 20, in: optional_let_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_let_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: nil, 20, in: optional_let_generic), (.init(0.0), 1.0)) - expectEqual(gradient(at: Tracked.init(10), Tracked.init(20), in: optional_let_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, Tracked.init(20), in: optional_let_generic), (.init(0.0), 1.0)) + expectEqual( + gradient( + at: Tracked.init(10), Tracked.init(20), + in: optional_let_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, Tracked.init(20), in: optional_let_generic), + (.init(0.0), 1.0)) @differentiable - func optional_let_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_let_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { if let maybeX = nestedMaybeX { if let x = maybeX { return x @@ -90,8 +137,12 @@ OptionalTests.test("Let") { return defaultValue } - expectEqual(gradient(at: 10.0, 20.0, in: optional_let_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_let_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10.0, 20.0, in: optional_let_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_let_nested_generic), + (.init(.init(0.0)), 1.0)) } OptionalTests.test("Switch") { @@ -115,14 +166,28 @@ OptionalTests.test("Switch") { expectEqual(gradient(at: 10, in: optional_switch_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_switch_tracked), .init(0.0)) + @differentiable + func optional_switch_nonresilient_tracked( + _ maybeX: NonresilientTracked? + ) -> NonresilientTracked { + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + expectEqual( + gradient(at: 10, in: optional_switch_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_switch_nonresilient_tracked), .init(0.0)) + @differentiable func optional_switch_nested(_ nestedMaybeX: Float??) -> Float { switch nestedMaybeX { case nil: return 10 case let .some(maybeX): switch maybeX { - case nil: return 10 - case let .some(x): return x * x + case nil: return 10 + case let .some(x): return x * x } } } @@ -130,42 +195,76 @@ OptionalTests.test("Switch") { expectEqual(gradient(at: nil, in: optional_switch_nested), .init(.init(0.0))) @differentiable - func optional_switch_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_switch_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { switch nestedMaybeX { case nil: return 10 case let .some(maybeX): switch maybeX { - case nil: return 10 - case let .some(x): return x * x + case nil: return 10 + case let .some(x): return x * x } } } - expectEqual(gradient(at: 10, in: optional_switch_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_switch_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_switch_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_switch_nested_tracked), .init(.init(0.0))) @differentiable - func optional_switch_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_switch_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { + switch nestedMaybeX { + case nil: return 10 + case let .some(maybeX): + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + } + expectEqual( + gradient(at: 10, in: optional_switch_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_switch_nested_nonresilient_tracked), + .init(.init(0.0))) + + @differentiable + func optional_switch_generic( + _ maybeX: T?, _ defaultValue: T + ) -> T { switch maybeX { case nil: return defaultValue case let .some(x): return x } } - expectEqual(gradient(at: 10, 20, in: optional_switch_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_switch_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_switch_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_switch_generic), (.init(0.0), 1.0)) @differentiable - func optional_switch_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_switch_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { switch nestedMaybeX { case nil: return defaultValue case let .some(maybeX): switch maybeX { - case nil: return defaultValue - case let .some(x): return x + case nil: return defaultValue + case let .some(x): return x } } } - expectEqual(gradient(at: 10, 20, in: optional_switch_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_switch_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_switch_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_switch_nested_generic), + (.init(.init(0.0)), 1.0)) } OptionalTests.test("Var1") { @@ -173,7 +272,7 @@ OptionalTests.test("Var1") { func optional_var1(_ maybeX: Float?) -> Float { var maybeX = maybeX if let x = maybeX { - return x * x + return x * x } return 10 } @@ -184,13 +283,28 @@ OptionalTests.test("Var1") { func optional_var1_tracked(_ maybeX: Tracked?) -> Tracked { var maybeX = maybeX if let x = maybeX { - return x * x + return x * x } return 10 } expectEqual(gradient(at: 10, in: optional_var1_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_var1_tracked), .init(0.0)) + @differentiable + func optional_var1_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + var maybeX = maybeX + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var1_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_var1_nonresilient_tracked), .init(0.0)) + @differentiable func optional_var1_nested(_ nestedMaybeX: Float??) -> Float { var nestedMaybeX = nestedMaybeX @@ -206,7 +320,9 @@ OptionalTests.test("Var1") { expectEqual(gradient(at: nil, in: optional_var1_nested), .init(.init(0.0))) @differentiable - func optional_var1_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_var1_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { var nestedMaybeX = nestedMaybeX if let maybeX = nestedMaybeX { if var x = maybeX { @@ -216,22 +332,50 @@ OptionalTests.test("Var1") { } return 10 } - expectEqual(gradient(at: 10, in: optional_var1_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_var1_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_var1_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var1_nested_tracked), .init(.init(0.0))) @differentiable - func optional_var1_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_var1_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { + var nestedMaybeX = nestedMaybeX + if let maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var1_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var1_nested_nonresilient_tracked), + .init(.init(0.0))) + + @differentiable + func optional_var1_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { var maybeX = maybeX if let x = maybeX { - return x + return x } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var1_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var1_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var1_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var1_generic), (.init(0.0), 1.0)) @differentiable - func optional_var1_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_var1_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { var nestedMaybeX = nestedMaybeX if let maybeX = nestedMaybeX { if var x = maybeX { @@ -241,8 +385,12 @@ OptionalTests.test("Var1") { } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var1_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var1_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var1_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var1_nested_generic), + (.init(.init(0.0)), 1.0)) } OptionalTests.test("Var2") { @@ -266,6 +414,20 @@ OptionalTests.test("Var2") { expectEqual(gradient(at: 10, in: optional_var2_tracked), .init(20.0)) expectEqual(gradient(at: nil, in: optional_var2_tracked), .init(0.0)) + @differentiable + func optional_var2_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + if var x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var2_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_var2_nonresilient_tracked), .init(0.0)) + @differentiable func optional_var2_nested(_ nestedMaybeX: Float??) -> Float { if var maybeX = nestedMaybeX { @@ -280,7 +442,26 @@ OptionalTests.test("Var2") { expectEqual(gradient(at: nil, in: optional_var2_nested), .init(.init(0.0))) @differentiable - func optional_var2_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked { + func optional_var2_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { + if var maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var2_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var2_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_var2_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { if var maybeX = nestedMaybeX { if var x = maybeX { return x * x @@ -289,21 +470,31 @@ OptionalTests.test("Var2") { } return 10 } - expectEqual(gradient(at: 10, in: optional_var2_nested_tracked), .init(.init(20.0))) - expectEqual(gradient(at: nil, in: optional_var2_nested_tracked), .init(.init(0.0))) + expectEqual( + gradient(at: 10, in: optional_var2_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var2_nested_nonresilient_tracked), + .init(.init(0.0))) @differentiable - func optional_var2_generic(_ maybeX: T?, _ defaultValue: T) -> T { + func optional_var2_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { if var x = maybeX { return x } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var2_generic), (.init(1.0), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var2_generic), (.init(0.0), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var2_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var2_generic), (.init(0.0), 1.0)) @differentiable - func optional_var2_nested_generic(_ nestedMaybeX: T??, _ defaultValue: T) -> T { + func optional_var2_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { if var maybeX = nestedMaybeX { if var x = maybeX { return x @@ -312,8 +503,12 @@ OptionalTests.test("Var2") { } return defaultValue } - expectEqual(gradient(at: 10, 20, in: optional_var2_nested_generic), (.init(.init(1.0)), 0.0)) - expectEqual(gradient(at: nil, 20, in: optional_var2_nested_generic), (.init(.init(0.0)), 1.0)) + expectEqual( + gradient(at: 10, 20, in: optional_var2_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var2_nested_generic), + (.init(.init(0.0)), 1.0)) } runAllTests() From 9f560ad13eecdc4a44690279af45663816bc5623 Mon Sep 17 00:00:00 2001 From: ematejska Date: Tue, 11 Aug 2020 10:53:39 -0700 Subject: [PATCH 121/123] Updating the tags for the merge. --- .../update-checkout-config.json | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 905467e8dc06e..fab01fd2aa14a 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -345,26 +345,26 @@ "tensorflow": { "aliases": ["tensorflow"], "repos": { - "llvm-project": "fc41e0afba70b658d512459ec631c6b4b9a526e8", + "llvm-project": "18d86c328dd7322dfede628b3cf5cd312a6efa7c", "swift": "tensorflow", - "cmark": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "llbuild": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", + "cmark": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "llbuild": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", "swift-tools-support-core": "0.1.8", - "swiftpm": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-argument-parser": "0.2.1", + "swiftpm": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-argument-parser": "0.2.2", "swift-driver": "bf0026c636347b4c31aab21deb01943529b7e556", - "swift-syntax": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-stress-tester": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-corelibs-xctest": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-corelibs-foundation": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-corelibs-libdispatch": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-integration-tests": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-xcode-playground-support": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", + "swift-syntax": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-stress-tester": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-corelibs-xctest": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-corelibs-foundation": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-corelibs-libdispatch": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-integration-tests": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-xcode-playground-support": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", "ninja": "release", "icu": "release-65-1", "yams": "3.0.1-patched", - "indexstore-db": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "sourcekit-lsp": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", + "indexstore-db": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "sourcekit-lsp": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", "PythonKit": "master", "swift-format": "master", "tensorflow": "v2.2.0-rc0", From b7228b75b0091764fa33111ae969caf77c0a2610 Mon Sep 17 00:00:00 2001 From: ematejska Date: Wed, 12 Aug 2020 14:01:21 -0700 Subject: [PATCH 122/123] Update tensorflow branch --- utils/update_checkout/update-checkout-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index fab01fd2aa14a..732b7de554e03 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -367,7 +367,7 @@ "sourcekit-lsp": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", "PythonKit": "master", "swift-format": "master", - "tensorflow": "v2.2.0-rc0", + "tensorflow": "v2.3", "tensorflow-swift-apis": "master" } } From f06709fc6e1c156f4d39347c92c32ad9d9d71967 Mon Sep 17 00:00:00 2001 From: ematejska Date: Wed, 12 Aug 2020 14:10:04 -0700 Subject: [PATCH 123/123] Update tensorflow from 2.3 to 2.3.0 --- utils/update_checkout/update-checkout-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 732b7de554e03..aecfa29a90c75 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -367,7 +367,7 @@ "sourcekit-lsp": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", "PythonKit": "master", "swift-format": "master", - "tensorflow": "v2.3", + "tensorflow": "v2.3.0", "tensorflow-swift-apis": "master" } }