Skip to content

Commit 99030d3

Browse files
committed
[APINotes] Upstream Sema support for API Notes
1 parent 51d2003 commit 99030d3

File tree

3 files changed

+166
-72
lines changed

3 files changed

+166
-72
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3021,6 +3021,9 @@ class Sema final {
30213021
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
30223022
SourceLocation Loc,
30233023
QualType T);
3024+
QualType AdjustParameterTypeForObjCAutoRefCount(QualType T,
3025+
SourceLocation NameLoc,
3026+
TypeSourceInfo *TSInfo);
30243027
ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc,
30253028
SourceLocation NameLoc, IdentifierInfo *Name,
30263029
QualType T, TypeSourceInfo *TSInfo,
@@ -4806,6 +4809,29 @@ class Sema final {
48064809
/// Valid types should not have multiple attributes with different CCs.
48074810
const AttributedType *getCallingConvAttributedType(QualType T) const;
48084811

4812+
/// Check whether a nullability type specifier can be added to the given
4813+
/// type through some means not written in source (e.g. API notes).
4814+
///
4815+
/// \param Type The type to which the nullability specifier will be
4816+
/// added. On success, this type will be updated appropriately.
4817+
///
4818+
/// \param Nullability The nullability specifier to add.
4819+
///
4820+
/// \param DiagLoc The location to use for diagnostics.
4821+
///
4822+
/// \param AllowArrayTypes Whether to accept nullability specifiers on an
4823+
/// array type (e.g., because it will decay to a pointer).
4824+
///
4825+
/// \param OverrideExisting Whether to override an existing, locally-specified
4826+
/// nullability specifier rather than complaining about the conflict.
4827+
///
4828+
/// \returns true if nullability cannot be applied, false otherwise.
4829+
bool CheckImplicitNullabilityTypeSpecifier(QualType &Type,
4830+
NullabilityKind Nullability,
4831+
SourceLocation DiagLoc,
4832+
bool AllowArrayTypes,
4833+
bool OverrideExisting);
4834+
48094835
/// Process the attributes before creating an attributed statement. Returns
48104836
/// the semantic attributes that have been processed.
48114837
void ProcessStmtAttributes(Stmt *Stmt, const ParsedAttributes &InAttrs,

clang/lib/Sema/SemaDecl.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15139,6 +15139,37 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(
1513915139
}
1514015140
}
1514115141

15142+
QualType Sema::AdjustParameterTypeForObjCAutoRefCount(QualType T,
15143+
SourceLocation NameLoc,
15144+
TypeSourceInfo *TSInfo) {
15145+
// In ARC, infer a lifetime qualifier for appropriate parameter types.
15146+
if (getLangOpts().ObjCAutoRefCount &&
15147+
T.getObjCLifetime() == Qualifiers::OCL_None && T->isObjCLifetimeType()) {
15148+
15149+
Qualifiers::ObjCLifetime Lifetime;
15150+
15151+
// Special cases for arrays:
15152+
// - if it's const, use __unsafe_unretained
15153+
// - otherwise, it's an error
15154+
if (T->isArrayType()) {
15155+
if (!T.isConstQualified()) {
15156+
if (DelayedDiagnostics.shouldDelayDiagnostics())
15157+
DelayedDiagnostics.add(sema::DelayedDiagnostic::makeForbiddenType(
15158+
NameLoc, diag::err_arc_array_param_no_ownership, T, false));
15159+
else
15160+
Diag(NameLoc, diag::err_arc_array_param_no_ownership)
15161+
<< TSInfo->getTypeLoc().getSourceRange();
15162+
}
15163+
Lifetime = Qualifiers::OCL_ExplicitNone;
15164+
} else {
15165+
Lifetime = T->getObjCARCImplicitLifetime();
15166+
}
15167+
T = Context.getLifetimeQualifiedType(T, Lifetime);
15168+
}
15169+
15170+
return T;
15171+
}
15172+
1514215173
ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
1514315174
SourceLocation NameLoc, IdentifierInfo *Name,
1514415175
QualType T, TypeSourceInfo *TSInfo,

clang/lib/Sema/SemaType.cpp

Lines changed: 109 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -7519,6 +7519,26 @@ static bool HandleWebAssemblyFuncrefAttr(TypeProcessingState &State,
75197519
return false;
75207520
}
75217521

7522+
/// Rebuild an attributed type without the nullability attribute on it.
7523+
static QualType rebuildAttributedTypeWithoutNullability(ASTContext &Ctx,
7524+
QualType Type) {
7525+
auto Attributed = dyn_cast<AttributedType>(Type.getTypePtr());
7526+
if (!Attributed)
7527+
return Type;
7528+
7529+
// Skip the nullability attribute; we're done.
7530+
if (Attributed->getImmediateNullability()) {
7531+
return Attributed->getModifiedType();
7532+
}
7533+
7534+
// Build the modified type.
7535+
auto Modified = rebuildAttributedTypeWithoutNullability(
7536+
Ctx, Attributed->getModifiedType());
7537+
assert(Modified.getTypePtr() != Attributed->getModifiedType().getTypePtr());
7538+
return Ctx.getAttributedType(Attributed->getAttrKind(), Modified,
7539+
Attributed->getEquivalentType());
7540+
}
7541+
75227542
/// Map a nullability attribute kind to a nullability kind.
75237543
static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) {
75247544
switch (kind) {
@@ -7539,74 +7559,65 @@ static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) {
75397559
}
75407560
}
75417561

