Skip to content

Commit d6f6480

Browse files
author
git apple-llvm automerger
committed
Merge commit 'a7091951f0bb' from llvm.org/main into next
2 parents 3e4b6d9 + 6798209 commit d6f6480

File tree

9 files changed

+226
-78
lines changed

9 files changed

+226
-78
lines changed

clang/include/clang/APINotes/APINotesManager.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ class APINotesManager {
5050
/// source file from which an entity was declared.
5151
bool ImplicitAPINotes;
5252

53+
/// Whether to apply all APINotes as optionally-applied versioned
54+
/// entities. This means that when building a Clang module,
55+
/// we capture every note on a given decl wrapped in a SwiftVersionedAttr
56+
/// (with an empty version field for unversioned notes), and have the
57+
/// client apply the relevant version's notes.
58+
bool VersionIndependentSwift;
59+
5360
/// The Swift version to use when interpreting versioned API notes.
5461
llvm::VersionTuple SwiftVersion;
5562

@@ -167,6 +174,8 @@ class APINotesManager {
167174

168175
/// Find the API notes readers that correspond to the given source location.
169176
llvm::SmallVector<APINotesReader *, 2> findAPINotes(SourceLocation Loc);
177+
178+
bool captureVersionIndependentSwift() { return VersionIndependentSwift; }
170179
};
171180

172181
} // end namespace api_notes

clang/include/clang/Basic/Attr.td

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3224,6 +3224,26 @@ def Regparm : TypeAttr {
32243224
let ASTNode = 0;
32253225
}
32263226

