2 * Compile-time checks associated with the @mustuse attribute.
4 * Copyright: Copyright (C) 2022-2023 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
;
21 // Used in isIncrementOrDecrement
22 private const StringExp plusPlus
, minusMinus
;
24 // Loc.initial cannot be used in static initializers, so
25 // these need a static constructor.
28 plusPlus
= new StringExp(Loc
.initial
, "++");
29 minusMinus
= new StringExp(Loc
.initial
, "--");
33 * Check whether discarding an expression would violate the requirements of
34 * @mustuse. If so, emit an error.
37 * e = the expression to check
38 * sc = scope in which `e` was semantically analyzed
40 * Returns: true on error, false on success.
42 bool checkMustUse(Expression e
, Scope
* sc
)
47 if (auto sym
= e
.type
.toDsymbol(sc
))
49 auto sd
= sym
.isStructDeclaration();
50 // isStructDeclaration returns non-null for both structs and unions
51 if (sd
&& hasMustUseAttribute(sd
, sc
) && !isAssignment(e
) && !isIncrementOrDecrement(e
))
53 error(e
.loc
, "ignored value of `@%s` type `%s`; prepend a `cast(void)` if intentional",
54 Id
.udaMustUse
.toChars(), e
.type
.toPrettyChars(true));
62 * Called from a symbol's semantic to check for reserved usage of @mustuse.
64 * If such usage is found, emits an errror.
67 * sym = symbol to check
69 void checkMustUseReserved(Dsymbol sym
)
71 import dmd
.attrib
: foreachUdaNoSemantic
;
72 import dmd
.errors
: error
;
75 // Can't use foreachUda (and by extension hasMustUseAttribute) while
76 // semantic analysis of `sym` is still in progress
77 foreachUdaNoSemantic(sym
, (exp
) {
78 if (isMustUseAttribute(exp
))
80 if (sym
.isFuncDeclaration())
82 error(sym
.loc
, "`@%s` on functions is reserved for future use",
83 Id
.udaMustUse
.toChars());
86 else if (sym
.isClassDeclaration() || sym
.isEnumDeclaration())
88 error(sym
.loc
, "`@%s` on `%s` types is reserved for future use",
89 Id
.udaMustUse
.toChars(), sym
.kind());
98 * Returns: true if the given expression is an assignment, either simple (a = b)
99 * or compound (a += b, etc).
101 private bool isAssignment(Expression e
)
103 if (e
.isAssignExp || e
.isBinAssignExp || e
.isConstructExp || e
.isBlitExp
)
105 if (auto ce
= e
.isCallExp())
110 if (id
&& isAssignmentOpId(id
))
118 * Returns: true if id is the identifier of an assignment operator overload.
120 private bool isAssignmentOpId(Identifier id
)
124 return id
== Id
.assign
140 || id
== Id
.opOpAssign
141 || id
== Id
.opIndexOpAssign
142 || id
== Id
.opSliceOpAssign
147 * Returns: true if the given expression is an increment (++) or decrement (--).
149 private bool isIncrementOrDecrement(Expression e
)
151 import dmd
.dtemplate
: isExpression
;
154 import dmd
.tokens
: EXP
;
156 if (e
.op
== EXP
.plusPlus
157 || e
.op
== EXP
.minusMinus
158 || e
.op
== EXP
.prePlusPlus
159 || e
.op
== EXP
.preMinusMinus
)
161 if (auto call = e
.isCallExp())
163 // Check for overloaded preincrement
164 // e.g., a.opUnary!"++"
165 if (auto fd
= call.f
)
167 if (fd
.ident
== Id
.opUnary
&& fd
.parent
)
169 if (auto ti
= fd
.parent
.isTemplateInstance())
171 auto tiargs
= ti
.tiargs
;
172 if (tiargs
&& tiargs
.length
>= 1)
174 if (auto argExp
= (*tiargs
)[0].isExpression())
176 auto op
= argExp
.isStringExp();
177 if (op
&& (op
.compare(plusPlus
) == 0 || op
.compare(minusMinus
) == 0))
185 else if (auto comma
= e
.isCommaExp())
187 // Check for overloaded postincrement
188 // e.g., (auto tmp = a, ++a, tmp)
191 if (auto left
= comma
.e1
.isCommaExp())
193 if (auto middle
= left
.e2
)
195 if (middle
&& isIncrementOrDecrement(middle
))
205 * Returns: true if the given symbol has the @mustuse attribute.
207 private bool hasMustUseAttribute(Dsymbol sym
, Scope
* sc
)
209 import dmd
.attrib
: foreachUda
;
213 foreachUda(sym
, sc
, (Expression uda
) {
214 if (isMustUseAttribute(uda
))
219 return 0; // continue
226 * Returns: true if the given expression is core.attribute.mustuse.
228 private bool isMustUseAttribute(Expression e
)
230 import dmd
.attrib
: isCoreUda
;
233 // Logic based on dmd.objc.Supported.declaredAsOptionalCount
234 auto typeExp
= e
.isTypeExp
;
238 auto typeEnum
= typeExp
.type
.isTypeEnum();
242 if (isCoreUda(typeEnum
.sym
, Id
.udaMustUse
))