Skip to content

Commit 17d8ed7

Browse files
authored
[clang] Make nullability-on-classes more robust to redeclarations (#114778)
This is relevant after b24650e where the selected template decl can be anything, even apparently a friend declaration in some cases.
1 parent b4ef43f commit 17d8ed7

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

clang/lib/AST/Type.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "llvm/ADT/APSInt.h"
4444
#include "llvm/ADT/ArrayRef.h"
4545
#include "llvm/ADT/FoldingSet.h"
46+
#include "llvm/ADT/STLExtras.h"
4647
#include "llvm/ADT/SmallVector.h"
4748
#include "llvm/Support/Casting.h"
4849
#include "llvm/Support/ErrorHandling.h"
@@ -4774,7 +4775,10 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
47744775
->getTemplateName()
47754776
.getAsTemplateDecl())
47764777
if (auto *CTD = dyn_cast<ClassTemplateDecl>(templateDecl))
4777-
return CTD->getTemplatedDecl()->hasAttr<TypeNullableAttr>();
4778+
return llvm::any_of(
4779+
CTD->redecls(), [](const RedeclarableTemplateDecl *RTD) {
4780+
return RTD->getTemplatedDecl()->hasAttr<TypeNullableAttr>();
4781+
});
47784782
return ResultIfUnknown;
47794783

47804784
case Type::Builtin:
@@ -4841,10 +4845,14 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
48414845
// For template specializations, look only at primary template attributes.
48424846
// This is a consistent regardless of whether the instantiation is known.
48434847
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
4844-
return CTSD->getSpecializedTemplate()
4845-
->getTemplatedDecl()
4846-
->hasAttr<TypeNullableAttr>();
4847-
return RD->hasAttr<TypeNullableAttr>();
4848+
return llvm::any_of(
4849+
CTSD->getSpecializedTemplate()->redecls(),
4850+
[](const RedeclarableTemplateDecl *RTD) {
4851+
return RTD->getTemplatedDecl()->hasAttr<TypeNullableAttr>();
4852+
});
4853+
return llvm::any_of(RD->redecls(), [](const TagDecl *RD) {
4854+
return RD->hasAttr<TypeNullableAttr>();
4855+
});
48484856
}
48494857

48504858
// Non-pointer types.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-nullability-declspec %s -verify -Wnullable-to-nonnull-conversion -I%S/Inputs
2+
3+
class Foo;
4+
using Foo1 = Foo _Nonnull; // expected-error{{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'Foo'}}
5+
class _Nullable Foo;
6+
using Foo2 = Foo _Nonnull;
7+
class Foo;
8+
using Foo3 = Foo _Nonnull;
9+
10+
template <class T>
11+
class Bar;
12+
using Bar1 = Bar<int> _Nonnull; // expected-error{{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'Bar<int>'}}
13+
template <class T>
14+
class _Nullable Bar;
15+
using Bar2 = Bar<int> _Nonnull;
16+
template <class T>
17+
class Bar;
18+
using Bar3 = Bar<int> _Nonnull;
19+
20+
namespace std {
21+
template<class T> class unique_ptr;
22+
using UP1 = unique_ptr<int> _Nonnull;
23+
class X { template<class T> friend class unique_ptr; };
24+
using UP2 = unique_ptr<int> _Nonnull;
25+
template<class T> class unique_ptr;
26+
using UP3 = unique_ptr<int> _Nonnull;
27+
}

0 commit comments

Comments
 (0)