forked from OSchip/llvm-project
Implement support for [[maybe_unused]] in C++1z that is based off existing support for unused, and treat it as an extension pre-C++1z. This also means extending the existing unused attribute so that it can be placed on an enum and enumerator, in addition to the other subjects.
llvm-svn: 263025
This commit is contained in:
parent
0da267dd1d
commit
0bcd6c1b18
clang
include/clang
lib
test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused
www
|
@ -1484,11 +1484,11 @@ def ObjCRequiresPropertyDefs : InheritableAttr {
|
|||
}
|
||||
|
||||
def Unused : InheritableAttr {
|
||||
let Spellings = [GCC<"unused">];
|
||||
let Subjects = SubjectList<[Var, ObjCIvar, Type, Label, Field, ObjCMethod,
|
||||
FunctionLike], WarnDiag,
|
||||
"ExpectedVariableFunctionOrLabel">;
|
||||
let Documentation = [Undocumented];
|
||||
let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">];
|
||||
let Subjects = SubjectList<[Var, ObjCIvar, Type, Enum, EnumConstant, Label,
|
||||
Field, ObjCMethod, FunctionLike], WarnDiag,
|
||||
"ExpectedForMaybeUnused">;
|
||||
let Documentation = [WarnMaybeUnusedDocs];
|
||||
}
|
||||
|
||||
def Used : InheritableAttr {
|
||||
|
|
|
@ -729,6 +729,32 @@ When one method overrides another, the overriding method can be more widely avai
|
|||
}];
|
||||
}
|
||||
|
||||
def WarnMaybeUnusedDocs : Documentation {
|
||||
let Category = DocCatVariable;
|
||||
let Heading = "maybe_unused, unused, gnu::unused";
|
||||
let Content = [{
|
||||
When passing the ``-Wunused`` flag to Clang, entities that are unused by the
|
||||
program may be diagnosed. The ``[[maybe_unused]]`` (or
|
||||
``__attribute__((unused))``) attribute can be used to silence such diagnostics
|
||||
when the entity cannot be removed. For instance, a local variable may exist
|
||||
solely for use in an ``assert()`` statement, which makes the local variable
|
||||
unused when ``NDEBUG`` is defined.
|
||||
|
||||
The attribute may be applied to the declaration of a class, a typedef, a
|
||||
variable, a function or method, a function parameter, an enumeration, an
|
||||
enumerator, a non-static data member, or a label.
|
||||
|
||||
.. code-block: c++
|
||||
#include <cassert>
|
||||
|
||||
[[maybe_unused]] void f([[maybe_unused]] bool thing1,
|
||||
[[maybe_unused]] bool thing2) {
|
||||
[[maybe_unused]] bool b = thing1 && thing2;
|
||||
assert(b);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
def WarnUnusedResultsDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "nodiscard, warn_unused_result, clang::warn_unused_result, gnu::warn_unused_result";
|
||||
|
|
|
@ -2468,8 +2468,7 @@ def warn_attribute_wrong_decl_type : Warning<
|
|||
"variables and functions|functions and methods|parameters|"
|
||||
"functions, methods and blocks|functions, methods, and classes|"
|
||||
"functions, methods, and parameters|classes|enums|variables|methods|"
|
||||
"variables, functions and labels|fields and global variables|structs|"
|
||||
"variables and typedefs|thread-local variables|"
|
||||
"fields and global variables|structs|variables and typedefs|thread-local variables|"
|
||||
"variables and fields|variables, data members and tag types|"
|
||||
"types and namespaces|Objective-C interfaces|methods and properties|"
|
||||
"struct or union|struct, union or class|types|"
|
||||
|
@ -2478,7 +2477,8 @@ def warn_attribute_wrong_decl_type : Warning<
|
|||
"functions and global variables|structs, unions, and typedefs|structs and typedefs|"
|
||||
"interface or protocol declarations|kernel functions|non-K&R-style functions|"
|
||||
"variables, enums, fields and typedefs|functions, methods, enums, and classes|"
|
||||
"structs, classes, variables, functions, and inline namespaces}1">,
|
||||
"structs, classes, variables, functions, and inline namespaces|"
|
||||
"variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members}1">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
|
||||
def warn_type_attribute_wrong_type : Warning<
|
||||
|
|
|
@ -871,7 +871,6 @@ enum AttributeDeclKind {
|
|||
ExpectedEnum,
|
||||
ExpectedVariable,
|
||||
ExpectedMethod,
|
||||
ExpectedVariableFunctionOrLabel,
|
||||
ExpectedFieldOrGlobalVar,
|
||||
ExpectedStruct,
|
||||
ExpectedVariableOrTypedef,
|
||||
|
@ -896,7 +895,8 @@ enum AttributeDeclKind {
|
|||
ExpectedFunctionWithProtoType,
|
||||
ExpectedVariableEnumFieldOrTypedef,
|
||||
ExpectedFunctionMethodEnumOrClass,
|
||||
ExpectedStructClassVariableFunctionOrInlineNamespace
|
||||
ExpectedStructClassVariableFunctionOrInlineNamespace,
|
||||
ExpectedForMaybeUnused
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -3637,6 +3637,8 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
|
|||
return true;
|
||||
case AttributeList::AT_WarnUnusedResult:
|
||||
return !ScopeName && AttrName->getName().equals("nodiscard");
|
||||
case AttributeList::AT_Unused:
|
||||
return !ScopeName && AttrName->getName().equals("maybe_unused");
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -459,7 +459,8 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
|
|||
if (VD->isUsed())
|
||||
Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name;
|
||||
|
||||
VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation()));
|
||||
VD->addAttr(UnusedAttr::CreateImplicit(Context, UnusedAttr::GNU_unused,
|
||||
IdTok.getLocation()));
|
||||
}
|
||||
|
||||
void Sema::AddCFAuditedAttribute(Decl *D) {
|
||||
|
|
|
@ -1807,6 +1807,28 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
|||
Attr.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||
bool IsCXX1zAttr = Attr.isCXX11Attribute() && !Attr.getScopeName();
|
||||
|
||||
if (IsCXX1zAttr && isa<VarDecl>(D)) {
|
||||
// The C++1z spelling of this attribute cannot be applied to a static data
|
||||
// member per [dcl.attr.unused]p2.
|
||||
if (cast<VarDecl>(D)->isStaticDataMember()) {
|
||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||
<< Attr.getName() << ExpectedForMaybeUnused;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is spelled as the standard C++1z attribute, but not in C++1z, warn
|
||||
// about using it as an extension.
|
||||
if (!S.getLangOpts().CPlusPlus1z && IsCXX1zAttr)
|
||||
S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName();
|
||||
|
||||
D->addAttr(::new (S.Context) UnusedAttr(
|
||||
Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||
uint32_t priority = ConstructorAttr::DefaultPriority;
|
||||
if (Attr.getNumArgs() &&
|
||||
|
@ -5545,7 +5567,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_Unused:
|
||||
handleSimpleAttribute<UnusedAttr>(S, D, Attr);
|
||||
handleUnusedAttr(S, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_ReturnsTwice:
|
||||
handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr);
|
||||
|
|
|
@ -76,10 +76,14 @@ bool Sema::CanUseDecl(NamedDecl *D) {
|
|||
|
||||
static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
|
||||
// Warn if this is used but marked unused.
|
||||
if (D->hasAttr<UnusedAttr>()) {
|
||||
const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext());
|
||||
if (DC && !DC->hasAttr<UnusedAttr>())
|
||||
S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
|
||||
if (const auto *A = D->getAttr<UnusedAttr>()) {
|
||||
// [[maybe_unused]] should not diagnose uses, but __attribute__((unused))
|
||||
// should diagnose them.
|
||||
if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused) {
|
||||
const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext());
|
||||
if (DC && !DC->hasAttr<UnusedAttr>())
|
||||
S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -Wunused -std=c++1z -verify %s
|
||||
|
||||
struct [[maybe_unused]] S1 {}; // ok
|
||||
struct [[maybe_unused maybe_unused]] S2 {}; // expected-error {{attribute 'maybe_unused' cannot appear multiple times in an attribute specifier}}
|
||||
struct [[maybe_unused("Wrong")]] S3 {}; // expected-error {{'maybe_unused' cannot have an argument list}}
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -Wunused -std=c++1z -verify %s
|
||||
|
||||
struct [[maybe_unused]] S {
|
||||
int I [[maybe_unused]];
|
||||
static int SI [[maybe_unused]]; // expected-warning {{'maybe_unused' attribute only applies to variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members}}
|
||||
};
|
||||
|
||||
enum [[maybe_unused]] E1 {
|
||||
EnumVal [[maybe_unused]]
|
||||
};
|
||||
|
||||
[[maybe_unused]] void unused_func([[maybe_unused]] int parm) {
|
||||
typedef int maybe_unused_int [[maybe_unused]];
|
||||
[[maybe_unused]] int I;
|
||||
}
|
||||
|
||||
namespace [[maybe_unused]] N {} // expected-warning {{'maybe_unused' attribute only applies to}}
|
|
@ -0,0 +1,26 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -Wunused -Wused-but-marked-unused -std=c++1z -Wc++1z-extensions -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -Wunused -Wused-but-marked-unused -std=c++11 -Wc++1z-extensions -verify -DEXT %s
|
||||
|
||||
static_assert(__has_cpp_attribute(maybe_unused) == 201603, "");
|
||||
|
||||
struct [[maybe_unused]] S {};
|
||||
|
||||
void f() {
|
||||
int x; // expected-warning {{unused variable}}
|
||||
typedef int I; // expected-warning {{unused typedef 'I'}}
|
||||
|
||||
// Should not warn about these due to not being used.
|
||||
[[maybe_unused]] int y;
|
||||
typedef int maybe_unused_int [[maybe_unused]];
|
||||
|
||||
// Should not warn about these uses.
|
||||
S s;
|
||||
maybe_unused_int test;
|
||||
y = 12;
|
||||
}
|
||||
|
||||
#ifdef EXT
|
||||
// expected-warning@6 {{use of the 'maybe_unused' attribute is a C++1z extension}}
|
||||
// expected-warning@13 {{use of the 'maybe_unused' attribute is a C++1z extension}}
|
||||
// expected-warning@14 {{use of the 'maybe_unused' attribute is a C++1z extension}}
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -Wunused -std=c++1z -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
void f();
|
||||
[[maybe_unused]] void f();
|
||||
|
||||
void f() {
|
||||
}
|
|
@ -639,7 +639,7 @@ as the draft C++1z standard evolves.</p>
|
|||
<tr>
|
||||
<td><tt>[[maybe_unused]]</tt> attribute</td>
|
||||
<td><a href="http://wg21.link/p0212r1">P0212R1</a></td>
|
||||
<td class="none" align="center">No</td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Aggregate initialization of classes with base classes</td>
|
||||
|
|
Loading…
Reference in New Issue