LoongArch: Organize the code related to split move and merge the same functions.
[official-gcc.git] / gcc / d / dmd / mustuse.d
blobc2fa5fbd02370633d0da86b517a3143b09b583ee
1 /**
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
9 */
11 module dmd.mustuse;
13 import dmd.dscope;
14 import dmd.dsymbol;
15 import dmd.errors;
16 import dmd.expression;
17 import dmd.globals;
18 import dmd.identifier;
19 import dmd.location;
21 /**
22 * Check whether discarding an expression would violate the requirements of
23 * @mustuse. If so, emit an error.
25 * Params:
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)
33 import dmd.id : Id;
34 import dmd.typesem : toDsymbol;
36 assert(e.type);
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));
45 return true;
48 return false;
51 /**
52 * Called from a symbol's semantic to check for reserved usage of @mustuse.
54 * If such usage is found, emits an errror.
56 * Params:
57 * sym = symbol to check
59 void checkMustUseReserved(Dsymbol sym)
61 import dmd.attrib : foreachUdaNoSemantic;
62 import dmd.errors : error;
63 import dmd.id : Id;
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());
74 sym.errors = true;
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());
80 sym.errors = true;
83 return 0; // continue
84 });
87 /**
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)
94 return true;
95 if (auto ce = e.isCallExp())
97 if (auto fd = ce.f)
99 auto id = fd.ident;
100 if (id && isAssignmentOpId(id))
101 return true;
104 return false;
108 * Returns: true if id is the identifier of an assignment operator overload.
110 private bool isAssignmentOpId(Identifier id)
112 import dmd.id : Id;
114 return id == Id.assign
115 || id == Id.addass
116 || id == Id.subass
117 || id == Id.mulass
118 || id == Id.divass
119 || id == Id.modass
120 || id == Id.andass
121 || id == Id.orass
122 || id == Id.xorass
123 || id == Id.shlass
124 || id == Id.shrass
125 || id == Id.ushrass
126 || id == Id.catass
127 || id == Id.indexass
128 || id == Id.slice
129 || id == Id.sliceass
130 || id == Id.opOpAssign
131 || id == Id.opIndexOpAssign
132 || id == Id.opSliceOpAssign
133 || id == Id.powass;
137 * Returns: true if the given expression is an increment (++) or decrement (--).
139 private bool isIncrementOrDecrement(Expression e)
141 import dmd.dtemplate : isExpression;
142 import dmd.location;
143 import dmd.id : Id;
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)
150 return true;
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 == "--")
172 return true;
181 else if (auto comma = e.isCommaExp())
183 // Check for overloaded postincrement
184 // e.g., (auto tmp = a, ++a, tmp)
185 if (comma.e1)
187 if (auto left = comma.e1.isCommaExp())
189 if (auto middle = left.e2)
191 if (middle && isIncrementOrDecrement(middle))
192 return true;
197 return false;
201 * Returns: true if the given symbol has the @mustuse attribute.
203 private bool hasMustUseAttribute(Dsymbol sym, Scope* sc)
205 import dmd.attrib : foreachUda;
207 bool result = false;
209 foreachUda(sym, sc, (Expression uda) {
210 if (isMustUseAttribute(uda))
212 result = true;
213 return 1; // break
215 return 0; // continue
218 return result;
222 * Returns: true if the given expression is core.attribute.mustuse.
224 private bool isMustUseAttribute(Expression e)
226 import dmd.attrib : isEnumAttribute;
227 import dmd.id : Id;
228 return isEnumAttribute(e, Id.udaMustUse);