1 
2 /* Compiler implementation of the D programming language
3  * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4  * written by Walter Bright
5  * http://www.digitalmars.com
6  * Distributed under the Boost Software License, Version 1.0.
7  * http://www.boost.org/LICENSE_1_0.txt
8  * https://github.com/D-Programming-Language/dmd/blob/master/src/cond.c
9  */
10 
11 #include "root/dsystem.h"               // strcmp()
12 
13 #include "mars.h"
14 #include "id.h"
15 #include "init.h"
16 #include "declaration.h"
17 #include "identifier.h"
18 #include "expression.h"
19 #include "cond.h"
20 #include "module.h"
21 #include "template.h"
22 #include "mtype.h"
23 #include "scope.h"
24 #include "arraytypes.h"
25 #include "tokens.h"
26 
27 Expression *semantic(Expression *e, Scope *sc);
28 bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
29 
findCondition(Strings * ids,Identifier * ident)30 int findCondition(Strings *ids, Identifier *ident)
31 {
32     if (ids)
33     {
34         for (size_t i = 0; i < ids->dim; i++)
35         {
36             const char *id = (*ids)[i];
37 
38             if (strcmp(id, ident->toChars()) == 0)
39                 return true;
40         }
41     }
42 
43     return false;
44 }
45 
46 /* ============================================================ */
47 
Condition(Loc loc)48 Condition::Condition(Loc loc)
49 {
50     this->loc = loc;
51     inc = 0;
52 }
53 
54 /* ============================================================ */
55 
DVCondition(Module * mod,unsigned level,Identifier * ident)56 DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
57         : Condition(Loc())
58 {
59     this->mod = mod;
60     this->level = level;
61     this->ident = ident;
62 }
63 
syntaxCopy()64 Condition *DVCondition::syntaxCopy()
65 {
66     return this;        // don't need to copy
67 }
68 
69 /* ============================================================ */
70 
setGlobalLevel(unsigned level)71 void DebugCondition::setGlobalLevel(unsigned level)
72 {
73     global.params.debuglevel = level;
74 }
75 
addGlobalIdent(const char * ident)76 void DebugCondition::addGlobalIdent(const char *ident)
77 {
78     if (!global.params.debugids)
79         global.params.debugids = new Strings();
80     global.params.debugids->push(ident);
81 }
82 
83 
DebugCondition(Module * mod,unsigned level,Identifier * ident)84 DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
85     : DVCondition(mod, level, ident)
86 {
87 }
88 
89 // Helper for printing dependency information
printDepsConditional(Scope * sc,DVCondition * condition,const char * depType)90 void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType)
91 {
92     if (!global.params.moduleDeps || global.params.moduleDepsFile)
93         return;
94     OutBuffer *ob = global.params.moduleDeps;
95     Module* imod = sc ? sc->instantiatingModule() : condition->mod;
96     if (!imod)
97         return;
98     ob->writestring(depType);
99     ob->writestring(imod->toPrettyChars());
100     ob->writestring(" (");
101     escapePath(ob, imod->srcfile->toChars());
102     ob->writestring(") : ");
103     if (condition->ident)
104         ob->printf("%s\n", condition->ident->toChars());
105     else
106         ob->printf("%d\n", condition->level);
107 }
108 
109 
include(Scope * sc,ScopeDsymbol *)110 int DebugCondition::include(Scope *sc, ScopeDsymbol *)
111 {
112     //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
113     if (inc == 0)
114     {
115         inc = 2;
116         bool definedInModule = false;
117         if (ident)
118         {
119             if (findCondition(mod->debugids, ident))
120             {
121                 inc = 1;
122                 definedInModule = true;
123             }
124             else if (findCondition(global.params.debugids, ident))
125                 inc = 1;
126             else
127             {   if (!mod->debugidsNot)
128                     mod->debugidsNot = new Strings();
129                 mod->debugidsNot->push(ident->toChars());
130             }
131         }
132         else if (level <= global.params.debuglevel || level <= mod->debuglevel)
133             inc = 1;
134         if (!definedInModule)
135             printDepsConditional(sc, this, "depsDebug ");
136     }
137     return (inc == 1);
138 }
139 
140 /* ============================================================ */
141 
setGlobalLevel(unsigned level)142 void VersionCondition::setGlobalLevel(unsigned level)
143 {
144     global.params.versionlevel = level;
145 }
146 
isReserved(const char * ident)147 static bool isReserved(const char *ident)
148 {
149     static const char* reserved[] =
150     {
151         "DigitalMars",
152         "GNU",
153         "LDC",
154         "SDC",
155         "Windows",
156         "Win32",
157         "Win64",
158         "linux",
159         "OSX",
160         "FreeBSD",
161         "OpenBSD",
162         "NetBSD",
163         "DragonFlyBSD",
164         "BSD",
165         "Solaris",
166         "Posix",
167         "AIX",
168         "Haiku",
169         "SkyOS",
170         "SysV3",
171         "SysV4",
172         "Hurd",
173         "Android",
174         "PlayStation",
175         "PlayStation4",
176         "Cygwin",
177         "MinGW",
178         "FreeStanding",
179         "X86",
180         "X86_64",
181         "ARM",
182         "ARM_Thumb",
183         "ARM_SoftFloat",
184         "ARM_SoftFP",
185         "ARM_HardFloat",
186         "AArch64",
187         "Epiphany",
188         "PPC",
189         "PPC_SoftFloat",
190         "PPC_HardFloat",
191         "PPC64",
192         "IA64",
193         "MIPS32",
194         "MIPS64",
195         "MIPS_O32",
196         "MIPS_N32",
197         "MIPS_O64",
198         "MIPS_N64",
199         "MIPS_EABI",
200         "MIPS_SoftFloat",
201         "MIPS_HardFloat",
202         "MSP430",
203         "NVPTX",
204         "NVPTX64",
205         "RISCV32",
206         "RISCV64",
207         "SPARC",
208         "SPARC_V8Plus",
209         "SPARC_SoftFloat",
210         "SPARC_HardFloat",
211         "SPARC64",
212         "S390",
213         "S390X",
214         "HPPA",
215         "HPPA64",
216         "SH",
217         "Alpha",
218         "Alpha_SoftFloat",
219         "Alpha_HardFloat",
220         "LittleEndian",
221         "BigEndian",
222         "ELFv1",
223         "ELFv2",
224         "CRuntime_Digitalmars",
225         "CRuntime_Glibc",
226         "CRuntime_Microsoft",
227         "CRuntime_Musl",
228         "CRuntime_UClibc",
229         "CppRuntime_Clang",
230         "CppRuntime_DigitalMars",
231         "CppRuntime_Gcc",
232         "CppRuntime_Microsoft",
233         "CppRuntime_Sun",
234         "D_Coverage",
235         "D_Ddoc",
236         "D_InlineAsm_X86",
237         "D_InlineAsm_X86_64",
238         "D_LP64",
239         "D_X32",
240         "D_HardFloat",
241         "D_SoftFloat",
242         "D_PIC",
243         "D_SIMD",
244         "D_Version2",
245         "D_NoBoundsChecks",
246         "unittest",
247         "assert",
248         "all",
249         "none",
250         NULL
251     };
252 
253     for (unsigned i = 0; reserved[i]; i++)
254     {
255         if (strcmp(ident, reserved[i]) == 0)
256             return true;
257     }
258 
259     if (ident[0] == 'D' && ident[1] == '_')
260         return true;
261     return false;
262 }
263 
checkReserved(Loc loc,const char * ident)264 void checkReserved(Loc loc, const char *ident)
265 {
266     if (isReserved(ident))
267         error(loc, "version identifier '%s' is reserved and cannot be set", ident);
268 }
269 
addGlobalIdent(const char * ident)270 void VersionCondition::addGlobalIdent(const char *ident)
271 {
272     checkReserved(Loc(), ident);
273     addPredefinedGlobalIdent(ident);
274 }
275 
addPredefinedGlobalIdent(const char * ident)276 void VersionCondition::addPredefinedGlobalIdent(const char *ident)
277 {
278     if (!global.params.versionids)
279         global.params.versionids = new Strings();
280     global.params.versionids->push(ident);
281 }
282 
283 
VersionCondition(Module * mod,unsigned level,Identifier * ident)284 VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
285     : DVCondition(mod, level, ident)
286 {
287 }
288 
include(Scope * sc,ScopeDsymbol *)289 int VersionCondition::include(Scope *sc, ScopeDsymbol *)
290 {
291     //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
292     //if (ident) printf("\tident = '%s'\n", ident->toChars());
293     if (inc == 0)
294     {
295         inc = 2;
296         bool definedInModule=false;
297         if (ident)
298         {
299             if (findCondition(mod->versionids, ident))
300             {
301                 inc = 1;
302                 definedInModule = true;
303             }
304             else if (findCondition(global.params.versionids, ident))
305                 inc = 1;
306             else
307             {
308                 if (!mod->versionidsNot)
309                     mod->versionidsNot = new Strings();
310                 mod->versionidsNot->push(ident->toChars());
311             }
312         }
313         else if (level <= global.params.versionlevel || level <= mod->versionlevel)
314             inc = 1;
315         if (!definedInModule && (!ident || (!isReserved(ident->toChars()) && ident != Id::_unittest && ident != Id::_assert)))
316             printDepsConditional(sc, this, "depsVersion ");
317     }
318     return (inc == 1);
319 }
320 
321 /**************************** StaticIfCondition *******************************/
322 
StaticIfCondition(Loc loc,Expression * exp)323 StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
324     : Condition(loc)
325 {
326     this->exp = exp;
327     this->nest = 0;
328 }
329 
syntaxCopy()330 Condition *StaticIfCondition::syntaxCopy()
331 {
332     return new StaticIfCondition(loc, exp->syntaxCopy());
333 }
334 
include(Scope * sc,ScopeDsymbol * sds)335 int StaticIfCondition::include(Scope *sc, ScopeDsymbol *sds)
336 {
337     if (inc == 0)
338     {
339         if (exp->op == TOKerror || nest > 100)
340         {
341             error(loc, (nest > 1000) ? "unresolvable circular static if expression"
342                                      : "error evaluating static if expression");
343             goto Lerror;
344         }
345 
346         if (!sc)
347         {
348             error(loc, "static if conditional cannot be at global scope");
349             inc = 2;
350             return 0;
351         }
352 
353         ++nest;
354         sc = sc->push(sc->scopesym);
355         sc->sds = sds;                  // sds gets any addMember()
356 
357         bool errors = false;
358         bool result = evalStaticCondition(sc, exp, exp, errors);
359         sc->pop();
360         --nest;
361 
362         // Prevent repeated condition evaluation.
363         // See: fail_compilation/fail7815.d
364         if (inc != 0)
365             return (inc == 1);
366         if (errors)
367             goto Lerror;
368         if (result)
369             inc = 1;
370         else
371             inc = 2;
372     }
373     return (inc == 1);
374 
375 Lerror:
376     if (!global.gag)
377         inc = 2;                // so we don't see the error message again
378     return 0;
379 }
380