From: Aaron Ballman Date: Sat, 20 Jul 2019 07:56:34 +0000 (+0000) Subject: Implement P1301R4, which allows specifying an optional message on the [[nodiscard... X-Git-Tag: llvmorg-11-init~13932 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3bef014e7d79b7aa58d968fd24e20669ac63d956;p=platform%2Fupstream%2Fllvm.git Implement P1301R4, which allows specifying an optional message on the [[nodiscard]] attribute. This also bumps the attribute feature test value and introduces the notion of a C++2a extension warning. llvm-svn: 366626 --- diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index d39b16e..7d8dbb1 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2335,10 +2335,11 @@ def WarnUnused : InheritableAttr { } 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]; } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index fac6116..7fc7a1d 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1482,6 +1482,13 @@ generated when a function or its return type is marked with ``[[nodiscard]]`` potentially-evaluated discarded-value expression that is not explicitly cast to `void`. +A string literal may optionally be provided to the attribute, which will be +reproduced in any resulting diagnostics. Redeclarations using different forms +of the attribute (with or without the string literal or with different string +literal contents) are allowed. If there are redeclarations of the entity with +differing string literals, it is unspecified which one will be used by Clang +in any resulting diagnostics. + .. code-block: c++ struct [[nodiscard]] error_info { /*...*/ }; error_info enable_missile_safety_mode(); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 04ac4be..b093b83 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7436,6 +7436,9 @@ def warn_side_effects_typeid : Warning< def warn_unused_result : Warning< "ignoring return value of function declared with %0 attribute">, InGroup; +def warn_unused_result_msg : Warning< + "ignoring return value of function declared with %0 attribute: %1">, + InGroup; def warn_unused_volatile : Warning< "expression result unused; assign into a variable to force a volatile load">, InGroup>; @@ -7444,6 +7447,8 @@ def ext_cxx14_attr : Extension< "use of the %0 attribute is a C++14 extension">, InGroup; def ext_cxx17_attr : Extension< "use of the %0 attribute is a C++17 extension">, InGroup; +def ext_cxx2a_attr : Extension< + "use of the %0 attribute is a C++2a extension">, InGroup; def warn_unused_comparison : Warning< "%select{equality|inequality|relational|three-way}0 comparison result unused">, diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 5f0b369..d800f79 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2841,14 +2841,30 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - // If this is spelled as the standard C++17 attribute, but not in C++17, warn - // about using it as an extension. - if (!S.getLangOpts().CPlusPlus17 && AL.isCXX11Attribute() && - !AL.getScopeName()) - S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL; + StringRef Str; + if ((AL.isCXX11Attribute() || AL.isC2xAttribute()) && !AL.getScopeName()) { + // If this is spelled as the standard C++17 attribute, but not in C++17, + // warn about using it as an extension. If there are attribute arguments, + // then claim it's a C++2a extension instead. + // FIXME: If WG14 does not seem likely to adopt the same feature, add an + // extension warning for C2x mode. + const LangOptions &LO = S.getLangOpts(); + if (AL.getNumArgs() == 1) { + if (LO.CPlusPlus && !LO.CPlusPlus2a) + S.Diag(AL.getLoc(), diag::ext_cxx2a_attr) << AL; + + // Since this this is spelled [[nodiscard]], get the optional string + // literal. If in C++ mode, but not in C++2a mode, diagnose as an + // extension. + // FIXME: C2x should support this feature as well, even as an extension. + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, nullptr)) + return; + } else if (LO.CPlusPlus && !LO.CPlusPlus17) + S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL; + } D->addAttr(::new (S.Context) - WarnUnusedResultAttr(AL.getRange(), S.Context, + WarnUnusedResultAttr(AL.getRange(), S.Context, Str, AL.getAttributeSpellingListIndex())); } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 480155d..3400f7d 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -258,8 +258,13 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (E->getType()->isVoidType()) return; - if (const Attr *A = CE->getUnusedResultAttr(Context)) { - Diag(Loc, diag::warn_unused_result) << A << R1 << R2; + if (const auto *A = cast_or_null( + CE->getUnusedResultAttr(Context))) { + StringRef Msg = A->getMessage(); + if (!Msg.empty()) + Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2; + else + Diag(Loc, diag::warn_unused_result) << A << R1 << R2; return; } @@ -290,7 +295,11 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD) { if (const auto *A = MD->getAttr()) { - Diag(Loc, diag::warn_unused_result) << A << R1 << R2; + StringRef Msg = A->getMessage(); + if (!Msg.empty()) + Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2; + else + Diag(Loc, diag::warn_unused_result) << A << R1 << R2; return; } } diff --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p1.cpp index 4425416..4591195 100644 --- a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p1.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p1.cpp @@ -1,8 +1,8 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++1z -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++2a -verify %s struct [[nodiscard]] S1 {}; // ok struct [[nodiscard nodiscard]] S2 {}; // expected-error {{attribute 'nodiscard' cannot appear multiple times in an attribute specifier}} -struct [[nodiscard("Wrong")]] S3 {}; // expected-error {{'nodiscard' cannot have an argument list}} +struct [[nodiscard("Wrong")]] S3 {}; [[nodiscard]] int f(); enum [[nodiscard]] E {}; diff --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp index 43de934..9b87608 100644 --- a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp @@ -1,5 +1,6 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++2a -verify -Wc++2a-extensions %s // RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify -Wc++17-extensions %s -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -DEXT -Wc++17-extensions %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -DEXT -Wc++17-extensions -Wc++2a-extensions %s struct [[nodiscard]] S {}; S get_s(); @@ -61,10 +62,33 @@ void f() { } } // namespace PR31526 +struct [[nodiscard("reason")]] ReasonStruct {}; +struct LaterReason; +struct [[nodiscard("later reason")]] LaterReason {}; + +ReasonStruct get_reason(); +LaterReason get_later_reason(); +[[nodiscard("another reason")]] int another_reason(); + +[[nodiscard("conflicting reason")]] int conflicting_reason(); +[[nodiscard("special reason")]] int conflicting_reason(); + +void cxx2a_use() { + get_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: reason}} + get_later_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: later reason}} + another_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: another reason}} + conflicting_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: special reason}} +} + #ifdef EXT -// expected-warning@4 {{use of the 'nodiscard' attribute is a C++17 extension}} -// expected-warning@8 {{use of the 'nodiscard' attribute is a C++17 extension}} -// expected-warning@11 {{use of the 'nodiscard' attribute is a C++17 extension}} +// 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}} // expected-warning@12 {{use of the 'nodiscard' attribute is a C++17 extension}} -// expected-warning@28 {{use of the 'nodiscard' attribute is a C++17 extension}} +// expected-warning@13 {{use of the 'nodiscard' attribute is a C++17 extension}} +// expected-warning@29 {{use of the 'nodiscard' attribute is a C++17 extension}} +// expected-warning@65 {{use of the 'nodiscard' attribute is a C++2a extension}} +// expected-warning@67 {{use of the 'nodiscard' attribute is a C++2a extension}} +// 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}} #endif diff --git a/clang/test/Preprocessor/has_attribute.cpp b/clang/test/Preprocessor/has_attribute.cpp index d35b673..83ee0e3 100644 --- a/clang/test/Preprocessor/has_attribute.cpp +++ b/clang/test/Preprocessor/has_attribute.cpp @@ -63,7 +63,7 @@ CXX11(unlikely) // 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 diff --git a/clang/test/Sema/c2x-nodiscard.c b/clang/test/Sema/c2x-nodiscard.c index 5eaeda4..cf1f081 100644 --- a/clang/test/Sema/c2x-nodiscard.c +++ b/clang/test/Sema/c2x-nodiscard.c @@ -6,10 +6,12 @@ struct [[nodiscard]] S1 { // ok struct [[nodiscard nodiscard]] S2 { // expected-error {{attribute 'nodiscard' cannot appear multiple times in an attribute specifier}} int i; }; -struct [[nodiscard("Wrong")]] S3 { // expected-error {{'nodiscard' cannot have an argument list}} +struct [[nodiscard("Wrong")]] S3 { // FIXME: may need an extension warning. int i; }; +struct S3 get_s3(void); + [[nodiscard]] int f1(void); enum [[nodiscard]] E1 { One }; @@ -27,11 +29,13 @@ enum E2 get_e(void); void f2(void) { get_s(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + get_s3(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: Wrong}} get_i(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} get_e(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} // Okay, warnings are not encouraged (void)get_s(); + (void)get_s3(); (void)get_i(); (void)get_e(); } diff --git a/clang/test/SemaCXX/cxx11-attr-print.cpp b/clang/test/SemaCXX/cxx11-attr-print.cpp index 12b4175..e7c00b7 100644 --- a/clang/test/SemaCXX/cxx11-attr-print.cpp +++ b/clang/test/SemaCXX/cxx11-attr-print.cpp @@ -37,13 +37,15 @@ void foo() __attribute__((const)); // CHECK: void bar() __attribute__((__const)); void bar() __attribute__((__const)); -// CHECK: int f1() __attribute__((warn_unused_result)); +// FIXME: It's unfortunate that the string literal prints with the below three +// cases given that the string is only exposed via the [[nodiscard]] spelling. +// CHECK: int f1() __attribute__((warn_unused_result(""))); int f1() __attribute__((warn_unused_result)); -// CHECK: {{\[}}[clang::warn_unused_result]]; +// CHECK: {{\[}}[clang::warn_unused_result("")]]; int f2 [[clang::warn_unused_result]] (); -// CHECK: {{\[}}[gnu::warn_unused_result]]; +// CHECK: {{\[}}[gnu::warn_unused_result("")]]; int f3 [[gnu::warn_unused_result]] (); // FIXME: ast-print need to print C++11