Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,9 @@ Bug Fixes to Attribute Support
``__attribute__((unused))`` are still ignored after the definition, though
this behavior may be relaxed in the future). (#GH135481)

- Clang will warn if a completete type specializes a deprecated partial specialization.
(#GH44496)

Bug Fixes to C++ Support
^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
16 changes: 10 additions & 6 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2385,12 +2385,16 @@ class Sema final : public SemaBase {
/// potential availability violations.
sema::FunctionScopeInfo *getCurFunctionAvailabilityContext();

void DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
const ObjCInterfaceDecl *UnknownObjCClass,
bool ObjCPropertyAccess,
bool AvoidPartialAvailabilityChecks = false,
ObjCInterfaceDecl *ClassReceiver = nullptr);

void DiagnoseAvailabilityOfDecl(
NamedDecl *D, ArrayRef<SourceLocation> Locs,
const ObjCInterfaceDecl *UnknownObjCClass = nullptr,
bool ObjCPropertyAccess = false,
bool AvoidPartialAvailabilityChecks = false,
ObjCInterfaceDecl *ClassReceiver = nullptr);

std::pair<AvailabilityResult, const NamedDecl *>
ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message,
ObjCInterfaceDecl *ClassReceiver);
///@}

//
Expand Down
21 changes: 10 additions & 11 deletions clang/lib/Sema/SemaAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,9 @@ static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
/// the availability attribute that is selected.
/// \param ClassReceiver If we're checking the method of a class message
/// send, the class. Otherwise nullptr.
static std::pair<AvailabilityResult, const NamedDecl *>
ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
std::string *Message,
ObjCInterfaceDecl *ClassReceiver) {
std::pair<AvailabilityResult, const NamedDecl *>
Sema::ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message,
ObjCInterfaceDecl *ClassReceiver) {
AvailabilityResult Result = D->getAvailability(Message);

// For typedefs, if the typedef declaration appears available look
Expand Down Expand Up @@ -147,12 +146,12 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,

// For +new, infer availability from -init.
if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (S.ObjC().NSAPIObj && ClassReceiver) {
if (ObjC().NSAPIObj && ClassReceiver) {
ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod(
S.ObjC().NSAPIObj->getInitSelector());
ObjC().NSAPIObj->getInitSelector());
if (Init && Result == AR_Available && MD->isClassMethod() &&
MD->getSelector() == S.ObjC().NSAPIObj->getNewSelector() &&
MD->definedInNSObject(S.getASTContext())) {
MD->getSelector() == ObjC().NSAPIObj->getNewSelector() &&
MD->definedInNSObject(getASTContext())) {
Result = Init->getAvailability(Message);
D = Init;
}
Expand All @@ -162,7 +161,6 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
return {Result, D};
}


/// whether we should emit a diagnostic for \c K and \c DeclVersion in
/// the context of \c Ctx. For example, we should emit an unavailable diagnostic
/// in a deprecated context, but not the other way around.
Expand Down Expand Up @@ -876,7 +874,7 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
AvailabilityResult Result;
const NamedDecl *OffendingDecl;
std::tie(Result, OffendingDecl) =
ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass);
SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr, ReceiverClass);
if (Result != AR_Available) {
// All other diagnostic kinds have already been handled in
// DiagnoseAvailabilityOfDecl.
Expand Down Expand Up @@ -1112,12 +1110,13 @@ void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D,
bool ObjCPropertyAccess,
bool AvoidPartialAvailabilityChecks,
ObjCInterfaceDecl *ClassReceiver) {

std::string Message;
AvailabilityResult Result;
const NamedDecl* OffendingDecl;
// See if this declaration is unavailable, deprecated, or partial.
std::tie(Result, OffendingDecl) =
ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver);
ShouldDiagnoseAvailabilityOfDecl(D, &Message, ClassReceiver);
if (Result == AR_Available)
return;

