@@ -29,6 +29,10 @@ import dmd.globals;
2929import dmd.mangle;
3030import dmd.dscope;
3131import dmd.dsymbol;
32+ import dmd.attribsem;
33+ import dmd.expression;
34+ import dmd.id;
35+ import dmd.timetrace;
3236import core.stdc.stdio ;
3337import core.stdc.string ;
3438
@@ -78,6 +82,7 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
7882 import dmd.dfa.fast.statement;
7983 import dmd.dfa.fast.analysis;
8084 import dmd.dfa.fast.report;
85+ import dmd.dfa.utils;
8186
8287 if (fd.skipCodegen)
8388 {
@@ -95,11 +100,85 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
95100 }
96101
97102 // Use these if statements for debugging specific things.
98- // if (fd.ident.toString != "checkFloatInit5 ") return;
99- // if (!(fd.ident.toString == "replaceReferenceDefinition " || fd.ident.toString == "extractReferences ")) return;
103+ // if (fd.ident.toString != "nullPtrVarDerefOuter ") return;
104+ // if (!(fd.ident.toString == "extractReferences " || fd.ident.toString == "replaceReferenceDefinition ")) return;
100105 // if (fd.loc.linnum != 54) return;
101- // if (fd.getModule.ident.toString != "start") return;
102- // if (strcmp(mangleExact(fd), "_D4core9exception15ArraySliceError6__ctorMFNaNbNiNfmmmAyamC6object9ThrowableZCQCyQCwQCp") != 0) return;
106+ // if (fd.getModule.ident.toString != "doc") return;
107+ // if (strcmp(mangleExact(fd), "_D5ocean4util9container5cache16ExpiringLRUCache__TQvTSQCaQBxQBvQBo20ExpiredCacheReloader__TQzTSQDpQDmQDkQDd25ExpiredCacheReloader_test7TrivialZQCz10CacheValueZQFa19getExpiringOrCreateMFmJbbZPQFi") != 0) return;
108+ // if (!(strcmp(mangleExact(fd), "?visit@DeduceType@deduceType@@UEAAXPEAVType@@@Z") == 0 || fd.ident.toString == "deduceWildHelper") )return;
109+
110+ // used in CI to skip tests that do need to error
111+ version (all )
112+ {
113+ if (fd.getModule.ident.toString == " testassert" )
114+ return ;
115+ else if (fd.getModule.ident.toString == " xtest46" )
116+ return ;
117+ else if (fd.getModule.ident.toString == " xtest46_gc" )
118+ return ;
119+ else if (fd.getModule.ident.toString == " b3841" )
120+ return ;
121+ else if (fd.getModule.ident.toString == " fail329" )
122+ return ;
123+ else if (fd.getModule.ident.toString == " fail_scope" )
124+ return ;
125+ else if (fd.getModule.ident.toString == " failcstuff2" )
126+ return ;
127+ else if (fd.getModule.ident.toString == " exe1" )
128+ return ;
129+ else if (fd.getModule.ident.toString == " exe2" )
130+ return ;
131+ else if (fd.getModule.ident.toString == " exe3" )
132+ return ;
133+ else if (fd.getModule.ident.toString == " nullderefcheck_safeonly" )
134+ return ;
135+ else if (fd.getModule.ident.toString == " nullderefcheck" )
136+ return ;
137+ else if (fd.getModule.ident.toString == " testcontracts" )
138+ return ;
139+ else if (fd.getModule.ident.toString == " arraytopointer" )
140+ return ;
141+ else if (fd.getModule.ident.toString == " compile1" )
142+ return ;
143+ else if (fd.getModule.ident.toString == " ctests2" )
144+ return ;
145+ else if (fd.getModule.ident.toString == " fix20425" )
146+ return ;
147+ else if (fd.getModule.ident.toString == " revert_dip1000" )
148+ return ;
149+ else if (fd.getModule.ident.toString == " test19873" )
150+ return ;
151+ else if (fd.getModule.ident.toString == " test22875" )
152+ return ;
153+ else if (fd.getModule.ident.toString == " test22842" )
154+ return ;
155+ else if (fd.getModule.ident.toString == " test22904" )
156+ return ;
157+ else if (fd.getModule.ident.toString == " test23034" )
158+ return ;
159+ else if (fd.getModule.ident.toString == " test23034b" )
160+ return ;
161+ else if (fd.getModule.ident.toString == " test23044" )
162+ return ;
163+ else if (fd.getModule.ident.toString == " test23875" )
164+ return ;
165+ else if (fd.getModule.ident.toString == " test24069" )
166+ return ;
167+ else if (fd.getModule.ident.toString == " testcstuff2" )
168+ return ;
169+ else if (fd.getModule.ident.toString == " testcstuff1" )
170+ return ;
171+ else if (fd.getModule.ident.toString == " complex" )
172+ return ;
173+ else if (fd.getModule.ident.toString == " a12874" )
174+ return ;
175+ else if (fd.getModule.ident.toString == " noreturn2" )
176+ return ;
177+
178+ if (strcmp(mangleExact(fd),
179+ " _D3std4json9JSONValue17__lambda_L726_C31FNaNbNiZSQBvQBuQBs" ) == 0 )
180+ return ;
181+ }
103182
104183 // Protect functions based upon safetiness of it.
105184 // It may be desirable to disable some behaviors in @system code, or completely.
@@ -118,6 +197,13 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
118197 DFAReporter reporter;
119198
120199 dfaCommon.allocator.dfaCommon = &dfaCommon;
200+ dfaCommon.currentFunction = fd;
201+
202+ if (auto ag = fd.isThis)
203+ {
204+ if (ag.isClassDeclaration)
205+ dfaCommon.isCurrentFunctionClassConstructor = fd.ident is Id.ctor;
206+ }
121207
122208 stmtWalker.dfaCommon = &dfaCommon;
123209 expWalker.dfaCommon = &dfaCommon;
@@ -133,6 +219,49 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
133219 analyzer.reporter = &reporter;
134220 reporter.errorSink = global.errorSink;
135221
222+ bool errorsPrinted;
223+
224+ void printOnError ()
225+ {
226+ if (errorsPrinted)
227+ return ;
228+ errorsPrinted = true ;
229+
230+ dfaCommon.printIfStructure((ref OutBuffer ob, scope void delegate (const (char )* ) prefix) {
231+ prefix(" " );
232+ ob.printf(" function dfa %s : %s = %s at %s\n " , fd.getModule.ident.toChars,
233+ mangleExact(fd), fd.toFullSignature, fd.loc.toChars);
234+
235+ dfaCommon.allocator.allVariables((DFAVar* var) {
236+ prefix(" var" );
237+ ob.printf(" %p base1=%p, base2=%p, dereferenceVar=%p, oldestLifeTimeAllowedDepth=%d<%d, writeCount=%d, unmodel=%d, isScope=%d, isByRef=%d, mayEscapeInitialValue=%d" ,
238+ var, var.base1, var.base2, var.dereferenceVar, var.oldestLifeTimeAllowedDepth,
239+ var.youngestLifeTimeAllowedDepth, var.writeCount, var.unmodellable,
240+ var.isScope, var.isByRef, var.mayEscapeInitialValue);
241+
242+ if (var.var ! is null )
243+ {
244+ ob.printf(" , `%s` at " , var.var.ident.toChars);
245+ appendLoc(ob, var.var.loc);
246+ }
247+
248+ ob.printf(" \n " );
249+ });
250+ dfaCommon.allocator.allObjects((DFAObject* obj) {
251+ prefix(" object" );
252+ ob.printf(" %p base1=%p, base2=%p, storageFor=%p, derivedFrom=%p, inCell=%p, constrainedBy=%p, mayNotBeExactPointer=%d, minimumDeclaredAtDepth=%d, onTheStack=%d, lifeTimeUnderstood=%d, delayOnReadErrorOfEscape=%d\n " ,
253+ obj, obj.base1, obj.base2, obj.storageFor, obj.derivedFrom,
254+ obj.inCell, obj.constrainedBy, obj.mayNotBeExactPointer, obj.minimumDeclaredAtDepth,
255+ obj.onTheStack, obj.lifeTimeUnderstood, obj.delayOnReadErrorOfEscape);
256+ });
257+ });
258+
259+ dfaCommon.printIfStructure((ref OutBuffer ob, scope PrintPrefixType prefix) {
260+ if (fd.parametersDFAInfo ! is null )
261+ printDFAParameters(fd.parametersDFAInfo);
262+ });
263+ }
264+
136265 dfaCommon.printIfStructure((ref OutBuffer ob, scope PrintPrefixType prefix) {
137266 ob.printf(" ============================== %s : %s = %s at " ,
138267 fd.getModule.ident.toChars, mangleExact (fd), fd.toFullSignature);
@@ -151,13 +280,6 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
151280 }
152281 }
153282
154- version (none )
155- {
156- printf(" function s %s : %s = %s at %s\n " , fd.getModule.ident.toChars,
157- mangleExact(fd), fd.toFullSignature, fd.loc.toChars);
158- fflush(stdout);
159- }
160-
161283 version (none )
162284 {
163285 import dmd.hdrgen;
@@ -169,20 +291,151 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
169291 printf(buf.extractChars);
170292 }
171293
172- stmtWalker.start(fd) ;
294+ int currentErrors = global.errors ;
173295
174- version ( none )
296+ try
175297 {
176- printf(" function e %s : %s = %s at %s\n " , fd.getModule.ident.toChars,
177- mangleExact(fd), fd.toFullSignature, fd.loc.toChars);
178- fflush(stdout);
298+ timeTraceBeginEvent(TimeTraceEventType.dfa);
299+ stmtWalker.start(fd);
300+ }
301+ finally
302+ {
303+ timeTraceEndEvent(TimeTraceEventType.dfa, fd);
179304 }
180305
181- dfaCommon.printIfStructure((ref OutBuffer ob, scope PrintPrefixType prefix) {
182- ob.printf(" ------------------------------ %s : %s = %s at " ,
183- fd.getModule.ident.toChars, mangleExact (fd), fd.toFullSignature);
306+ if (currentErrors != global.errors)
307+ {
308+ version (none )
309+ {
310+ printf(" function dfa %s : %s = %s at %s\n " , fd.getModule.ident.toChars,
311+ mangleExact(fd), fd.toFullSignature, fd.loc.toChars);
312+ }
184313
185- appendLoc(ob, fd.loc);
186- ob.writestring(" \n " );
314+ printOnError;
315+ }
316+
317+ version (all )
318+ printOnError;
319+
320+ version (all )
321+ {
322+ if (checkEscapes(fd, sc))
323+ printOnError;
324+ }
325+ }
326+
327+ bool checkEscapes (FuncDeclaration fd, Scope* sc)
328+ {
329+ import dmd.dfa.utils;
330+ import dmd.printast;
331+
332+ if (fd.getModule.ident.toString != " __fastdfa_escape_test" )
333+ return false ;
334+
335+ Expression[] expecteds;
336+ bool found, error;
337+
338+ foreachUda(fd, sc, (Expression uda) {
339+ if (auto sl = uda.isStructLiteralExp)
340+ {
341+ ArrayLiteralExp al;
342+
343+ if (sl.sd.ident.toString() == " __FastDFAEscapeTest" )
344+ {
345+ if ((al = (* sl.elements)[0 ].isArrayLiteralExp) ! is null )
346+ {
347+ if (al.elements ! is null )
348+ expecteds = (* al.elements)[];
349+ }
350+
351+ found = true ;
352+ }
353+ }
354+
355+ return 0 ;
187356 });
357+
358+ if (found)
359+ {
360+ struct TestParam
361+ {
362+ bool present;
363+ bool escapeIntoNothing;
364+ bool escapeIntoUnknown;
365+ ParameterDFAInfo.Inferrable inferrable;
366+ }
367+
368+ TestParam nextTestParam ()
369+ {
370+ if (expecteds.length == 0 )
371+ return TestParam (false );
372+
373+ TestParam ret = TestParam(true );
374+
375+ StructLiteralExp sl = expecteds[0 ].isStructLiteralExp;
376+ expecteds = expecteds[1 .. $];
377+ if (sl is null || sl.elements is null )
378+ return TestParam (true );
379+ else if (sl.elements.length != 2 )
380+ return TestParam (false );
381+
382+ IntegerExp ie;
383+
384+ ret.escapeIntoNothing = (ie = (* sl.elements)[0 ].isIntegerExp) ! is null && ie.value == 1 ;
385+ ret.inferrable.escapesInto = (ie = (* sl.elements)[1 ].isIntegerExp) ! is null ? ie.value
386+ : 0 ;
387+
388+ return ret;
389+ }
390+
391+ void checkEscapeTest (ref ParameterDFAInfo paramDFAInfo)
392+ {
393+ TestParam tp = nextTestParam();
394+ if (! tp.present)
395+ {
396+ printf(" Missing UDA param info for param %d\n " , paramDFAInfo.parameterId);
397+ error = true ;
398+ return ;
399+ }
400+
401+ if (tp.escapeIntoNothing && ! paramDFAInfo.inferred.escapeIntoNothing)
402+ {
403+ printf(" UDA param info param %d missing escapeIntoNothing\n " ,
404+ paramDFAInfo.parameterId);
405+ error = true ;
406+ }
407+
408+ if (tp.inferrable.escapesInto != 0 && paramDFAInfo.inferred.escapesInto == 0 )
409+ {
410+ printf(" UDA param info param %d missing escapesInto\n " , paramDFAInfo.parameterId);
411+ error = true ;
412+ }
413+ else if (tp.inferrable.escapesInto != paramDFAInfo.inferred.escapesInto)
414+ {
415+ printf(" UDA param info param %d incorrect escapesInto\n " , paramDFAInfo.parameterId);
416+ error = true ;
417+ }
418+ }
419+
420+ if (fd.parametersDFAInfo.thisPointer.parameterId == - 2 )
421+ checkEscapeTest(fd.parametersDFAInfo.thisPointer);
422+
423+ foreach (ref paramDFAInfo; fd.parametersDFAInfo.parameters)
424+ checkEscapeTest(paramDFAInfo);
425+
426+ foreach (expected; expecteds)
427+ printAST(expected);
428+ }
429+ else
430+ error = true ;
431+
432+ if (error && ! fd.isGenerated && fd.loc.linnum > 999 )
433+ {
434+ printf(" %s test UDA: function %s : %s = %s at #%d\n " , found ? " Incompatible" .ptr : " Missing" .ptr,
435+ fd.getModule.ident.toChars, mangleExact (fd), fd.toFullSignature, fd.loc.linnum);
436+ printDFAParameters(fd.parametersDFAInfo);
437+ return true ;
438+ }
439+ else
440+ return false ;
188441}
0 commit comments