7542-
/// Applies a nullability type specifier to the given type, if possible.
7543-
///
7544-
/// \param state The type processing state.
7545-
///
7546-
/// \param type The type to which the nullability specifier will be
7547-
/// added. On success, this type will be updated appropriately.
7548-
///
7549-
/// \param attr The attribute as written on the type.
7550-
///
7551-
/// \param allowOnArrayType Whether to accept nullability specifiers on an
7552-
/// array type (e.g., because it will decay to a pointer).
7553-
///
7554-
/// \returns true if a problem has been diagnosed, false on success.
7555-
static bool checkNullabilityTypeSpecifier(TypeProcessingState &state,
7556-
QualType &type,
7557-
ParsedAttr &attr,
7558-
bool allowOnArrayType) {
7559-
Sema &S = state.getSema();
7560-
7561-
NullabilityKind nullability = mapNullabilityAttrKind(attr.getKind());
7562-
SourceLocation nullabilityLoc = attr.getLoc();
7563-
bool isContextSensitive = attr.isContextSensitiveKeywordAttribute();
7564-
7565-
recordNullabilitySeen(S, nullabilityLoc);
7562+
static bool CheckNullabilityTypeSpecifier(
7563+
Sema &S, TypeProcessingState *State, ParsedAttr *PAttr, QualType &QT,
7564+
NullabilityKind Nullability, SourceLocation NullabilityLoc,
7565+
bool IsContextSensitive, bool AllowOnArrayType, bool OverrideExisting) {
7566+
bool Implicit = (State == nullptr);
7567+
if (!Implicit)
7568+
recordNullabilitySeen(S, NullabilityLoc);
75667569

75677570
// Check for existing nullability attributes on the type.
7568-
QualType desugared = type;
7569-
while (auto attributed = dyn_cast<AttributedType>(desugared.getTypePtr())) {
7571+
QualType Desugared = QT;
7572+
while (auto Attributed = dyn_cast<AttributedType>(Desugared.getTypePtr())) {
75707573
// Check whether there is already a null
7571-
if (auto existingNullability = attributed->getImmediateNullability()) {
7574+
if (auto ExistingNullability = Attributed->getImmediateNullability()) {
75727575
// Duplicated nullability.
7573-
if (nullability == *existingNullability) {
7574-
S.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
7575-
<< DiagNullabilityKind(nullability, isContextSensitive)
7576-
<< FixItHint::CreateRemoval(nullabilityLoc);
7576+
if (Nullability == *ExistingNullability) {
7577+
if (Implicit)
7578+
break;
7579+
7580+
S.Diag(NullabilityLoc, diag::warn_nullability_duplicate)
7581+
<< DiagNullabilityKind(Nullability, IsContextSensitive)
7582+
<< FixItHint::CreateRemoval(NullabilityLoc);
75777583

75787584
break;
75797585
}
75807586

7581-
// Conflicting nullability.
7582-
S.Diag(nullabilityLoc, diag::err_nullability_conflicting)
7583-
<< DiagNullabilityKind(nullability, isContextSensitive)
7584-
<< DiagNullabilityKind(*existingNullability, false);
7585-
return true;
7587+
if (!OverrideExisting) {
7588+
// Conflicting nullability.
7589+
S.Diag(NullabilityLoc, diag::err_nullability_conflicting)
7590+
<< DiagNullabilityKind(Nullability, IsContextSensitive)
7591+
<< DiagNullabilityKind(*ExistingNullability, false);
7592+
return true;
7593+
}
7594+
7595+
// Rebuild the attributed type, dropping the existing nullability.
7596+
QT = rebuildAttributedTypeWithoutNullability(S.Context, QT);
75867597
}
75877598

7588-
desugared = attributed->getModifiedType();
7599+
Desugared = Attributed->getModifiedType();
75897600
}
75907601

75917602
// If there is already a different nullability specifier, complain.
75927603
// This (unlike the code above) looks through typedefs that might
75937604
// have nullability specifiers on them, which means we cannot
75947605
// provide a useful Fix-It.
7595-
if (auto existingNullability = desugared->getNullability()) {
7596-
if (nullability != *existingNullability) {
7597-
S.Diag(nullabilityLoc, diag::err_nullability_conflicting)
7598-
<< DiagNullabilityKind(nullability, isContextSensitive)
7599-
<< DiagNullabilityKind(*existingNullability, false);
7606+
if (auto ExistingNullability = Desugared->getNullability()) {
7607+
if (Nullability != *ExistingNullability && !Implicit) {
7608+
S.Diag(NullabilityLoc, diag::err_nullability_conflicting)
7609+
<< DiagNullabilityKind(Nullability, IsContextSensitive)
7610+
<< DiagNullabilityKind(*ExistingNullability, false);
76007611

76017612
// Try to find the typedef with the existing nullability specifier.
7602-
if (auto typedefType = desugared->getAs<TypedefType>()) {
7603-
TypedefNameDecl *typedefDecl = typedefType->getDecl();
7613+
if (auto TT = Desugared->getAs<TypedefType>()) {
7614+
TypedefNameDecl *typedefDecl = TT->getDecl();
76047615
QualType underlyingType = typedefDecl->getUnderlyingType();
7605-
if (auto typedefNullability
7606-
= AttributedType::stripOuterNullability(underlyingType)) {
7607-
if (*typedefNullability == *existingNullability) {
7616+
if (auto typedefNullability =
7617+
AttributedType::stripOuterNullability(underlyingType)) {
7618+
if (*typedefNullability == *ExistingNullability) {
76087619
S.Diag(typedefDecl->getLocation(), diag::note_nullability_here)
7609-
<< DiagNullabilityKind(*existingNullability, false);
7620+
<< DiagNullabilityKind(*ExistingNullability, false);
76107621
}
76117622
}
76127623
}
@@ -7616,44 +7627,73 @@ static bool checkNullabilityTypeSpecifier(TypeProcessingState &state,
76167627
}
76177628

76187629
// If this definitely isn't a pointer type, reject the specifier.
7619-
if (!desugared->canHaveNullability() &&
7620-
!(allowOnArrayType && desugared->isArrayType())) {
7621-
S.Diag(nullabilityLoc, diag::err_nullability_nonpointer)
7622-
<< DiagNullabilityKind(nullability, isContextSensitive) << type;
7630+
if (!Desugared->canHaveNullability() &&
7631+
!(AllowOnArrayType && Desugared->isArrayType())) {
7632+
if (!Implicit)
7633+
S.Diag(NullabilityLoc, diag::err_nullability_nonpointer)
7634+
<< DiagNullabilityKind(Nullability, IsContextSensitive) << QT;
7635+
76237636
return true;
76247637
}
76257638

76267639
// For the context-sensitive keywords/Objective-C property
76277640
// attributes, require that the type be a single-level pointer.
7628-
if (isContextSensitive) {
7641+
if (IsContextSensitive) {
76297642
// Make sure that the pointee isn't itself a pointer type.
76307643
const Type *pointeeType = nullptr;
7631-
if (desugared->isArrayType())
7632-
pointeeType = desugared->getArrayElementTypeNoTypeQual();
7633-
else if (desugared->isAnyPointerType())
7634-
pointeeType = desugared->getPointeeType().getTypePtr();
7644+
if (Desugared->isArrayType())
7645+
pointeeType = Desugared->getArrayElementTypeNoTypeQual();
7646+
else if (Desugared->isAnyPointerType())
7647+
pointeeType = Desugared->getPointeeType().getTypePtr();
76357648

76367649
if (pointeeType && (pointeeType->isAnyPointerType() ||
76377650
pointeeType->isObjCObjectPointerType() ||
76387651
pointeeType->isMemberPointerType())) {
7639-
S.Diag(nullabilityLoc, diag::err_nullability_cs_multilevel)
7640-
<< DiagNullabilityKind(nullability, true)
7641-
<< type;
7642-
S.Diag(nullabilityLoc, diag::note_nullability_type_specifier)
7643-
<< DiagNullabilityKind(nullability, false)
7644-
<< type
7645-
<< FixItHint::CreateReplacement(nullabilityLoc,
7646-
getNullabilitySpelling(nullability));
7652+
S.Diag(NullabilityLoc, diag::err_nullability_cs_multilevel)
7653+
<< DiagNullabilityKind(Nullability, true) << QT;
7654+
S.Diag(NullabilityLoc, diag::note_nullability_type_specifier)
7655+
<< DiagNullabilityKind(Nullability, false) << QT
7656+
<< FixItHint::CreateReplacement(NullabilityLoc,
7657+
getNullabilitySpelling(Nullability));
76477658
return true;
76487659
}
76497660
}
76507661

76517662
// Form the attributed type.
7652-
type = state.getAttributedType(
7653-
createNullabilityAttr(S.Context, attr, nullability), type, type);
7663+
if (State) {
7664+
assert(PAttr);
7665+
Attr *A = createNullabilityAttr(S.Context, *PAttr, Nullability);
7666+
QT = State->getAttributedType(A, QT, QT);
7667+
} else {
7668+
attr::Kind attrKind = AttributedType::getNullabilityAttrKind(Nullability);
7669+
QT = S.Context.getAttributedType(attrKind, QT, QT);
7670+
}
76547671
return false;
76557672
}
76567673

7674+
static bool CheckNullabilityTypeSpecifier(TypeProcessingState &State,
7675+
QualType &Type, ParsedAttr &Attr,
7676+
bool AllowOnArrayType) {
7677+
NullabilityKind Nullability = mapNullabilityAttrKind(Attr.getKind());
7678+
SourceLocation NullabilityLoc = Attr.getLoc();
7679+
bool IsContextSensitive = Attr.isContextSensitiveKeywordAttribute();
7680+
7681+
return CheckNullabilityTypeSpecifier(State.getSema(), &State, &Attr, Type,
7682+
Nullability, NullabilityLoc,
7683+
IsContextSensitive, AllowOnArrayType,
7684+
/*overrideExisting*/ false);
7685+
}
7686+
7687+
bool Sema::CheckImplicitNullabilityTypeSpecifier(QualType &Type,
7688+
NullabilityKind Nullability,
7689+
SourceLocation DiagLoc,
7690+
bool AllowArrayTypes,
7691+
bool OverrideExisting) {
7692+
return CheckNullabilityTypeSpecifier(
7693+
*this, nullptr, nullptr, Type, Nullability, DiagLoc,
7694+
/*isContextSensitive*/ false, AllowArrayTypes, OverrideExisting);
7695+
}
7696+
76577697
/// Check the application of the Objective-C '__kindof' qualifier to
76587698
/// the given type.
76597699
static bool checkObjCKindOfType(TypeProcessingState &state, QualType &type,
@@ -8858,11 +8898,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
88588898
bool allowOnArrayType =
88598899
state.getDeclarator().isPrototypeContext() &&
88608900
!hasOuterPointerLikeChunk(state.getDeclarator(), endIndex);
8861-
if (checkNullabilityTypeSpecifier(
8862-
state,
8863-
type,
8864-
attr,
8865-
allowOnArrayType)) {
8901+
if (CheckNullabilityTypeSpecifier(state, type, attr,
8902+
allowOnArrayType)) {
88668903
attr.setInvalid();
88678904
}
88688905

0 commit comments

Comments
 (0)