erichkeane updated this revision to Diff 211094.
erichkeane marked an inline comment as done.
erichkeane added a comment.
Rebased and did all the comments (including the www_status). @aaron.ballman :
Wasn't positive what you meant about the conversion functions, but I think I
got one? I would also love some bikeshedding on the documentation.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D64914/new/
https://reviews.llvm.org/D64914
Files:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/AST/Expr.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaStmt.cpp
clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
clang/test/Preprocessor/has_attribute.cpp
clang/www/cxx_status.html
Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -664,7 +664,7 @@
</tr>
<tr> <!-- from Cologne 2019 -->
<td><a href="http://wg21.link/p1771r1">P1771R1</a> (<a href="#dr">DR</a>)</td>
- <td class="none" align="center">No</td>
+ <td class="none" align="center">SVN</td>
</tr>
<tr>
<td><tt>[[maybe_unused]]</tt> attribute</td>
Index: clang/test/Preprocessor/has_attribute.cpp
===================================================================
--- clang/test/Preprocessor/has_attribute.cpp
+++ clang/test/Preprocessor/has_attribute.cpp
@@ -63,7 +63,7 @@
// CHECK: maybe_unused: 201603L
// ITANIUM: no_unique_address: 201803L
// WINDOWS: no_unique_address: 0
-// CHECK: nodiscard: 201603L
+// CHECK: nodiscard: 201907L
// CHECK: noreturn: 200809L
// FIXME(201803L) CHECK: unlikely: 0
Index: clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
+++ clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
@@ -80,6 +80,27 @@
conflicting_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: special reason}}
}
+namespace p1771 {
+ struct [[nodiscard]] ConvertTo{};
+ struct S {
+ [[nodiscard]] S();
+ S(int);
+ [[gnu::warn_unused_result]] S(double);
+ operator ConvertTo();
+ };
+
+ struct[[nodiscard]] Y{};
+
+ void usage() {
+ S(); // expected-warning {{ignoring temporary created by a constructor declared with 'nodiscard' attribute}}
+ S(1);
+ S(2.2);
+ Y(); // expected-warning {{expression result unused}}
+ S s;
+ (ConvertTo)s; // expected-warning {{expression result unused}}
+ }
+}; // namespace p1771
+
#ifdef EXT
// expected-warning@5 {{use of the 'nodiscard' attribute is a C++17 extension}}
// expected-warning@9 {{use of the 'nodiscard' attribute is a C++17 extension}}
@@ -91,4 +112,7 @@
// expected-warning@71 {{use of the 'nodiscard' attribute is a C++2a extension}}
// expected-warning@73 {{use of the 'nodiscard' attribute is a C++2a extension}}
// expected-warning@74 {{use of the 'nodiscard' attribute is a C++2a extension}}
+// expected-warning@84 {{use of the 'nodiscard' attribute is a C++17 extension}}
+// expected-warning@86 {{use of the 'nodiscard' attribute is a C++17 extension}}
+// expected-warning@92 {{use of the 'nodiscard' attribute is a C++17 extension}}
#endif
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -284,6 +284,13 @@
return;
}
}
+ } else if (const auto *CE = dyn_cast<CXXConstructExpr>(E)) {
+ if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
+ if (const auto *A = Ctor->getAttr<WarnUnusedResultAttr>()) {
+ Diag(Loc, diag::warn_unused_constructor) << A << R1 << R2;
+ return;
+ }
+ }
} else if (ShouldSuppress)
return;
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -2831,7 +2831,8 @@
static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->getFunctionType() &&
- D->getFunctionType()->getReturnType()->isVoidType()) {
+ D->getFunctionType()->getReturnType()->isVoidType() &&
+ !isa<CXXConstructorDecl>(D)) {
S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 0;
return;
}
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -2563,13 +2563,31 @@
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass: {
if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) {
- if (Type->hasAttr<WarnUnusedAttr>()) {
+ const auto *WarnURAttr = Type->getAttr<WarnUnusedResultAttr>();
+ if (Type->hasAttr<WarnUnusedAttr>() ||
+ (WarnURAttr && WarnURAttr->IsCXX11NoDiscard())) {
WarnE = this;
Loc = getBeginLoc();
R1 = getSourceRange();
return true;
}
}
+
+ const auto *CE = cast<CXXConstructExpr>(this);
+ if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
+ const auto *WarnURAttr = Ctor->getAttr<WarnUnusedResultAttr>();
+ if (WarnURAttr && WarnURAttr->IsCXX11NoDiscard()) {
+ WarnE = this;
+ Loc = getBeginLoc();
+ R1 = getSourceRange();
+
+ if (unsigned NumArgs = CE->getNumArgs())
+ R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
+ CE->getArg(NumArgs - 1)->getEndLoc());
+ return true;
+ }
+ }
+
return false;
}
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7430,6 +7430,9 @@
def warn_unused_call : Warning<
"ignoring return value of function declared with %0 attribute">,
InGroup<UnusedValue>;
+def warn_unused_constructor : Warning<
+ "ignoring temporary created by a constructor declared with %0 attribute">,
+ InGroup<UnusedValue>;
def warn_side_effects_unevaluated_context : Warning<
"expression with side effects has no effect in an unevaluated context">,
InGroup<UnevaluatedExpression>;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -1500,6 +1500,23 @@
}
error_info &foo();
void f() { foo(); } // Does not diagnose, error_info is a reference.
+
+Additionally, discarded temporaries resulting from a call to a constructor
+marked with ``[[nodiscard]]`` or a constructor of a type marked
+``[[nodiscard]]`` will also diagnose. This also applies to type conversions that
+use the annotated ``[[nodiscard]]`` constructor or result in an annotated type.
+
+.. code-block: c++
+ struct [[nodiscard]] marked_type {/*..*/ };
+ struct marked_ctor {
+ [[nodiscard]] marked_ctor();
+ marked_ctor(int);
+ };
+ void usages() {
+ marked_type(); // diagnoses.
+ marked_ctor(); // diagnoses.
+ marked_ctor(3); // Does not diagnose, int constructor isn't marked nodiscard.
+ }
}];
}
@@ -4201,4 +4218,4 @@
not initialized on device side. It has internal linkage and is initialized by
the initializer on host side.
}];
-}
\ No newline at end of file
+}
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -2335,12 +2335,19 @@
}
def WarnUnusedResult : InheritableAttr {
- let Spellings = [CXX11<"", "nodiscard", 201603>, C2x<"", "nodiscard">,
+ let Spellings = [CXX11<"", "nodiscard", 201907>, C2x<"", "nodiscard">,
CXX11<"clang", "warn_unused_result">,
GCC<"warn_unused_result">];
let Subjects = SubjectList<[ObjCMethod, Enum, Record, FunctionLike]>;
let Args = [StringArgument<"Message", 1>];
let Documentation = [WarnUnusedResultsDocs];
+ let AdditionalMembers = [{
+ // Check whether this the C++11 nodiscard version, even in non C++11
+ // spellings.
+ bool IsCXX11NoDiscard() const {
+ return this->getSemanticSpelling() == CXX11_nodiscard;
+ }
+ }];
}
def Weak : InheritableAttr {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits