Skip to content

Commit fb3f431

Browse files
committed
Merge "merge main into amd-staging Change-Id: I311e3f7f31bbac3d235873b131bf30c6ac9c0d90" into amd-staging
2 parents c78ae8a + 1a00e9f commit fb3f431

File tree

34 files changed

+637
-117
lines changed

34 files changed

+637
-117
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,21 @@ Attribute Changes in Clang
238238
added a new extension query ``__has_extension(swiftcc)`` corresponding to the
239239
``__attribute__((swiftcc))`` attribute.
240240

241+
- The ``_Nullable`` and ``_Nonnull`` family of type attributes can now apply
242+
to certain C++ class types, such as smart pointers:
243+
``void useObject(std::unique_ptr<Object> _Nonnull obj);``.
244+
245+
This works for standard library types including ``unique_ptr``, ``shared_ptr``,
246+
and ``function``. See
247+
`the attribute reference documentation <https://llvm.org/docs/AttributeReference.html#nullability-attributes>`_
248+
for the full list.
249+
250+
- The ``_Nullable`` attribute can be applied to C++ class declarations:
251+
``template <class T> class _Nullable MySmartPointer {};``.
252+
253+
This allows the ``_Nullable`` and ``_Nonnull`` family of type attributes to
254+
apply to this class.
255+
241256
Improvements to Clang's diagnostics
242257
-----------------------------------
243258
- Clang now applies syntax highlighting to the code snippets it

clang/include/clang/Basic/Attr.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2178,9 +2178,10 @@ def TypeNonNull : TypeAttr {
21782178
let Documentation = [TypeNonNullDocs];
21792179
}
21802180

2181-
def TypeNullable : TypeAttr {
2181+
def TypeNullable : DeclOrTypeAttr {
21822182
let Spellings = [CustomKeyword<"_Nullable">];
21832183
let Documentation = [TypeNullableDocs];
2184+
// let Subjects = SubjectList<[CXXRecord], ErrorDiag>;
21842185
}
21852186

21862187
def TypeNullableResult : TypeAttr {

clang/include/clang/Basic/AttrDocs.td

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4151,6 +4151,20 @@ non-underscored keywords. For example:
41514151
@property (assign, nullable) NSView *superview;
41524152
@property (readonly, nonnull) NSArray *subviews;
41534153
@end
4154+
4155+
As well as built-in pointer types, the nullability attributes can be attached
4156+
to C++ classes marked with the ``_Nullable`` attribute.
4157+
4158+
The following C++ standard library types are considered nullable:
4159+
``unique_ptr``, ``shared_ptr``, ``auto_ptr``, ``exception_ptr``, ``function``,
4160+
``move_only_function`` and ``coroutine_handle``.
4161+
4162+
Types should be marked nullable only where the type itself leaves nullability
4163+
ambiguous. For example, ``std::optional`` is not marked ``_Nullable``, because
4164+
``optional<int> _Nullable`` is redundant and ``optional<int> _Nonnull`` is
4165+
not a useful type. ``std::weak_ptr`` is not nullable, because its nullability
4166+
can change with no visible modification, so static annotation is unlikely to be
4167+
unhelpful.
41544168
}];
41554169
}
41564170

@@ -4185,6 +4199,17 @@ The ``_Nullable`` nullability qualifier indicates that a value of the
41854199
int fetch_or_zero(int * _Nullable ptr);
41864200

