2 * Compile-time checks associated with the @mustuse attribute.
4 * Copyright: Copyright (C) 2022-2024 by The D Language Foundation, All Rights Reserved
5 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
6 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d, _mustuse.d)
7 * Documentation: https://dlang.org/phobos/dmd_mustuse.html
8 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mustuse.d
16 import dmd
.expression
;
18 import dmd
.identifier
;
22 * Check whether discarding an expression would violate the requirements of
23 * @mustuse. If so, emit an error.
26 * e = the expression to check
27 * sc = scope in which `e` was semantically analyzed
29 * Returns: true on error, false on success.
31 bool checkMustUse(Expression e
, Scope
* sc
)
34 import dmd
.typesem
: toDsymbol
;
37 if (auto sym
= e
.type
.toDsymbol(sc
))
39 auto sd
= sym
.isStructDeclaration();
40 // isStructDeclaration returns non-null for both structs and unions
41 if (sd
&& hasMustUseAttribute(sd
, sc
) && !isAssignment(e
) && !isIncrementOrDecrement(e
))
43 error(e
.loc
, "ignored value of `@%s` type `%s`; prepend a `cast(void)` if intentional",
44 Id
.udaMustUse
.toChars(), e
.type
.toPrettyChars(true));
52 * Called from a symbol's semantic to check for reserved usage of @mustuse.
54 * If such usage is found, emits an errror.
57 * sym = symbol to check
59 void checkMustUseReserved(Dsymbol sym
)
61 import dmd
.attrib
: foreachUdaNoSemantic
;
62 import dmd
.errors
: error
;
65 // Can't use foreachUda (and by extension hasMustUseAttribute) while
66 // semantic analysis of `sym` is still in progress
67 foreachUdaNoSemantic(sym
, (exp
) {
68 if (isMustUseAttribute(exp
))
70 if (sym
.isFuncDeclaration())
72 error(sym
.loc
, "`@%s` on functions is reserved for future use",
73 Id
.udaMustUse
.toChars());
76 else if (sym
.isClassDeclaration() || sym
.isEnumDeclaration())
78 error(sym
.loc
, "`@%s` on `%s` types is reserved for future use",
79 Id
.udaMustUse
.toChars(), sym
.kind());
88 * Returns: true if the given expression is an assignment, either simple (a = b)
89 * or compound (a += b, etc).
91 private bool isAssignment(Expression e
)
93 if (e
.isAssignExp || e
.isBinAssignExp || e
.isConstructExp || e
.isBlitExp
)
95 if (auto ce
= e
.isCallExp())
100 if (id
&& isAssignmentOpId(id
))
108 * Returns: true if id is the identifier of an assignment operator overload.
110 private bool isAssignmentOpId(Identifier id
)
114 return id
== Id
.assign
130 || id
== Id
.opOpAssign
131 || id
== Id
.opIndexOpAssign
132 || id
== Id
.opSliceOpAssign
137 * Returns: true if the given expression is an increment (++) or decrement (--).
139 private bool isIncrementOrDecrement(Expression e
)
141 import dmd
.dtemplate
: isExpression
;
144 import dmd
.tokens
: EXP
;
146 if (e
.op
== EXP
.plusPlus
147 || e
.op
== EXP
.minusMinus
148 || e
.op
== EXP
.prePlusPlus
149 || e
.op
== EXP
.preMinusMinus
)
151 if (auto call = e
.isCallExp())
153 // Check for overloaded preincrement
154 // e.g., a.opUnary!"++"
155 if (auto fd
= call.f
)
157 if (fd
.ident
== Id
.opUnary
&& fd
.parent
)
159 if (auto ti
= fd
.parent
.isTemplateInstance())
161 auto tiargs
= ti
.tiargs
;
162 if (tiargs
&& tiargs
.length
>= 1)
164 if (auto argExp
= (*tiargs
)[0].isExpression())
166 if (auto op
= argExp
.isStringExp())
168 if (op
.len
== 2 && op
.sz
== 1)
170 const s
= op
.peekString();
171 if (s
== "++" || s
== "--")
181 else if (auto comma
= e
.isCommaExp())
183 // Check for overloaded postincrement
184 // e.g., (auto tmp = a, ++a, tmp)
187 if (auto left
= comma
.e1
.isCommaExp())
189 if (auto middle
= left
.e2
)
191 if (middle
&& isIncrementOrDecrement(middle
))
201 * Returns: true if the given symbol has the @mustuse attribute.
203 private bool hasMustUseAttribute(Dsymbol sym
, Scope
* sc
)
205 import dmd
.attrib
: foreachUda
;
209 foreachUda(sym
, sc
, (Expression uda
) {
210 if (isMustUseAttribute(uda
))
215 return 0; // continue
222 * Returns: true if the given expression is core.attribute.mustuse.
224 private bool isMustUseAttribute(Expression e
)
226 import dmd
.attrib
: isEnumAttribute
;
228 return isEnumAttribute(e
, Id
.udaMustUse
);