Skip to content

Commit 8a77cba

Browse files
authored
Merge pull request #83501 from rjmccall/pack-tuple-projection-silgen
Fix projecting a tuple element out of a tuple with packs.
2 parents eacbcae + 6c3fd0e commit 8a77cba

18 files changed

+332
-43
lines changed

include/swift/Basic/Compiler.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,10 @@ inline const char *operator""_swift_u8(const char8_t *p, size_t) {
190190
#endif // defined(__cpp_char8_t)
191191
#endif // defined(__cplusplus)
192192

193+
#if __has_attribute(trivial_abi)
194+
#define SWIFT_TRIVIAL_ABI __attribute__((trivial_abi))
195+
#else
196+
#define SWIFT_TRIVIAL_ABI
197+
#endif
198+
193199
#endif // SWIFT_BASIC_COMPILER_H
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
//===--- PossiblyUniquePtr.h - A dynamic smart pointer ----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
///
15+
/// This file defines PossiblyUniquePtr, a smart pointer template that
16+
/// typically owns its pointee but can dynamically just contain an unowned
17+
/// pointer.
18+
///
19+
//===----------------------------------------------------------------------===//
20+
21+
#ifndef SWIFT_BASIC_POSSIBLY_UNIQUE_PTR_H
22+
#define SWIFT_BASIC_POSSIBLY_UNIQUE_PTR_H
23+
24+
#include "llvm/ADT/PointerIntPair.h"
25+
#include "swift/Basic/Compiler.h"
26+
27+
namespace swift {
28+
29+
enum PointerIsOwned_t: bool {
30+
PointerIsNotOwned = false,
31+
PointerIsOwned = true
32+
};
33+
34+
/// Essentially std::unique_ptr except it dynamically tracks whether the
35+
/// pointer is actually owned.
36+
///
37+
/// The operations which possibly transfer ownership into a PossiblyUniquePtr
38+
/// (the constructor and `reset`) privilege the owning case. This allows
39+
/// PossiblyUniquePtr<T> to serve as a drop-in replacement for
40+
/// std::unique_ptr<T>.
41+
template <class T, class PtrTraits = llvm::PointerLikeTypeTraits<T*>>
42+
class SWIFT_TRIVIAL_ABI PossiblyUniquePtr {
43+
llvm::PointerIntPair<T*, 1, bool, PtrTraits> Value;
44+
45+
// Befriend all other specializations of this class, for the use of the
46+
// converting constructor and assignment operator.
47+
template <class, class>
48+
friend class PossiblyUniquePtr;
49+
50+
public:
51+
PossiblyUniquePtr() {}
52+
53+
// Allow implicit conversion from a null pointer.
54+
PossiblyUniquePtr(std::nullptr_t) {}
55+
56+
// Require conversion from any other pointer to be explicit.
57+
explicit PossiblyUniquePtr(T *pointer,
58+
PointerIsOwned_t owned = PointerIsOwned)
59+
: Value(pointer, owned) {
60+
assert((pointer != nullptr || !owned) && "claiming ownership of null pointer");
61+
}
62+
63+
PossiblyUniquePtr(PossiblyUniquePtr &&other)
64+
: Value(other.Value) {
65+
other.dropValue();
66+
}
67+
68+
PossiblyUniquePtr &operator=(PossiblyUniquePtr &&other) {
69+
destroyValue();
70+
Value = other.Value;
71+
other.dropValue();
72+
return *this;
73+
}
74+
75+
~PossiblyUniquePtr() {
76+
destroyValue();
77+
}
78+
79+
// Converting constructor.
80+
template <class U, class UTraits>
81+
PossiblyUniquePtr(PossiblyUniquePtr<U,UTraits> &&other)
82+
: Value(other.Value.getPointer(), other.Value.getInt()) {
83+
other.dropValue();
84+
}
85+
86+
// Converting assignment operator.
87+
template <class U, class UTraits>
88+
PossiblyUniquePtr &operator=(PossiblyUniquePtr<U,UTraits> &&other) {
89+
destroyValue();
90+
Value.setPointerAndInt(other.Value.getPointer(),
91+
other.Value.getInt());
92+
other.dropValue();
93+
return *this;
94+
}
95+
96+
template <class ObjectType, class... Args>
97+
static PossiblyUniquePtr make(Args &&...args) {
98+
return PossiblyUniquePtr(new ObjectType(std::forward<Args>(args)...));
99+
}
100+
101+
/// As a unique pointer, PossiblyUniquePtr is non-copyable.
102+
PossiblyUniquePtr(const PossiblyUniquePtr &other) = delete;
103+
PossiblyUniquePtr &operator=(const PossiblyUniquePtr &other) = delete;
104+
105+
explicit operator bool() const {
106+
return Value.getPointer() != nullptr;
107+
}
108+
109+
T &operator*() const {
110+
return *get_nonnull();
111+
}
112+
T *operator->() const {
113+
return get_nonnull();
114+
}
115+
116+
/// Reset the value of this object to the given pointer.
117+
///
118+
/// Destroys the current value, if any.
119+
void reset(T *pointer = nullptr, PointerIsOwned_t owned = PointerIsOwned) & {
120+
destroyValue();
121+
Value.setPointerAndInt(pointer, owned);
122+
}
123+
124+
/// Borrow the current pointer value, leaving ownership (if any) with this object.
125+
T *get() const {
126+
return Value.getPointer();
127+
}
128+
129+
/// Borrow the current pointer value, leaving ownership (if any) with this object.
130+
/// Asserts that the pointer is non-null.
131+
T *get_nonnull() const {
132+
auto value = get();
133+
assert(value);
134+
return value;
135+
}
136+
137+
/// Determines whether this object owns its pointer value.
138+
PointerIsOwned_t isOwned() const {
139+
return PointerIsOwned_t(Value.getInt());
140+
}
141+
142+
/// Release ownership of the pointer, making the caller responsible for it.
143+
/// This can only be called on an owned pointer.
144+
T *releaseOwned() {
145+
assert(isOwned());
146+
auto value = get();
147+
dropValue();
148+
return value;
149+
}
150+
151+
private:
152+
/// Destroy the value, if we own it.
153+
void destroyValue() {
154+
if (Value.getInt()) {
155+
delete Value.getPointer();
156+
}
157+
}
158+
159+
/// Clear the stored value without asserting ownership.
160+
void dropValue() & {
161+
Value.setPointerAndInt(nullptr, 0);
162+
}
163+
};
164+
165+
template <class ObjectType, class... As>
166+
PossiblyUniquePtr<ObjectType> make_possibly_unique(As &&...args) {
167+
return PossiblyUniquePtr<ObjectType>::
168+
template make<ObjectType>(std::forward<As>(args)...);
169+
}
170+
171+
} // end namespace swift
172+
173+
#endif

lib/SILGen/Condition.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ void ConditionalValue::exitBranch(RValue &&condResult) {
100100
// already.
101101
assert(currentInitialization && "no current initialization?!");
102102
std::move(condResult).forwardInto(SGF, loc,
103-
currentInitialization.release());
103+
currentInitialization.get());
104+
currentInitialization.reset();
104105
scope.reset();
105106
SGF.B.createBranch(loc, contBB);
106107
} else {

lib/SILGen/Condition.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class ConditionalValue {
109109
std::optional<Scope> scope;
110110

111111
/// A place to hold conditional Initializations of our result.
112-
std::unique_ptr<Initialization> currentInitialization;
112+
InitializationPtr currentInitialization;
113113

114114
public:
115115
/// Begins a conditional computation of the type represented by the given

lib/SILGen/Initialization.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define SWIFT_LOWERING_INITIALIZATION_H
2020

2121
#include "ManagedValue.h"
22+
#include "swift/Basic/PossiblyUniquePtr.h"
2223
#include "swift/SIL/AbstractionPattern.h"
2324
#include "llvm/ADT/TinyPtrVector.h"
2425
#include <memory>
@@ -28,9 +29,9 @@ namespace Lowering {
2829

2930
class SILGenFunction;
3031
class Initialization;
31-
using InitializationPtr = std::unique_ptr<Initialization>;
32+
using InitializationPtr = PossiblyUniquePtr<Initialization>;
3233
class TemporaryInitialization;
33-
using TemporaryInitializationPtr = std::unique_ptr<TemporaryInitialization>;
34+
using TemporaryInitializationPtr = PossiblyUniquePtr<TemporaryInitialization>;
3435
class ConvertingInitialization;
3536

3637
/// An abstract class for consuming a value. This is used for initializing

lib/SILGen/ResultPlan.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,14 @@ class IndirectOpenedSelfResultPlan final : public ResultPlan {
225225
/// reabstracting it. The value can actually be a tuple if the
226226
/// abstraction is opaque.
227227
class ScalarResultPlan final : public ResultPlan {
228-
std::unique_ptr<TemporaryInitialization> temporary;
228+
TemporaryInitializationPtr temporary;
229229
AbstractionPattern origType;
230230
CanType substType;
231231
Initialization *init;
232232
SILFunctionTypeRepresentation rep;
233233

234234
public:
235-
ScalarResultPlan(std::unique_ptr<TemporaryInitialization> &&temporary,
235+
ScalarResultPlan(TemporaryInitializationPtr &&temporary,
236236
AbstractionPattern origType, CanType substType,
237237
Initialization *init,
238238
SILFunctionTypeRepresentation rep)
@@ -339,13 +339,13 @@ class InitValueFromTemporaryResultPlan final : public ResultPlan {
339339
Initialization *init;
340340
CanType substType;
341341
ResultPlanPtr subPlan;
342-
std::unique_ptr<TemporaryInitialization> temporary;
342+
TemporaryInitializationPtr temporary;
343343

344344
public:
345345
InitValueFromTemporaryResultPlan(
346346
Initialization *init, CanType substType,
347347
ResultPlanPtr &&subPlan,
348-
std::unique_ptr<TemporaryInitialization> &&temporary)
348+
TemporaryInitializationPtr &&temporary)
349349
: init(init), substType(substType), subPlan(std::move(subPlan)),
350350
temporary(std::move(temporary)) {}
351351

@@ -1249,7 +1249,7 @@ ResultPlanPtr ResultPlanBuilder::buildForScalar(Initialization *init,
12491249
}
12501250

12511251
// Create a temporary if the result is indirect.
1252-
std::unique_ptr<TemporaryInitialization> temporary;
1252+
TemporaryInitializationPtr temporary;
12531253
if (SGF.silConv.isSILIndirect(result)) {
12541254
auto &resultTL = SGF.getTypeLowering(result.getReturnValueType(
12551255
SGF.SGM.M, calleeTy, SGF.getTypeExpansionContext()));

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2130,7 +2130,7 @@ static ManagedValue emitBuiltinEmplace(SILGenFunction &SGF,
21302130
bool didEmitInto;
21312131
Initialization *dest;
21322132
TemporaryInitialization *destTemporary = nullptr;
2133-
std::unique_ptr<Initialization> destOwner;
2133+
InitializationPtr destOwner;
21342134

21352135
// Use the context destination if available.
21362136
if (C.getEmitInto()

lib/SILGen/SILGenConstructor.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) {
853853
Loc.markAutoGenerated();
854854

855855
// Emit the indirect return slot.
856-
std::unique_ptr<Initialization> dest;
856+
InitializationPtr dest;
857857
if (enumTI.isAddressOnly() && silConv.useLoweredAddresses()) {
858858
auto &AC = getASTContext();
859859
auto VD = new (AC) ParamDecl(SourceLoc(), SourceLoc(),
@@ -865,8 +865,7 @@ void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) {
865865
VD->setInterfaceType(enumIfaceTy);
866866
auto resultSlot =
867867
F.begin()->createFunctionArgument(enumTI.getLoweredType(), VD);
868-
dest = std::unique_ptr<Initialization>(
869-
new KnownAddressInitialization(resultSlot));
868+
dest.reset(new KnownAddressInitialization(resultSlot));
870869
}
871870

872871
Scope scope(Cleanups, CleanupLoc);

lib/SILGen/SILGenDecl.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ splitSingleBufferIntoTupleElements(SILGenFunction &SGF, SILLocation loc,
312312
if (eltCleanup.isValid())
313313
splitCleanups.push_back(eltCleanup);
314314

315-
buf.emplace_back(eltInit.release());
315+
buf.emplace_back(std::move(eltInit));
316316
}
317317

318318
return buf;
@@ -1992,7 +1992,7 @@ InitializationPtr SILGenFunction::emitLocalVariableWithCleanup(
19921992
}
19931993

19941994
/// Create an Initialization for an uninitialized temporary.
1995-
std::unique_ptr<TemporaryInitialization>
1995+
TemporaryInitializationPtr
19961996
SILGenFunction::emitTemporary(SILLocation loc, const TypeLowering &tempTL) {
19971997
SILValue addr = emitTemporaryAllocation(loc, tempTL.getLoweredType());
19981998
if (addr->getType().isMoveOnly())
@@ -2002,7 +2002,7 @@ SILGenFunction::emitTemporary(SILLocation loc, const TypeLowering &tempTL) {
20022002
return useBufferAsTemporary(addr, tempTL);
20032003
}
20042004

2005-
std::unique_ptr<TemporaryInitialization>
2005+
TemporaryInitializationPtr
20062006
SILGenFunction::emitFormalAccessTemporary(SILLocation loc,
20072007
const TypeLowering &tempTL) {
20082008
SILValue addr = emitTemporaryAllocation(loc, tempTL.getLoweredType());
@@ -2012,16 +2012,16 @@ SILGenFunction::emitFormalAccessTemporary(SILLocation loc,
20122012
MarkUnresolvedNonCopyableValueInst::CheckKind::ConsumableAndAssignable);
20132013
CleanupHandle cleanup =
20142014
enterDormantFormalAccessTemporaryCleanup(addr, loc, tempTL);
2015-
return std::unique_ptr<TemporaryInitialization>(
2015+
return TemporaryInitializationPtr(
20162016
new TemporaryInitialization(addr, cleanup));
20172017
}
20182018

20192019
/// Create an Initialization for an uninitialized buffer.
2020-
std::unique_ptr<TemporaryInitialization>
2020+
TemporaryInitializationPtr
20212021
SILGenFunction::useBufferAsTemporary(SILValue addr,
20222022
const TypeLowering &tempTL) {
20232023
CleanupHandle cleanup = enterDormantTemporaryCleanup(addr, tempTL);
2024-
return std::unique_ptr<TemporaryInitialization>(
2024+
return TemporaryInitializationPtr(
20252025
new TemporaryInitialization(addr, cleanup));
20262026
}
20272027

lib/SILGen/SILGenDynamicCast.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ namespace {
5959

6060
SGFContext ctx;
6161

62-
std::unique_ptr<TemporaryInitialization> temporary;
62+
TemporaryInitializationPtr temporary;
6363
if (isOperandIndirect()) {
6464
temporary = SGF.emitTemporary(Loc, origSourceTL);
6565
ctx = SGFContext(temporary.get());
@@ -417,7 +417,7 @@ adjustForConditionalCheckedCastOperand(SILLocation loc, ManagedValue src,
417417
if (!hasAbstraction && (!requiresAddress || src.getType().isAddress()))
418418
return src;
419419

420-
std::unique_ptr<TemporaryInitialization> init;
420+
TemporaryInitializationPtr init;
421421
if (requiresAddress) {
422422
init = SGF.emitTemporary(loc, srcAbstractTL);
423423

0 commit comments

Comments
 (0)