41874201
a caller of ``fetch_or_zero`` can provide null.
4202+
4203+
The ``_Nullable`` attribute on classes indicates that the given class can
4204+
represent null values, and so the ``_Nullable``, ``_Nonnull`` etc qualifiers
4205+
make sense for this type. For example:
4206+
4207+
.. code-block:: c
4208+
4209+
class _Nullable ArenaPointer { ... };
4210+
4211+
ArenaPointer _Nonnull x = ...;
4212+
ArenaPointer _Nullable y = nullptr;
41884213
}];
41894214
}
41904215

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ EXTENSION(define_target_os_macros,
9494
FEATURE(enumerator_attributes, true)
9595
FEATURE(nullability, true)
9696
FEATURE(nullability_on_arrays, true)
97+
FEATURE(nullability_on_classes, true)
9798
FEATURE(nullability_nullable_result, true)
9899
FEATURE(memory_sanitizer,
99100
LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory |

clang/include/clang/Parse/Parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3014,6 +3014,7 @@ class Parser : public CodeCompletionHandler {
30143014
void DiagnoseAndSkipExtendedMicrosoftTypeAttributes();
30153015
SourceLocation SkipExtendedMicrosoftTypeAttributes();
30163016
void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs);
3017+
void ParseNullabilityClassAttributes(ParsedAttributes &attrs);
30173018
void ParseBorlandTypeAttributes(ParsedAttributes &attrs);
30183019
void ParseOpenCLKernelAttributes(ParsedAttributes &attrs);
30193020
void ParseOpenCLQualifiers(ParsedAttributes &Attrs);

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,9 @@ class Sema final {
16551655
/// Add [[gsl::Pointer]] attributes for std:: types.
16561656
void inferGslPointerAttribute(TypedefNameDecl *TD);
16571657

1658+
/// Add _Nullable attributes for std:: types.
1659+
void inferNullableClassAttribute(CXXRecordDecl *CRD);
1660+
16581661
enum PragmaOptionsAlignKind {
16591662
POAK_Native, // #pragma options align=native
16601663
POAK_Natural, // #pragma options align=natural

clang/lib/AST/Type.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4642,16 +4642,15 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
46424642
case Type::Auto:
46434643
return ResultIfUnknown;
46444644

4645-
// Dependent template specializations can instantiate to pointer
4646-
// types unless they're known to be specializations of a class
4647-
// template.
4645+
// Dependent template specializations could instantiate to pointer types.
46484646
case Type::TemplateSpecialization:
4649-
if (TemplateDecl *templateDecl
4650-
= cast<TemplateSpecializationType>(type.getTypePtr())
4651-
->getTemplateName().getAsTemplateDecl()) {
4652-
if (isa<ClassTemplateDecl>(templateDecl))
4653-
return false;
4654-
}
4647+
// If it's a known class template, we can already check if it's nullable.
4648+
if (TemplateDecl *templateDecl =
4649+
cast<TemplateSpecializationType>(type.getTypePtr())
4650+
->getTemplateName()
4651+
.getAsTemplateDecl())
4652+
if (auto *CTD = dyn_cast<ClassTemplateDecl>(templateDecl))
4653+
return CTD->getTemplatedDecl()->hasAttr<TypeNullableAttr>();
46554654
return ResultIfUnknown;
46564655

46574656
case Type::Builtin:
@@ -4708,6 +4707,17 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
47084707
}
47094708
llvm_unreachable("unknown builtin type");
47104709

4710+
case Type::Record: {
4711+
const RecordDecl *RD = cast<RecordType>(type)->getDecl();
4712+
// For template specializations, look only at primary template attributes.
4713+
// This is a consistent regardless of whether the instantiation is known.
4714+
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
4715+
return CTSD->getSpecializedTemplate()
4716+
->getTemplatedDecl()
4717+
->hasAttr<TypeNullableAttr>();
4718+
return RD->hasAttr<TypeNullableAttr>();
4719+
}
4720+
47114721
// Non-pointer types.
47124722
case Type::Complex:
47134723
case Type::LValueReference:
@@ -4725,7 +4735,6 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
47254735
case Type::DependentAddressSpace:
47264736
case Type::FunctionProto:
47274737
case Type::FunctionNoProto:
4728-
case Type::Record:
47294738
case Type::DeducedTemplateSpecialization:
47304739
case Type::Enum:
47314740
case Type::InjectedClassName:

clang/lib/CodeGen/CGCall.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4393,7 +4393,8 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
43934393
NNAttr = getNonNullAttr(AC.getDecl(), PVD, ArgType, ArgNo);
43944394

43954395
bool CanCheckNullability = false;
4396-
if (SanOpts.has(SanitizerKind::NullabilityArg) && !NNAttr && PVD) {
4396+
if (SanOpts.has(SanitizerKind::NullabilityArg) && !NNAttr && PVD &&
4397+
!PVD->getType()->isRecordType()) {
43974398
auto Nullability = PVD->getType()->getNullability();
43984399
CanCheckNullability = Nullability &&
43994400
*Nullability == NullabilityKind::NonNull &&

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
989989
// return value. Initialize the flag to 'true' and refine it in EmitParmDecl.
990990
if (SanOpts.has(SanitizerKind::NullabilityReturn)) {
991991
auto Nullability = FnRetTy->getNullability();
992-
if (Nullability && *Nullability == NullabilityKind::NonNull) {
992+
if (Nullability && *Nullability == NullabilityKind::NonNull &&
993+
!FnRetTy->isRecordType()) {
993994
if (!(SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) &&
994995
CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>()))
995996
RetValNullabilityPrecondition =

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,15 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) {
15021502
}
15031503
}
15041504

1505+
void Parser::ParseNullabilityClassAttributes(ParsedAttributes &attrs) {
1506+
while (Tok.is(tok::kw__Nullable)) {
1507+
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
1508+
auto Kind = Tok.getKind();
1509+
SourceLocation AttrNameLoc = ConsumeToken();
1510+
attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, Kind);
1511+
}
1512+
}
1513+
15051514
/// Determine whether the following tokens are valid after a type-specifier
15061515
/// which could be a standalone declaration. This will conservatively return
15071516
/// true if there's any doubt, and is appropriate for insert-';' fixits.
@@ -1683,15 +1692,21 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
16831692

16841693
ParsedAttributes attrs(AttrFactory);
16851694
// If attributes exist after tag, parse them.
1686-
MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs);
1687-
1688-
// Parse inheritance specifiers.
1689-
if (Tok.isOneOf(tok::kw___single_inheritance, tok::kw___multiple_inheritance,
1690-
tok::kw___virtual_inheritance))
1691-
ParseMicrosoftInheritanceClassAttributes(attrs);
1692-
1693-
// Allow attributes to precede or succeed the inheritance specifiers.
1694-
MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs);
1695+
for (;;) {
1696+
MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs);
1697+
// Parse inheritance specifiers.
1698+
if (Tok.isOneOf(tok::kw___single_inheritance,
1699+
tok::kw___multiple_inheritance,
1700+
tok::kw___virtual_inheritance)) {
1701+
ParseMicrosoftInheritanceClassAttributes(attrs);
1702+
continue;
1703+
}
1704+
if (Tok.is(tok::kw__Nullable)) {
1705+
ParseNullabilityClassAttributes(attrs);
1706+
continue;
1707+
}
1708+
break;
1709+
}
16951710

16961711
// Source location used by FIXIT to insert misplaced
16971712
// C++11 attributes

clang/lib/Sema/SemaAttr.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,18 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
215215
inferGslPointerAttribute(Record, Record);
216216
}
217217

218+
void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
219+
static llvm::StringSet<> Nullable{
220+
"auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr",
221+
"coroutine_handle", "function", "move_only_function",
222+
};
223+
224+
if (CRD->isInStdNamespace() && Nullable.count(CRD->getName()) &&
225+
!CRD->hasAttr<TypeNullableAttr>())
226+
for (Decl *Redecl : CRD->redecls())
227+
Redecl->addAttr(TypeNullableAttr::CreateImplicit(Context));
228+
}
229+
218230
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
219231
SourceLocation PragmaLoc) {
220232
PragmaMsStackAction Action = Sema::PSK_Reset;

clang/lib/Sema/SemaChecking.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "clang/AST/ExprObjC.h"
2828
#include "clang/AST/ExprOpenMP.h"
2929
#include "clang/AST/FormatString.h"
30+
#include "clang/AST/IgnoreExpr.h"
3031
#include "clang/AST/NSAPI.h"
3132
#include "clang/AST/NonTrivialTypeVisitor.h"
3233
#include "clang/AST/OperationKinds.h"
@@ -7608,6 +7609,14 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
76087609
///
76097610
/// Returns true if the value evaluates to null.
76107611
static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
7612+
// Treat (smart) pointers constructed from nullptr as null, whether we can
7613+
// const-evaluate them or not.
7614+
// This must happen first: the smart pointer expr might have _Nonnull type!
7615+
if (isa<CXXNullPtrLiteralExpr>(
7616+
IgnoreExprNodes(Expr, IgnoreImplicitAsWrittenSingleStep,
7617+
IgnoreElidableImplicitConstructorSingleStep)))
7618+
return true;
7619+
76117620
// If the expression has non-null type, it doesn't evaluate to null.
76127621
if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) {
76137622
if (*nullability == NullabilityKind::NonNull)

clang/lib/Sema/SemaDecl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18317,8 +18317,10 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
1831718317
if (PrevDecl)
1831818318
mergeDeclAttributes(New, PrevDecl);
1831918319

18320-
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(New))
18320+
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(New)) {
1832118321
inferGslOwnerPointerAttribute(CXXRD);
18322+
inferNullableClassAttribute(CXXRD);
18323+
}
1832218324

