Skip to content

Commit 19634d4

Browse files
committed
[APINotes] Upstream Sema support for API Notes
1 parent 3a5c9b7 commit 19634d4

File tree

3 files changed

+165
-72
lines changed

3 files changed

+165
-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,
@@ -4820,6 +4823,29 @@ class Sema final {
48204823
/// Valid types should not have multiple attributes with different CCs.
48214824
const AttributedType *getCallingConvAttributedType(QualType T) const;
48224825

4826+
/// Check whether a nullability type specifier can be added to the given
4827+
/// type through some means not written in source (e.g. API notes).
4828+
///
4829+
/// \param Type The type to which the nullability specifier will be
4830+
/// added. On success, this type will be updated appropriately.
4831+
///
4832+
/// \param Nullability The nullability specifier to add.
4833+
///
4834+
/// \param DiagLoc The location to use for diagnostics.
4835+
///
4836+
/// \param AllowArrayTypes Whether to accept nullability specifiers on an
4837+
/// array type (e.g., because it will decay to a pointer).
4838+
///
4839+
/// \param OverrideExisting Whether to override an existing, locally-specified
4840+
/// nullability specifier rather than complaining about the conflict.
4841+
///
4842+
/// \returns true if nullability cannot be applied, false otherwise.
4843+
bool CheckImplicitNullabilityTypeSpecifier(QualType &Type,
4844+
NullabilityKind Nullability,
4845+
SourceLocation DiagLoc,
4846+
bool AllowArrayTypes,
4847+
bool OverrideExisting);
4848+
48234849
/// Process the attributes before creating an attributed statement. Returns
48244850
/// the semantic attributes that have been processed.
48254851
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
@@ -15171,6 +15171,37 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(
1517115171
}
1517215172
}
1517315173

15174+
QualType Sema::AdjustParameterTypeForObjCAutoRefCount(QualType T,
15175+
SourceLocation NameLoc,
15176+
TypeSourceInfo *TSInfo) {
15177+
// In ARC, infer a lifetime qualifier for appropriate parameter types.
15178+
if (!getLangOpts().ObjCAutoRefCount ||
15179+
T.getObjCLifetime() != Qualifiers::OCL_None || !T->isObjCLifetimeType())
15180+
return T;
15181+
15182+
Qualifiers::ObjCLifetime Lifetime;
15183+
15184+
// Special cases for arrays:
15185+
// - if it's const, use __unsafe_unretained
15186+
// - otherwise, it's an error
15187+
if (T->isArrayType()) {
15188+
if (!T.isConstQualified()) {
15189+
if (DelayedDiagnostics.shouldDelayDiagnostics())
15190+
DelayedDiagnostics.add(sema::DelayedDiagnostic::makeForbiddenType(
15191+
NameLoc, diag::err_arc_array_param_no_ownership, T, false));
15192+
else
15193+
Diag(NameLoc, diag::err_arc_array_param_no_ownership)
15194+
<< TSInfo->getTypeLoc().getSourceRange();
15195+
}
15196+
Lifetime = Qualifiers::OCL_ExplicitNone;
15197+
} else {
15198+
Lifetime = T->getObjCARCImplicitLifetime();
15199+
}
15200+
T = Context.getLifetimeQualifiedType(T, Lifetime);
15201+
15202+
return T;
15203+
}
15204+
1517415205
ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
1517515206
SourceLocation NameLoc, IdentifierInfo *Name,
1517615207
QualType T, TypeSourceInfo *TSInfo,

clang/lib/Sema/SemaType.cpp

Lines changed: 108 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -7521,6 +7521,25 @@ static bool HandleWebAssemblyFuncrefAttr(TypeProcessingState &State,
75217521
return false;
75227522
}
75237523

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

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

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

75807585
break;
75817586
}
75827587

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

7590-
desugared = attributed->getModifiedType();
7600+
Desugared = Attributed->getModifiedType();
75917601
}
75927602

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

