Skip to content

Commit 77512f8

Browse files
committed
[Noncopyable] Mangle enum elements as "always in the primary definition"
For entities that must be part of the primary definition of a type, mangle without inverses on the generic parameters of the enclosing type. This ensures that we can adopt noncopyable on the generic parameters without breaking the mangling of the fundamental entities that describe the layout of the type. Do this for enum elements first, so we don't break the mangling of `Optional`. There will be other cases to consider as well.
1 parent f54782e commit 77512f8

File tree

4 files changed

+58
-9
lines changed

4 files changed

+58
-9
lines changed

include/swift/AST/ASTMangler.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,12 +461,24 @@ class ASTMangler : public Mangler {
461461
bool innermostTypeDecl;
462462
bool extension;
463463
std::optional<unsigned> mangledDepth; // for inverses
464+
std::optional<unsigned> suppressedInnermostDepth;
464465
public:
465466
bool reachedInnermostTypeDecl() {
466467
bool answer = innermostTypeDecl;
467468
innermostTypeDecl = false;
468469
return answer;
469470
}
471+
472+
/// Whether inverses of the innermost declaration's generic parameters
473+
/// should be suppressed.
474+
///
475+
/// This makes sense only for entities that can only ever be defined
476+
/// within the primary type, such as enum cases and the stored properties
477+
/// of struct and class types.
478+
std::optional<unsigned> getSuppressedInnermostInversesDepth() const {
479+
return suppressedInnermostDepth;
480+
}
481+
470482
bool reachedExtension() const { return extension; }
471483
void setReachedExtension() { assert(!extension); extension = true; }
472484
GenericSignature getSignature() const { return sig; }

lib/AST/ASTMangler.cpp

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2610,12 +2610,13 @@ void ASTMangler::appendSymbolicReference(SymbolicReferent referent) {
26102610
static void reconcileInverses(
26112611
SmallVector<InverseRequirement, 2> &inverses,
26122612
GenericSignature sig,
2613-
std::optional<unsigned> inversesAlreadyMangledDepth) {
2613+
std::optional<unsigned> inversesAlreadyMangledDepth,
2614+
std::optional<unsigned> suppressedInnermostDepth) {
26142615
CanGenericSignature baseSig;
26152616
if (sig)
26162617
baseSig = sig.getCanonicalSignature();
26172618

2618-
if (baseSig || inversesAlreadyMangledDepth)
2619+
if (baseSig || inversesAlreadyMangledDepth || suppressedInnermostDepth)
26192620
llvm::erase_if(inverses, [&](InverseRequirement const& inv) -> bool {
26202621
// Drop inverses that aren't applicable in the nested / child signature,
26212622
// because of an added requirement.
@@ -2630,6 +2631,10 @@ static void reconcileInverses(
26302631
if (gp->getDepth() <= limit)
26312632
return true;
26322633

2634+
if (suppressedInnermostDepth &&
2635+
gp->getDepth() == *suppressedInnermostDepth)
2636+
return true;
2637+
26332638
return false;
26342639
});
26352640

@@ -3353,7 +3358,8 @@ void ASTMangler::gatherGenericSignatureParts(GenericSignature sig,
33533358
// Process inverses relative to the base entity's signature.
33543359
if (AllowInverses) {
33553360
// Simplify and canonicalize inverses.
3356-
reconcileInverses(inverseReqs, base.getSignature(), base.getDepth());
3361+
reconcileInverses(inverseReqs, base.getSignature(), base.getDepth(),
3362+
base.getSuppressedInnermostInversesDepth());
33573363
} else {
33583364
inverseReqs.clear();
33593365
}
@@ -4654,6 +4660,31 @@ void ASTMangler::appendConstrainedExistential(Type base, GenericSignature sig,
46544660
return appendOperator("XP");
46554661
}
46564662

4663+
/// Determine whether this declaration can only occur within the primary
4664+
/// type definition.
4665+
static bool canOnlyOccurInPrimaryTypeDefinition(const Decl *decl) {
4666+
// Enum elements always occur within the primary definition.
4667+
if (isa<EnumElementDecl>(decl))
4668+
return true;
4669+
4670+
return false;
4671+
}
4672+
4673+
/// When the immediate enclosing context of this declaration is
4674+
/// a generic type (with its own generic parameters), return the depth of
4675+
/// the innermost generic parameters.
4676+
static std::optional<unsigned> getEnclosingTypeGenericDepth(const Decl *decl) {
4677+
auto typeDecl = dyn_cast<GenericTypeDecl>(decl->getDeclContext());
4678+
if (!typeDecl)
4679+
return std::nullopt;
4680+
4681+
auto genericParams = typeDecl->getGenericParams();
4682+
if (!genericParams)
4683+
return std::nullopt;
4684+
4685+
return genericParams->getParams().back()->getDepth();
4686+
}
4687+
46574688
ASTMangler::BaseEntitySignature::BaseEntitySignature(const Decl *decl)
46584689
: sig(nullptr), innermostTypeDecl(true), extension(false),
46594690
mangledDepth(std::nullopt) {
@@ -4668,12 +4699,22 @@ ASTMangler::BaseEntitySignature::BaseEntitySignature(const Decl *decl)
46684699
case DeclKind::Enum:
46694700
case DeclKind::Struct:
46704701
case DeclKind::Class:
4702+
case DeclKind::EnumElement:
46714703
sig = decl->getInnermostDeclContext()->getGenericSignatureOfContext();
46724704

46734705
// Protocol members never mangle inverse constraints on `Self`.
46744706
if (isa<ProtocolDecl>(decl->getDeclContext()))
46754707
setDepth(0);
46764708

4709+
// Declarations that can only occur in the primary type definition should
4710+
// not mangle inverses for the generic parameters of that type definition.
4711+
// This allows types to introduce conditional conformances to invertible
4712+
// protocols without breaking ABI.
4713+
if (canOnlyOccurInPrimaryTypeDefinition(decl)) {
4714+
if (auto depth = getEnclosingTypeGenericDepth(decl))
4715+
suppressedInnermostDepth = depth;
4716+
}
4717+
46774718
break;
46784719

46794720
case DeclKind::TypeAlias: // FIXME: is this right? typealiases have a generic signature!
@@ -4686,7 +4727,6 @@ ASTMangler::BaseEntitySignature::BaseEntitySignature(const Decl *decl)
46864727
case DeclKind::Module:
46874728
case DeclKind::Param:
46884729
case DeclKind::Macro:
4689-
case DeclKind::EnumElement:
46904730
case DeclKind::Extension:
46914731
case DeclKind::TopLevelCode:
46924732
case DeclKind::Import:

lib/IRGen/IRGenMangler.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,6 @@ class IRGenMangler : public Mangle::ASTMangler {
401401
}
402402

403403
std::string mangleEnumCase(const ValueDecl *Decl) {
404-
// No mangling of inverse conformances.
405-
llvm::SaveAndRestore X(AllowInverses, false);
406-
407404
beginMangling();
408405
appendEntity(Decl);
409406
appendOperator("WC");

test/IRGen/mangling_inverse_generics_evolution.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ public protocol P: ~Copyable { }
1212

1313
public struct CallMe<U: ~Copyable> {
1414
public enum Maybe<T: ~Copyable>: ~Copyable {
15-
// CHECK-LABEL: @"$s4test6CallMeV5MaybeO4someyAEyx_qd__Gqd__cAGmr__lFWC"
16-
// CHECK: @"$s4test6CallMeV5MaybeO4noneyAEyx_qd__GAGmr__lFWC"
15+
// CHECK-LABEL: @"$s4test6CallMeV5MaybeOAARiczrlE4someyAEyx_qd__Gqd__cAGmr__lFWC"
16+
// CHECK: @"$s4test6CallMeV5MaybeOAARiczrlE4noneyAEyx_qd__GAGmr__lFWC"
1717
case none
1818
case some(T)
1919
}

0 commit comments

Comments
 (0)