Expand Down
18 changes: 17 additions & 1 deletion clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4094,16 +4094,32 @@ bool Sema::InstantiateClassTemplateSpecialization(
if (ClassTemplateSpec->isInvalidDecl())
return true;

bool HadAvaibilityWarning =
ShouldDiagnoseAvailabilityOfDecl(ClassTemplateSpec, nullptr, nullptr)
.first != AR_Available;

ActionResult<CXXRecordDecl *> Pattern =
getPatternForClassTemplateSpecialization(*this, PointOfInstantiation,
ClassTemplateSpec, TSK,
PrimaryStrictPackMatch);

if (!Pattern.isUsable())
return Pattern.isInvalid();

return InstantiateClass(
bool Err = InstantiateClass(
PointOfInstantiation, ClassTemplateSpec, Pattern.get(),
getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain);

// If we haven't already warn on avaibility, consider the avaibility
// attributes of the partial specialization.
// Note that - because we need to have deduced the partial specialization -
// We can only emit these warnings when the specialization is instantiated.
if (!Err && !HadAvaibilityWarning) {
assert(ClassTemplateSpec->getTemplateSpecializationKind() !=
TSK_Undeclared);
DiagnoseAvailabilityOfDecl(ClassTemplateSpec, PointOfInstantiation);
}
return Err;
}

void
Expand Down
57 changes: 56 additions & 1 deletion clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ template <typename T> struct [[deprecated]] B;//expected-note {{'B<int>' has bee
B<int> *q2; // expected-warning {{'B<int>' is deprecated}}
B<float> *r2; // expected-warning {{'B<float>' is deprecated}}

template <typename T>
template <typename T>
T some_func(T t) {
struct [[deprecated]] FunS{}; // expected-note {{'FunS' has been explicitly marked deprecated here}}
FunS f;// expected-warning {{'FunS' is deprecated}}
Expand All @@ -72,3 +72,58 @@ template <class B1> struct B {

template struct B<A>; // expected-note {{requested here}}
} // namespace GH58547


namespace GH44496 {
template <class> struct my_template {
using type = void;
};

template <class T>
struct [[deprecated("primary")]] deprecated { // #deprecated-primary-marked-here
using type = T;
};

template <class T>
struct my_template<volatile T> : deprecated<T> {}; // #deprecated-primary-base

template <class T>
struct [[deprecated("specialization")]] my_template<const T> : deprecated<const T> {}; // #my_template-explicit-here


template <class T> using my_template_t = typename my_template<T>::type; // #deprecated-my-template-alias

// We cannot warn on X because no instantiation has taken place yet
using X = my_template<volatile int>;

// Because we already warn on the attribute on the plimary template, we ignore the attribute on the specialization
using Y = my_template_t<const int>;
// expected-warning@#deprecated-primary-base {{'deprecated<int>' is deprecated: primary}} \
// expected-note@-1 {{in instantiation of template type alias}} \
// expected-note@#deprecated-primary-marked-here {{has been explicitly marked deprecated here}}

using Z = my_template_t<volatile int>;
// expected-warning@#deprecated-my-template-alias {{'my_template<const int>' is deprecated: specialization}} \
// expected-note@#my_template-explicit-here {{'my_template<const int>' has been explicitly marked deprecated here}} \
// expected-note@#deprecated-my-template-alias {{in instantiation of template class 'GH44496::my_template<volatile int>' requested here}} \
// expected-note@-1 {{in instantiation of template type alias 'my_template_t' requested here}}

template <class T>
struct primary_not_deprecated {
using type = T;
};
template <class T>
struct [[deprecated("specialization")]] primary_not_deprecated<volatile T> : deprecated<T> {};
// expected-note@-1 {{'primary_not_deprecated<volatile int>' has been explicitly marked deprecated here}}

// We cannot warn on S1 because no instantiation has taken place yet
using S1 = primary_not_deprecated<volatile int>;


using S2 = primary_not_deprecated<volatile int>;

X x;
Z z;
S2 s2;
// expected-warning@-1 {{'primary_not_deprecated<volatile int>' is deprecated: specialization}}
}
Loading