3227+
def SwiftType : Attr {
3228+
// This attribute has no spellings as it is only ever created implicitly
3229+
// from API notes.
3230+
let Spellings = [];
3231+
let Args = [StringArgument<"TypeString">];
3232+
let SemaHandler = 0;
3233+
let Documentation = [InternalOnly];
3234+
}
3235+
3236+
def SwiftNullability : Attr {
3237+
// This attribute has no spellings as it is only ever created implicitly
3238+
// from API notes.
3239+
let Spellings = [];
3240+
let Args = [EnumArgument<"Kind", "Kind", /*is_string=*/false,
3241+
["non_null", "nullable", "unspecified", "nullable_result"],
3242+
["NonNull", "Nullable", "Unspecified", "NullableResult"]>];
3243+
let SemaHandler = 0;
3244+
let Documentation = [InternalOnly];
3245+
}
3246+
32273247
def SwiftAsyncName : InheritableAttr {
32283248
let Spellings = [GNU<"swift_async_name">];
32293249
let Args = [StringArgument<"Name">];

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, Compatible, "retain documentation
397397

398398
LANGOPT(APINotes, 1, 0, NotCompatible, "use external API notes")
399399
LANGOPT(APINotesModules, 1, 0, NotCompatible, "use module-based external API notes")
400+
LANGOPT(SwiftVersionIndependentAPINotes, 1, 0, NotCompatible, "use external API notes capturing all versions")
400401
LANGOPT(NeededByPCHOrCompilationUsesPCH, 1, 0, NotCompatible, "compilation involves pch")
401402

402403
LANGOPT(SanitizeAddressFieldPadding, 2, 0, NotCompatible, "controls how aggressive is ASan "

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,6 +1918,12 @@ defm apinotes_modules : BoolOption<"f", "apinotes-modules",
19181918
NegFlag<SetFalse, [], [ClangOption], "Disable">,
19191919
BothFlags<[], [ClangOption, CC1Option], " module-based external API notes support">>,
19201920
Group<f_clang_Group>;
1921+
defm swift_version_independent_apinotes : BoolOption<"f", "swift-version-independent-apinotes",
1922+
LangOpts<"SwiftVersionIndependentAPINotes">, DefaultFalse,
1923+
PosFlag<SetTrue, [], [ClangOption], "Enable">,
1924+
NegFlag<SetFalse, [], [ClangOption], "Disable">,
1925+
BothFlags<[], [ClangOption, CC1Option], " version-independent external API notes support">>,
1926+
Group<f_clang_Group>;
19211927
def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">,
19221928
Group<f_clang_Group>, Visibility<[ClangOption, CC1Option]>,
19231929
MetaVarName<"<version>">,

clang/include/clang/Sema/Sema.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1848,7 +1848,17 @@ class Sema final : public SemaBase {
18481848
///
18491849
/// Triggered by declaration-attribute processing.
18501850
void ProcessAPINotes(Decl *D);
1851-
1851+
/// Apply the 'Nullability:' annotation to the specified declaration
1852+
void ApplyNullability(Decl *D, NullabilityKind Nullability);
1853+
/// Apply the 'Type:' annotation to the specified declaration
1854+
void ApplyAPINotesType(Decl *D, StringRef TypeString);
1855+
1856+
/// Whether APINotes should be gathered for all applicable Swift language
1857+
/// versions, without being applied. Leaving clients of the current module
1858+
/// to select and apply the correct version.
1859+
bool captureSwiftVersionIndependentAPINotes() {
1860+
return APINotes.captureVersionIndependentSwift();
1861+
}
18521862
///@}
18531863

18541864
//

clang/lib/APINotes/APINotesManager.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry {
4949
} // namespace
5050

5151
APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts)
52-
: SM(SM), ImplicitAPINotes(LangOpts.APINotes) {}
52+
: SM(SM), ImplicitAPINotes(LangOpts.APINotes),
53+
VersionIndependentSwift(LangOpts.SwiftVersionIndependentAPINotes) {}
5354

5455
APINotesManager::~APINotesManager() {
5556
// Free the API notes readers.

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7270,6 +7270,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &Job,
72707270
Args.AddLastArg(CmdArgs, options::OPT_fapinotes_swift_version);
72717271
}
72727272

7273+
if (Args.hasFlag(options::OPT_fswift_version_independent_apinotes,
7274+
options::OPT_fno_swift_version_independent_apinotes, false))
7275+
CmdArgs.push_back("-fswift-version-independent-apinotes");
7276+
72737277
// -fblocks=0 is default.
72747278
if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
72757279
TC.IsBlocksDefault()) ||

clang/lib/Sema/SemaAPINotes.cpp

Lines changed: 137 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -52,63 +52,58 @@ static bool isIndirectPointerType(QualType Type) {
5252
Pointee->isMemberPointerType();
5353
}
5454

55-
/// Apply nullability to the given declaration.
56-
static void applyNullability(Sema &S, Decl *D, NullabilityKind Nullability,
57-
VersionedInfoMetadata Metadata) {
58-
if (!Metadata.IsActive)
59-
return;
60-
61-
auto GetModified =
62-
[&](Decl *D, QualType QT,
63-
NullabilityKind Nullability) -> std::optional<QualType> {
64-
QualType Original = QT;
65-
S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
66-
isa<ParmVarDecl>(D),
67-
/*OverrideExisting=*/true);
68-
return (QT.getTypePtr() != Original.getTypePtr()) ? std::optional(QT)
69-
: std::nullopt;
70-
};
55+
static void applyAPINotesType(Sema &S, Decl *decl, StringRef typeString,
56+
VersionedInfoMetadata metadata) {
57+
if (typeString.empty())
7158

72-
if (auto Function = dyn_cast<FunctionDecl>(D)) {
73-
if (auto Modified =
74-
GetModified(D, Function->getReturnType(), Nullability)) {
75-
const FunctionType *FnType = Function->getType()->castAs<FunctionType>();
76-
if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))
77-
Function->setType(S.Context.getFunctionType(
78-
*Modified, proto->getParamTypes(), proto->getExtProtoInfo()));
79-
else
80-
Function->setType(
81-
S.Context.getFunctionNoProtoType(*Modified, FnType->getExtInfo()));
82-
}
83-
} else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
84-
if (auto Modified = GetModified(D, Method->getReturnType(), Nullability)) {
85-
Method->setReturnType(*Modified);
59+
return;
8660

87-
// Make it a context-sensitive keyword if we can.
88-
if (!isIndirectPointerType(*Modified))
89-
Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
90-
Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
91-
}
92-
} else if (auto Value = dyn_cast<ValueDecl>(D)) {
93-
if (auto Modified = GetModified(D, Value->getType(), Nullability)) {
94-
Value->setType(*Modified);
61+
// Version-independent APINotes add "type" annotations
62+
// with a versioned attribute for the client to select and apply.
63+
if (S.captureSwiftVersionIndependentAPINotes()) {
64+
auto *typeAttr = SwiftTypeAttr::CreateImplicit(S.Context, typeString);
65+
auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit(
66+
S.Context, metadata.Version, typeAttr, metadata.IsReplacement);
67+
decl->addAttr(versioned);
68+
} else {
69+
if (!metadata.IsActive)
70+
return;
71+
S.ApplyAPINotesType(decl, typeString);
72+
}
73+
}
9574

96-
// Make it a context-sensitive keyword if we can.
97-
if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
98-
if (Parm->isObjCMethodParameter() && !isIndirectPointerType(*Modified))
99-
Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
100-
Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
101-
}
75+
/// Apply nullability to the given declaration.
76+
static void applyNullability(Sema &S, Decl *decl, NullabilityKind nullability,
77+
VersionedInfoMetadata metadata) {
78+
// Version-independent APINotes add "nullability" annotations
79+
// with a versioned attribute for the client to select and apply.
80+
if (S.captureSwiftVersionIndependentAPINotes()) {
81+
SwiftNullabilityAttr::Kind attrNullabilityKind;
82+
switch (nullability) {
83+
case NullabilityKind::NonNull:
84+
attrNullabilityKind = SwiftNullabilityAttr::Kind::NonNull;
85+
break;
86+
case NullabilityKind::Nullable:
87+
attrNullabilityKind = SwiftNullabilityAttr::Kind::Nullable;
88+
break;
89+
case NullabilityKind::Unspecified:
90+
attrNullabilityKind = SwiftNullabilityAttr::Kind::Unspecified;
91+
break;
92+
case NullabilityKind::NullableResult:
93+
attrNullabilityKind = SwiftNullabilityAttr::Kind::NullableResult;
94+
break;
10295
}
103-
} else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
104-
if (auto Modified = GetModified(D, Property->getType(), Nullability)) {
105-
Property->setType(*Modified, Property->getTypeSourceInfo());
96+
auto *nullabilityAttr =
97+
SwiftNullabilityAttr::CreateImplicit(S.Context, attrNullabilityKind);
98+
auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit(
99+
S.Context, metadata.Version, nullabilityAttr, metadata.IsReplacement);
100+
decl->addAttr(versioned);
101+
return;
102+
} else {
103+
if (!metadata.IsActive)
104+
return;
106105

107-
// Make it a property attribute if we can.
108-
if (!isIndirectPointerType(*Modified))
109-
Property->setPropertyAttributes(
110-
ObjCPropertyAttribute::kind_null_resettable);
111-
}
106+
S.ApplyNullability(decl, nullability);
112107
}
113108
}
114109

