From 0bcd6c1b18d23e0d47d0a9bbc8084547faa9786f Mon Sep 17 00:00:00 2001
From: Aaron Ballman
Date: Wed, 9 Mar 2016 16:48:08 +0000
Subject: [PATCH] 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
---
clang/include/clang/Basic/Attr.td | 10 ++++-----
clang/include/clang/Basic/AttrDocs.td | 26 ++++++++++++++++++++++
clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 ++---
clang/include/clang/Sema/AttributeList.h | 4 ++--
clang/lib/Parse/ParseDeclCXX.cpp | 2 ++
clang/lib/Sema/SemaAttr.cpp | 3 ++-
clang/lib/Sema/SemaDeclAttr.cpp | 24 +++++++++++++++++++-
clang/lib/Sema/SemaExpr.cpp | 12 ++++++----
.../CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p1.cpp | 5 +++++
.../CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p2.cpp | 17 ++++++++++++++
.../CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p3.cpp | 26 ++++++++++++++++++++++
.../CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p4.cpp | 8 +++++++
clang/www/cxx_status.html | 2 +-
13 files changed, 128 insertions(+), 17 deletions(-)
create mode 100644 clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p1.cpp
create mode 100644 clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p2.cpp
create mode 100644 clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p3.cpp
create mode 100644 clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p4.cpp
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 21078e0..f50cb29 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -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 {
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 2bf8a82..70a2e5b 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -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
+
+ [[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";
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 45de16b..239144d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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;
def err_attribute_wrong_decl_type : Error;
def warn_type_attribute_wrong_type : Warning<
diff --git a/clang/include/clang/Sema/AttributeList.h b/clang/include/clang/Sema/AttributeList.h
index a3e656e..c59f3b9 100644
--- a/clang/include/clang/Sema/AttributeList.h
+++ b/clang/include/clang/Sema/AttributeList.h
@@ -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
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 354e405..8a28f65 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -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;
}
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 4b7aa2b..7f523c4 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -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) {
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index f8cec75..0cae52a 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -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(D)) {
+ // The C++1z spelling of this attribute cannot be applied to a static data
+ // member per [dcl.attr.unused]p2.
+ if (cast(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(S, D, Attr);
break;
case AttributeList::AT_Unused:
- handleSimpleAttribute(S, D, Attr);
+ handleUnusedAttr(S, D, Attr);
break;
case AttributeList::AT_ReturnsTwice:
handleSimpleAttribute(S, D, Attr);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 4b88175..54dcced 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -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()) {
- const Decl *DC = cast_or_null(S.getCurObjCLexicalContext());
- if (DC && !DC->hasAttr())
- S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
+ if (const auto *A = D->getAttr()) {
+ // [[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(S.getCurObjCLexicalContext());
+ if (DC && !DC->hasAttr())
+ S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
+ }
}
}
diff --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p1.cpp
new file mode 100644
index 0000000..8da2ca7
--- /dev/null
+++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p1.cpp
@@ -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}}
diff --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p2.cpp
new file mode 100644
index 0000000..b539ca4
--- /dev/null
+++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p2.cpp
@@ -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}}
diff --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p3.cpp
new file mode 100644
index 0000000..a627d83
--- /dev/null
+++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p3.cpp
@@ -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
diff --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p4.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p4.cpp
new file mode 100644
index 0000000..d4a2759
--- /dev/null
+++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p4.cpp
@@ -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() {
+}
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 5163402..fc354b2 100644
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -639,7 +639,7 @@ as the draft C++1z standard evolves.
[[maybe_unused]] attribute |
P0212R1 |
- No |
+ SVN |
Aggregate initialization of classes with base classes |
--
2.7.4