76037613
// Try to find the typedef with the existing nullability specifier.
7604-
if (auto typedefType = desugared->getAs<TypedefType>()) {
7605-
TypedefNameDecl *typedefDecl = typedefType->getDecl();
7614+
if (auto TT = Desugared->getAs<TypedefType>()) {
7615+
TypedefNameDecl *typedefDecl = TT->getDecl();
76067616
QualType underlyingType = typedefDecl->getUnderlyingType();
7607-
if (auto typedefNullability
7608-
= AttributedType::stripOuterNullability(underlyingType)) {
7609-
if (*typedefNullability == *existingNullability) {
7617+
if (auto typedefNullability =
7618+
AttributedType::stripOuterNullability(underlyingType)) {
7619+
if (*typedefNullability == *ExistingNullability) {
76107620
S.Diag(typedefDecl->getLocation(), diag::note_nullability_here)
7611-
<< DiagNullabilityKind(*existingNullability, false);
7621+
<< DiagNullabilityKind(*ExistingNullability, false);
76127622
}
76137623
}
76147624
}
@@ -7618,44 +7628,73 @@ static bool checkNullabilityTypeSpecifier(TypeProcessingState &state,
76187628
}
76197629

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

76287640
// For the context-sensitive keywords/Objective-C property
76297641
// attributes, require that the type be a single-level pointer.
7630-
if (isContextSensitive) {
7642+
if (IsContextSensitive) {
76317643
// Make sure that the pointee isn't itself a pointer type.
76327644
const Type *pointeeType = nullptr;
7633-
if (desugared->isArrayType())
7634-
pointeeType = desugared->getArrayElementTypeNoTypeQual();
7635-
else if (desugared->isAnyPointerType())
7636-
pointeeType = desugared->getPointeeType().getTypePtr();
7645+
if (Desugared->isArrayType())
7646+
pointeeType = Desugared->getArrayElementTypeNoTypeQual();
7647+
else if (Desugared->isAnyPointerType())
7648+
pointeeType = Desugared->getPointeeType().getTypePtr();
76377649

76387650
if (pointeeType && (pointeeType->isAnyPointerType() ||
76397651
pointeeType->isObjCObjectPointerType() ||
76407652
pointeeType->isMemberPointerType())) {
7641-
S.Diag(nullabilityLoc, diag::err_nullability_cs_multilevel)
7642-
<< DiagNullabilityKind(nullability, true)
7643-
<< type;
7644-
S.Diag(nullabilityLoc, diag::note_nullability_type_specifier)
7645-
<< DiagNullabilityKind(nullability, false)
7646-
<< type
7647-
<< FixItHint::CreateReplacement(nullabilityLoc,
7648-
getNullabilitySpelling(nullability));
7653+
S.Diag(NullabilityLoc, diag::err_nullability_cs_multilevel)
7654+
<< DiagNullabilityKind(Nullability, true) << QT;
7655+
S.Diag(NullabilityLoc, diag::note_nullability_type_specifier)
7656+
<< DiagNullabilityKind(Nullability, false) << QT
7657+
<< FixItHint::CreateReplacement(NullabilityLoc,
7658+
getNullabilitySpelling(Nullability));
76497659
return true;
76507660
}
76517661
}
76527662

76537663
// Form the attributed type.
7654-
type = state.getAttributedType(
7655-
createNullabilityAttr(S.Context, attr, nullability), type, type);
7664+
if (State) {
7665+
assert(PAttr);
7666+
Attr *A = createNullabilityAttr(S.Context, *PAttr, Nullability);
7667+
QT = State->getAttributedType(A, QT, QT);
7668+
} else {
7669+
attr::Kind attrKind = AttributedType::getNullabilityAttrKind(Nullability);
7670+
QT = S.Context.getAttributedType(attrKind, QT, QT);
7671+
}
76567672
return false;
76577673
}
76587674

7675+
static bool CheckNullabilityTypeSpecifier(TypeProcessingState &State,
7676+
QualType &Type, ParsedAttr &Attr,
7677+
bool AllowOnArrayType) {
7678+
NullabilityKind Nullability = mapNullabilityAttrKind(Attr.getKind());
7679+
SourceLocation NullabilityLoc = Attr.getLoc();
7680+
bool IsContextSensitive = Attr.isContextSensitiveKeywordAttribute();
7681+
7682+
return CheckNullabilityTypeSpecifier(State.getSema(), &State, &Attr, Type,
7683+
Nullability, NullabilityLoc,
7684+
IsContextSensitive, AllowOnArrayType,
7685+
/*overrideExisting*/ false);
7686+
}
7687+
7688+
bool Sema::CheckImplicitNullabilityTypeSpecifier(QualType &Type,
7689+
NullabilityKind Nullability,
7690+
SourceLocation DiagLoc,
7691+
bool AllowArrayTypes,
7692+
bool OverrideExisting) {
7693+
return CheckNullabilityTypeSpecifier(
7694+
*this, nullptr, nullptr, Type, Nullability, DiagLoc,
7695+
/*isContextSensitive*/ false, AllowArrayTypes, OverrideExisting);
7696+
}
7697+
76597698
/// Check the application of the Objective-C '__kindof' qualifier to
76607699
/// the given type.
76617700
static bool checkObjCKindOfType(TypeProcessingState &state, QualType &type,
@@ -8950,11 +8989,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
89508989
bool allowOnArrayType =
89518990
state.getDeclarator().isPrototypeContext() &&
89528991
!hasOuterPointerLikeChunk(state.getDeclarator(), endIndex);
8953-
if (checkNullabilityTypeSpecifier(
8954-
state,
8955-
type,
8956-
attr,
8957-
allowOnArrayType)) {
8992+
if (CheckNullabilityTypeSpecifier(state, type, attr,
8993+
allowOnArrayType)) {
89588994
attr.setInvalid();
89598995
}
89608996

0 commit comments

Comments
 (0)