@@ -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,81 @@ 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+
174+ if (strcmp(mangleExact(fd),
175+ " _D3std4json9JSONValue17__lambda_L726_C31FNaNbNiZSQBvQBuQBs" ) == 0 )
176+ return ;
177+ }
103178
104179 // Protect functions based upon safetiness of it.
105180 // It may be desirable to disable some behaviors in @system code, or completely.
@@ -118,6 +193,13 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
118193 DFAReporter reporter;
119194
120195 dfaCommon.allocator.dfaCommon = &dfaCommon;
196+ dfaCommon.currentFunction = fd;
197+
198+ if (auto ag = fd.isThis)
199+ {
200+ if (ag.isClassDeclaration)
201+ dfaCommon.isCurrentFunctionClassConstructor = fd.ident is Id.ctor;
202+ }
121203
122204 stmtWalker.dfaCommon = &dfaCommon;
123205 expWalker.dfaCommon = &dfaCommon;
@@ -133,6 +215,49 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
133215 analyzer.reporter = &reporter;
134216 reporter.errorSink = global.errorSink;
135217
218+ bool errorsPrinted;
219+
220+ void printOnError ()
221+ {
222+ if (errorsPrinted)
223+ return ;
224+ errorsPrinted = true ;
225+
226+ dfaCommon.printIfStructure((ref OutBuffer ob, scope void delegate (const (char )* ) prefix) {
227+ prefix(" " );
228+ ob.printf(" function dfa %s : %s = %s at %s\n " , fd.getModule.ident.toChars,
229+ mangleExact(fd), fd.toFullSignature, fd.loc.toChars);
230+
231+ dfaCommon.allocator.allVariables((DFAVar* var) {
232+ prefix(" var" );
233+ ob.printf(" %p base1=%p, base2=%p, dereferenceVar=%p, oldestLifeTimeAllowedDepth=%d<%d, writeCount=%d, unmodel=%d, isScope=%d, isByRef=%d, mayEscapeInitialValue=%d" ,
234+ var, var.base1, var.base2, var.dereferenceVar, var.oldestLifeTimeAllowedDepth,
235+ var.youngestLifeTimeAllowedDepth, var.writeCount, var.unmodellable,
236+ var.isScope, var.isByRef, var.mayEscapeInitialValue);
237+
238+ if (var.var ! is null )
239+ {
240+ ob.printf(" , `%s` at " , var.var.ident.toChars);
241+ appendLoc(ob, var.var.loc);
242+ }
243+
244+ ob.printf(" \n " );
245+ });
246+ dfaCommon.allocator.allObjects((DFAObject* obj) {
247+ prefix(" object" );
248+ 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 " ,
249+ obj, obj.base1, obj.base2, obj.storageFor, obj.derivedFrom,
250+ obj.inCell, obj.constrainedBy, obj.mayNotBeExactPointer, obj.minimumDeclaredAtDepth,
251+ obj.onTheStack, obj.lifeTimeUnderstood, obj.delayOnReadErrorOfEscape);
252+ });
253+ });
254+
255+ dfaCommon.printIfStructure((ref OutBuffer ob, scope PrintPrefixType prefix) {
256+ if (fd.parametersDFAInfo ! is null )
257+ printDFAParameters(fd.parametersDFAInfo);
258+ });
259+ }
260+
136261 dfaCommon.printIfStructure((ref OutBuffer ob, scope PrintPrefixType prefix) {
137262 ob.printf(" ============================== %s : %s = %s at " ,
138263 fd.getModule.ident.toChars, mangleExact (fd), fd.toFullSignature);
@@ -151,13 +276,6 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
151276 }
152277 }
153278
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-
161279 version (none )
162280 {
163281 import dmd.hdrgen;
@@ -169,20 +287,151 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
169287 printf(buf.extractChars);
170288 }
171289
172- stmtWalker.start(fd) ;
290+ int currentErrors = global.errors ;
173291
174- version ( none )
292+ try
175293 {
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);
294+ timeTraceBeginEvent(TimeTraceEventType.dfa);
295+ stmtWalker.start(fd);
296+ }
297+ finally
298+ {
299+ timeTraceEndEvent(TimeTraceEventType.dfa, fd);
179300 }
180301
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);
302+ if (currentErrors != global.errors)
303+ {
304+ version (none )
305+ {
306+ printf(" function dfa %s : %s = %s at %s\n " , fd.getModule.ident.toChars,
307+ mangleExact(fd), fd.toFullSignature, fd.loc.toChars);
308+ }
184309
185- appendLoc(ob, fd.loc);
186- ob.writestring(" \n " );
310+ printOnError;
311+ }
312+
313+ version (all )
314+ printOnError;
315+
316+ version (all )
317+ {
318+ if (checkEscapes(fd, sc))
319+ printOnError;
320+ }
321+ }
322+
323+ bool checkEscapes (FuncDeclaration fd, Scope* sc)
324+ {
325+ import dmd.dfa.utils;
326+ import dmd.printast;
327+
328+ if (fd.getModule.ident.toString != " __fastdfa_escape_test" )
329+ return false ;
330+
331+ Expression[] expecteds;
332+ bool found, error;
333+
334+ foreachUda(fd, sc, (Expression uda) {
335+ if (auto sl = uda.isStructLiteralExp)
336+ {
337+ ArrayLiteralExp al;
338+
339+ if (sl.sd.ident.toString() == " __FastDFAEscapeTest" )
340+ {
341+ if ((al = (* sl.elements)[0 ].isArrayLiteralExp) ! is null )
342+ {
343+ if (al.elements ! is null )
344+ expecteds = (* al.elements)[];
345+ }
346+
347+ found = true ;
348+ }
349+ }
350+
351+ return 0 ;
187352 });
353+
354+ if (found)
355+ {
356+ struct TestParam
357+ {
358+ bool present;
359+ bool escapeIntoNothing;
360+ bool escapeIntoUnknown;
361+ ParameterDFAInfo.Inferrable inferrable;
362+ }
363+
364+ TestParam nextTestParam ()
365+ {
366+ if (expecteds.length == 0 )
367+ return TestParam (false );
368+
369+ TestParam ret = TestParam(true );
370+
371+ StructLiteralExp sl = expecteds[0 ].isStructLiteralExp;
372+ expecteds = expecteds[1 .. $];
373+ if (sl is null || sl.elements is null )
374+ return TestParam (true );
375+ else if (sl.elements.length != 2 )
376+ return TestParam (false );
377+
378+ IntegerExp ie;
379+
380+ ret.escapeIntoNothing = (ie = (* sl.elements)[0 ].isIntegerExp) ! is null && ie.value == 1 ;
381+ ret.inferrable.escapesInto = (ie = (* sl.elements)[1 ].isIntegerExp) ! is null ? ie.value
382+ : 0 ;
383+
384+ return ret;
385+ }
386+
387+ void checkEscapeTest (ref ParameterDFAInfo paramDFAInfo)
388+ {
389+ TestParam tp = nextTestParam();
390+ if (! tp.present)
391+ {
392+ printf(" Missing UDA param info for param %d\n " , paramDFAInfo.parameterId);
393+ error = true ;
394+ return ;
395+ }
396+
397+ if (tp.escapeIntoNothing && ! paramDFAInfo.inferred.escapeIntoNothing)
398+ {
399+ printf(" UDA param info param %d missing escapeIntoNothing\n " ,
400+ paramDFAInfo.parameterId);
401+ error = true ;
402+ }
403+
404+ if (tp.inferrable.escapesInto != 0 && paramDFAInfo.inferred.escapesInto == 0 )
405+ {
406+ printf(" UDA param info param %d missing escapesInto\n " , paramDFAInfo.parameterId);
407+ error = true ;
408+ }
409+ else if (tp.inferrable.escapesInto != paramDFAInfo.inferred.escapesInto)
410+ {
411+ printf(" UDA param info param %d incorrect escapesInto\n " , paramDFAInfo.parameterId);
412+ error = true ;
413+ }
414+ }
415+
416+ if (fd.parametersDFAInfo.thisPointer.parameterId == - 2 )
417+ checkEscapeTest(fd.parametersDFAInfo.thisPointer);
418+
419+ foreach (ref paramDFAInfo; fd.parametersDFAInfo.parameters)
420+ checkEscapeTest(paramDFAInfo);
421+
422+ foreach (expected; expecteds)
423+ printAST(expected);
424+ }
425+ else
426+ error = true ;
427+
428+ if (error && ! fd.isGenerated && fd.loc.linnum > 999 )
429+ {
430+ printf(" %s test UDA: function %s : %s = %s at #%d\n " , found ? " Incompatible" .ptr : " Missing" .ptr,
431+ fd.getModule.ident.toChars, mangleExact (fd), fd.toFullSignature, fd.loc.linnum);
432+ printDFAParameters(fd.parametersDFAInfo);
433+ return true ;
434+ }
435+ else
436+ return false ;
188437}
0 commit comments