1832318325
// If there's a #pragma GCC visibility in scope, set the visibility of this
1832418326
// record.

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5982,6 +5982,20 @@ static void handleBuiltinAliasAttr(Sema &S, Decl *D,
59825982
D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
59835983
}
59845984

5985+
static void handleNullableTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5986+
if (AL.isUsedAsTypeAttr())
5987+
return;
5988+
5989+
if (auto *CRD = dyn_cast<CXXRecordDecl>(D);
5990+
!CRD || !(CRD->isClass() || CRD->isStruct())) {
5991+
S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type_str)
5992+
<< AL << AL.isRegularKeywordAttribute() << "classes";
5993+
return;
5994+
}
5995+
5996+
handleSimpleAttribute<TypeNullableAttr>(S, D, AL);
5997+
}
5998+
59855999
static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
59866000
if (!AL.hasParsedType()) {
59876001
S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
@@ -9933,6 +9947,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
99339947
case ParsedAttr::AT_UsingIfExists:
99349948
handleSimpleAttribute<UsingIfExistsAttr>(S, D, AL);
99359949
break;
9950+
9951+
case ParsedAttr::AT_TypeNullable:
9952+
handleNullableTypeAttr(S, D, AL);
9953+
break;
99369954
}
99379955
}
99389956

clang/lib/Sema/SemaInit.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7079,6 +7079,11 @@ PerformConstructorInitialization(Sema &S,
70797079
hasCopyOrMoveCtorParam(S.Context,
70807080
getConstructorInfo(Step.Function.FoundDecl));
70817081

7082+
// A smart pointer constructed from a nullable pointer is nullable.
7083+
if (NumArgs == 1 && !Kind.isExplicitCast())
7084+
S.diagnoseNullableToNonnullConversion(
7085+
Entity.getType(), Args.front()->getType(), Kind.getLocation());
7086+
70827087
// Determine the arguments required to actually perform the constructor
70837088
// call.
70847089
if (S.CompleteConstructorCall(Constructor, Step.Type, Args, Loc,

clang/lib/Sema/SemaOverload.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14811,6 +14811,13 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
1481114811
}
1481214812
}
1481314813

14814+
// Check for nonnull = nullable.
14815+
// This won't be caught in the arg's initialization: the parameter to
14816+
// the assignment operator is not marked nonnull.
14817+
if (Op == OO_Equal)
14818+
diagnoseNullableToNonnullConversion(Args[0]->getType(),
14819+
Args[1]->getType(), OpLoc);
14820+
1481414821
// Convert the arguments.
1481514822
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
1481614823
// Best->Access is only meaningful for class members.

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2171,6 +2171,7 @@ DeclResult Sema::CheckClassTemplate(
21712171

21722172
AddPushedVisibilityAttribute(NewClass);
21732173
inferGslOwnerPointerAttribute(NewClass);
2174+
inferNullableClassAttribute(NewClass);
21742175

21752176
if (TUK != TUK_Friend) {
21762177
// Per C++ [basic.scope.temp]p2, skip the template parameter scopes.

clang/lib/Sema/SemaType.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4715,6 +4715,18 @@ static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld,
47154715
return false;
47164716
}
47174717

4718+
// Whether this is a type broadly expected to have nullability attached.
4719+
// These types are affected by `#pragma assume_nonnull`, and missing nullability
4720+
// will be diagnosed with -Wnullability-completeness.
4721+
static bool shouldHaveNullability(QualType T) {
4722+
return T->canHaveNullability(/*ResultIfUnknown=*/false) &&
4723+
// For now, do not infer/require nullability on C++ smart pointers.
4724+
// It's unclear whether the pragma's behavior is useful for C++.
4725+
// e.g. treating type-aliases and template-type-parameters differently
4726+
// from types of declarations can be surprising.
4727+
!isa<RecordType>(T->getCanonicalTypeInternal());
4728+
}
4729+
47184730
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
47194731
QualType declSpecType,
47204732
TypeSourceInfo *TInfo) {
@@ -4833,8 +4845,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
48334845
// inner pointers.
48344846
complainAboutMissingNullability = CAMN_InnerPointers;
48354847

4836-
if (T->canHaveNullability(/*ResultIfUnknown*/ false) &&
4837-
!T->getNullability()) {
4848+
if (shouldHaveNullability(T) && !T->getNullability()) {
48384849
// Note that we allow but don't require nullability on dependent types.
48394850
++NumPointersRemaining;
48404851
}
@@ -5057,8 +5068,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
50575068
// If the type itself could have nullability but does not, infer pointer
50585069
// nullability and perform consistency checking.
50595070
if (S.CodeSynthesisContexts.empty()) {
5060-
if (T->canHaveNullability(/*ResultIfUnknown*/ false) &&
5061-
!T->getNullability()) {
5071+
if (shouldHaveNullability(T) && !T->getNullability()) {
50625072
if (isVaList(T)) {
50635073
// Record that we've seen a pointer, but do nothing else.
50645074
if (NumPointersRemaining > 0)

clang/test/APINotes/module-cache.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
// RUN: FileCheck -check-prefix=CHECK-ONE-ERROR %s < %t/before.log
2828

2929
// Change the API notes file, after the module has rebuilt once.
30+
// RUN: chmod u+w %t/APINotes/SomeOtherKit.apinotes
3031
// RUN: echo ' - Selector: "methodA"' >> %t/APINotes/SomeOtherKit.apinotes
3132
// RUN: echo ' MethodKind: Instance' >> %t/APINotes/SomeOtherKit.apinotes
3233
// RUN: echo ' Availability: none' >> %t/APINotes/SomeOtherKit.apinotes

clang/test/Sema/nullability.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,5 @@ void arraysInBlocks(void) {
248248
void (^withTypedefBad)(INTS _Nonnull [2]) = // expected-error {{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'INTS' (aka 'int[4]')}}
249249
^(INTS _Nonnull x[2]) {}; // expected-error {{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'INTS' (aka 'int[4]')}}
250250
}
251+
252+
struct _Nullable NotCplusplusClass {}; // expected-error {{'_Nullable' attribute only applies to classes}}

0 commit comments

Comments
 (0)