@@ -361,42 +356,99 @@ static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc,
361356
return false;
362357
}
363358

364-
/// Process API notes for a variable or property.
365-
static void ProcessAPINotes(Sema &S, Decl *D,
366-
const api_notes::VariableInfo &Info,
367-
VersionedInfoMetadata Metadata) {
368-
// Type override.
369-
if (Metadata.IsActive && !Info.getType().empty() &&
370-
S.ParseTypeFromStringCallback) {
371-
auto ParsedType = S.ParseTypeFromStringCallback(
372-
Info.getType(), "<API Notes>", D->getLocation());
359+
void Sema::ApplyAPINotesType(Decl *D, StringRef TypeString) {
360+
if (!TypeString.empty() && ParseTypeFromStringCallback) {
361+
auto ParsedType = ParseTypeFromStringCallback(TypeString, "<API Notes>",
362+
D->getLocation());
373363
if (ParsedType.isUsable()) {
374364
QualType Type = Sema::GetTypeFromParser(ParsedType.get());
375-
auto TypeInfo =
376-
S.Context.getTrivialTypeSourceInfo(Type, D->getLocation());
377-
365+
auto TypeInfo = Context.getTrivialTypeSourceInfo(Type, D->getLocation());
378366
if (auto Var = dyn_cast<VarDecl>(D)) {
379367
// Make adjustments to parameter types.
380368
if (isa<ParmVarDecl>(Var)) {
381-
Type = S.ObjC().AdjustParameterTypeForObjCAutoRefCount(
369+
Type = ObjC().AdjustParameterTypeForObjCAutoRefCount(
382370
Type, D->getLocation(), TypeInfo);
383-
Type = S.Context.getAdjustedParameterType(Type);
371+
Type = Context.getAdjustedParameterType(Type);
384372
}
385373

386-
if (!checkAPINotesReplacementType(S, Var->getLocation(), Var->getType(),
387-
Type)) {
374+
if (!checkAPINotesReplacementType(*this, Var->getLocation(),
375+
Var->getType(), Type)) {
388376
Var->setType(Type);
389377
Var->setTypeSourceInfo(TypeInfo);
390378
}
391-
} else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
392-
if (!checkAPINotesReplacementType(S, Property->getLocation(),
393-
Property->getType(), Type))
394-
Property->setType(Type, TypeInfo);
395-
396-
} else
379+
} else if (auto property = dyn_cast<ObjCPropertyDecl>(D)) {
380+
if (!checkAPINotesReplacementType(*this, property->getLocation(),
381+
property->getType(), Type)) {
382+
property->setType(Type, TypeInfo);
383+
}
384+
} else {
397385
llvm_unreachable("API notes allowed a type on an unknown declaration");
386+
}
387+
}
388+
}
389+
}
390+
391+
void Sema::ApplyNullability(Decl *D, NullabilityKind Nullability) {
392+
auto GetModified =
393+
[&](class Decl *D, QualType QT,
394+
NullabilityKind Nullability) -> std::optional<QualType> {
395+
QualType Original = QT;
396+
CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
397+
isa<ParmVarDecl>(D),
398+
/*OverrideExisting=*/true);
399+
return (QT.getTypePtr() != Original.getTypePtr()) ? std::optional(QT)
400+
: std::nullopt;
401+
};
402+
403+
if (auto Function = dyn_cast<FunctionDecl>(D)) {
404+
if (auto Modified =
405+
GetModified(D, Function->getReturnType(), Nullability)) {
406+
const FunctionType *FnType = Function->getType()->castAs<FunctionType>();
407+
if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))
408+
Function->setType(Context.getFunctionType(
409+
*Modified, proto->getParamTypes(), proto->getExtProtoInfo()));
410+
else
411+
Function->setType(
412+
Context.getFunctionNoProtoType(*Modified, FnType->getExtInfo()));
413+
}
414+
} else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
415+
if (auto Modified = GetModified(D, Method->getReturnType(), Nullability)) {
416+
Method->setReturnType(*Modified);
417+
418+
// Make it a context-sensitive keyword if we can.
419+
if (!isIndirectPointerType(*Modified))
420+
Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
421+
Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
422+
}
423+
} else if (auto Value = dyn_cast<ValueDecl>(D)) {
424+
if (auto Modified = GetModified(D, Value->getType(), Nullability)) {
425+
Value->setType(*Modified);
426+
427+
// Make it a context-sensitive keyword if we can.
428+
if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
429+
if (Parm->isObjCMethodParameter() && !isIndirectPointerType(*Modified))
430+
Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
431+
Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
432+
}
433+
}
434+
} else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
435+
if (auto Modified = GetModified(D, Property->getType(), Nullability)) {
436+
Property->setType(*Modified, Property->getTypeSourceInfo());
437+
438+
// Make it a property attribute if we can.
439+
if (!isIndirectPointerType(*Modified))
440+
Property->setPropertyAttributes(
441+
ObjCPropertyAttribute::kind_null_resettable);
398442
}
399443
}
444+
}
445+
446+
/// Process API notes for a variable or property.
447+
static void ProcessAPINotes(Sema &S, Decl *D,
448+
const api_notes::VariableInfo &Info,
449+
VersionedInfoMetadata Metadata) {
450+
// Type override.
451+
applyAPINotesType(S, D, Info.getType(), Metadata);
400452

401453
// Nullability.
402454
if (auto Nullability = Info.getNullability())
@@ -893,7 +945,8 @@ static void ProcessVersionedAPINotes(
893945
Sema &S, SpecificDecl *D,
894946
const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
895947

896-
maybeAttachUnversionedSwiftName(S, D, Info);
948+
if (!S.captureSwiftVersionIndependentAPINotes())
949+
maybeAttachUnversionedSwiftName(S, D, Info);
897950

898951
unsigned Selected = Info.getSelected().value_or(Info.size());
899952

@@ -903,10 +956,18 @@ static void ProcessVersionedAPINotes(
903956
std::tie(Version, InfoSlice) = Info[i];
904957
auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive;
905958
auto Replacement = IsSubstitution_t::Original;
906-
if (Active == IsActive_t::Inactive && Version.empty()) {
959+
960+
// When collection all APINotes as version-independent,
961+
// capture all as inactive and defer to the client select the
962+
// right one.
963+
if (S.captureSwiftVersionIndependentAPINotes()) {
964+
Active = IsActive_t::Inactive;
965+
Replacement = IsSubstitution_t::Original;
966+
} else if (Active == IsActive_t::Inactive && Version.empty()) {
907967
Replacement = IsSubstitution_t::Replacement;
908968
Version = Info[Selected].first;
909969
}
970+
910971
ProcessAPINotes(S, D, InfoSlice,
911972
VersionedInfoMetadata(Version, Active, Replacement));
912973
}

0 commit comments

Comments
 (0)