Skip to content

Commit cb08f4a

Browse files
committed
Support warn_unused_result on typedefs
While it's not as robust as using the attribute on enums/classes (the type information may be lost through a function pointer, a declaration or use of the underlying type without using the typedef, etc) but I think there's still value in being able to attribute a typedef and have all return types written with that typedef pick up the warn_unused_result behavior. Specifically I'd like to be able to annotate LLVMErrorRef (a wrapper for llvm::Error used in the C API - the underlying type is a raw pointer, so it can't be attributed itself) to reduce the chance of unhandled errors. Differential Revision: https://reviews.llvm.org/D102122
1 parent dbead23 commit cb08f4a

File tree

11 files changed

+61
-5
lines changed

11 files changed

+61
-5
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2944,7 +2944,7 @@ def WarnUnusedResult : InheritableAttr {
29442944
C2x<"", "nodiscard", 201904>,
29452945
CXX11<"clang", "warn_unused_result">,
29462946
GCC<"warn_unused_result">];
2947-
let Subjects = SubjectList<[ObjCMethod, Enum, Record, FunctionLike]>;
2947+
let Subjects = SubjectList<[ObjCMethod, Enum, Record, FunctionLike, TypedefName]>;
29482948
let Args = [StringArgument<"Message", 1>];
29492949
let Documentation = [WarnUnusedResultsDocs];
29502950
let AdditionalMembers = [{

clang/include/clang/Basic/AttributeCommonInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ class AttributeCommonInfo {
146146
bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
147147

148148
bool isGNUScope() const;
149+
bool isClangScope() const;
149150

150151
bool isAlignasAttribute() const {
151152
// FIXME: Use a better mechanism to determine this.
@@ -164,6 +165,8 @@ class AttributeCommonInfo {
164165
return isCXX11Attribute() || isC2xAttribute();
165166
}
166167

168+
bool isGNUAttribute() const { return SyntaxUsed == AS_GNU; }
169+
167170
bool isKeywordAttribute() const {
168171
return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
169172
}

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8734,6 +8734,10 @@ def warn_unused_result : Warning<
87348734
def warn_unused_result_msg : Warning<
87358735
"ignoring return value of function declared with %0 attribute: %1">,
87368736
InGroup<UnusedResult>;
8737+
def warn_unused_result_typedef_unsupported_spelling : Warning<
8738+
"'[[%select{nodiscard|gnu::warn_unused_result}0]]' attribute ignored when "
8739+
"applied to a typedef; consider using '__attribute__((warn_unused_result))' "
8740+
"or '[[clang::warn_unused_result]]' instead">, InGroup<IgnoredAttributes>;
87378741
def warn_unused_volatile : Warning<
87388742
"expression result unused; assign into a variable to force a volatile load">,
87398743
InGroup<DiagGroup<"unused-volatile-lvalue">>;

clang/lib/AST/Expr.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,6 +1522,11 @@ const Attr *CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const {
15221522
if (const auto *A = TD->getAttr<WarnUnusedResultAttr>())
15231523
return A;
15241524

1525+
for (const auto *TD = getCallReturnType(Ctx)->getAs<TypedefType>(); TD;
1526+
TD = TD->desugar()->getAs<TypedefType>())
1527+
if (const auto *A = TD->getDecl()->getAttr<WarnUnusedResultAttr>())
1528+
return A;
1529+
15251530
// Otherwise, see if the callee is marked nodiscard and return that attribute
15261531
// instead.
15271532
const Decl *D = getCalleeDecl();

clang/lib/Basic/Attributes.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ bool AttributeCommonInfo::isGNUScope() const {
8585
return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__"));
8686
}
8787

88+
bool AttributeCommonInfo::isClangScope() const {
89+
return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang"));
90+
}
91+
8892
#include "clang/Sema/AttrParsedAttrKinds.inc"
8993

9094
static SmallString<64> normalizeName(const IdentifierInfo *Name,

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3156,6 +3156,14 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
31563156
S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
31573157
}
31583158

3159+
if ((!AL.isGNUAttribute() &&
3160+
!(AL.isStandardAttributeSyntax() && AL.isClangScope())) &&
3161+
isa<TypedefNameDecl>(D)) {
3162+
S.Diag(AL.getLoc(), diag::warn_unused_result_typedef_unsupported_spelling)
3163+
<< AL.isGNUScope();
3164+
return;
3165+
}
3166+
31593167
D->addAttr(::new (S.Context) WarnUnusedResultAttr(S.Context, AL, Str));
31603168
}
31613169

clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p1.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ struct [[nodiscard("Wrong")]] S3 {};
77
[[nodiscard]] int f();
88
enum [[nodiscard]] E {};
99

10-
namespace [[nodiscard]] N {} // expected-warning {{'nodiscard' attribute only applies to Objective-C methods, enums, structs, unions, classes, functions, and function pointers}}
10+
namespace [[nodiscard]] N {} // expected-warning {{'nodiscard' attribute only applies to Objective-C methods, enums, structs, unions, classes, functions, function pointers, and typedefs}}

clang/test/Misc/pragma-attribute-supported-attributes-list.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@
185185
// CHECK-NEXT: VecReturn (SubjectMatchRule_record)
186186
// CHECK-NEXT: VecTypeHint (SubjectMatchRule_function)
187187
// CHECK-NEXT: WarnUnused (SubjectMatchRule_record)
188-
// CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, SubjectMatchRule_enum, SubjectMatchRule_record, SubjectMatchRule_hasType_functionType)
188+
// CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, SubjectMatchRule_enum, SubjectMatchRule_record, SubjectMatchRule_hasType_functionType, SubjectMatchRule_type_alias)
189189
// CHECK-NEXT: Weak (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record)
190190
// CHECK-NEXT: WeakRef (SubjectMatchRule_variable, SubjectMatchRule_function)
191191
// CHECK-NEXT: WebAssemblyExportName (SubjectMatchRule_function)

clang/test/Sema/c2x-nodiscard.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct S3 get_s3(void);
1515
[[nodiscard]] int f1(void);
1616
enum [[nodiscard]] E1 { One };
1717

18-
[[nodiscard]] int i; // expected-warning {{'nodiscard' attribute only applies to Objective-C methods, enums, structs, unions, classes, functions, and function pointers}}
18+
[[nodiscard]] int i; // expected-warning {{'nodiscard' attribute only applies to Objective-C methods, enums, structs, unions, classes, functions, function pointers, and typedefs}}
1919

2020
struct [[nodiscard]] S4 {
2121
int i;

clang/test/Sema/unused-expr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ int t6(void) {
9696
return 0;
9797
}
9898

99-
int t7 __attribute__ ((warn_unused_result)); // expected-warning {{'warn_unused_result' attribute only applies to Objective-C methods, enums, structs, unions, classes, functions, and function pointers}}
99+
int t7 __attribute__ ((warn_unused_result)); // expected-warning {{'warn_unused_result' attribute only applies to Objective-C methods, enums, structs, unions, classes, functions, function pointers, and typedefs}}
100100

101101
// PR4010
102102
int (*fn4)(void) __attribute__ ((warn_unused_result));

0 commit comments

Comments
 (0)