@@ -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,90 @@ 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 you try to mangle C++ file, and C++ generator is on, it can do funky things and error out.
114+ auto mangling = fd._linkage == LINK .d ? mangleExact(fd) : null ;
115+
116+ if (fd.getModule.ident.toString == " testassert" )
117+ return ;
118+ else if (fd.getModule.ident.toString == " xtest46" )
119+ return ;
120+ else if (fd.getModule.ident.toString == " xtest46_gc" )
121+ return ;
122+ else if (fd.getModule.ident.toString == " b3841" )
123+ return ;
124+ else if (fd.getModule.ident.toString == " fail329" )
125+ return ;
126+ else if (fd.getModule.ident.toString == " fail_scope" )
127+ return ;
128+ else if (fd.getModule.ident.toString == " failcstuff2" )
129+ return ;
130+ else if (fd.getModule.ident.toString == " exe1" )
131+ return ;
132+ else if (fd.getModule.ident.toString == " exe2" )
133+ return ;
134+ else if (fd.getModule.ident.toString == " exe3" )
135+ return ;
136+ else if (fd.getModule.ident.toString == " nullderefcheck_safeonly" )
137+ return ;
138+ else if (fd.getModule.ident.toString == " nullderefcheck" )
139+ return ;
140+ else if (fd.getModule.ident.toString == " testcontracts" )
141+ return ;
142+ else if (fd.getModule.ident.toString == " arraytopointer" )
143+ return ;
144+ else if (fd.getModule.ident.toString == " compile1" )
145+ return ;
146+ else if (fd.getModule.ident.toString == " ctests2" )
147+ return ;
148+ else if (fd.getModule.ident.toString == " fix20425" )
149+ return ;
150+ else if (fd.getModule.ident.toString == " revert_dip1000" )
151+ return ;
152+ else if (fd.getModule.ident.toString == " test19873" )
153+ return ;
154+ else if (fd.getModule.ident.toString == " test22875" )
155+ return ;
156+ else if (fd.getModule.ident.toString == " test22842" )
157+ return ;
158+ else if (fd.getModule.ident.toString == " test22904" )
159+ return ;
160+ else if (fd.getModule.ident.toString == " test23034" )
161+ return ;
162+ else if (fd.getModule.ident.toString == " test23034b" )
163+ return ;
164+ else if (fd.getModule.ident.toString == " test23044" )
165+ return ;
166+ else if (fd.getModule.ident.toString == " test23875" )
167+ return ;
168+ else if (fd.getModule.ident.toString == " test24069" )
169+ return ;
170+ else if (fd.getModule.ident.toString == " testcstuff2" )
171+ return ;
172+ else if (fd.getModule.ident.toString == " testcstuff1" )
173+ return ;
174+ else if (fd.getModule.ident.toString == " complex" )
175+ return ;
176+ else if (fd.getModule.ident.toString == " a12874" )
177+ return ;
178+ else if (fd.getModule.ident.toString == " noreturn2" )
179+ return ;
180+
181+ if (mangling ! is null )
182+ {
183+ if (strcmp(mangling, " _D3std4json9JSONValue17__lambda_L726_C31FNaNbNiZSQBvQBuQBs" ) == 0 )
184+ return ;
185+ }
186+ }
103187
104188 // Protect functions based upon safetiness of it.
105189 // It may be desirable to disable some behaviors in @system code, or completely.
@@ -118,6 +202,13 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
118202 DFAReporter reporter;
119203
120204 dfaCommon.allocator.dfaCommon = &dfaCommon;
205+ dfaCommon.currentFunction = fd;
206+
207+ if (auto ag = fd.isThis)
208+ {
209+ if (ag.isClassDeclaration)
210+ dfaCommon.isCurrentFunctionClassConstructor = fd.ident is Id.ctor;
211+ }
121212
122213 stmtWalker.dfaCommon = &dfaCommon;
123214 expWalker.dfaCommon = &dfaCommon;
@@ -133,6 +224,49 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
133224 analyzer.reporter = &reporter;
134225 reporter.errorSink = global.errorSink;
135226
227+ bool errorsPrinted;
228+
229+ void printOnError ()
230+ {
231+ if (errorsPrinted)
232+ return ;
233+ errorsPrinted = true ;
234+
235+ dfaCommon.printIfStructure((ref OutBuffer ob, scope void delegate (const (char )* ) prefix) {
236+ prefix(" " );
237+ ob.printf(" function dfa %s : %s = %s at %s\n " , fd.getModule.ident.toChars,
238+ mangleExact(fd), fd.toFullSignature, fd.loc.toChars);
239+
240+ dfaCommon.allocator.allVariables((DFAVar* var) {
241+ prefix(" var" );
242+ ob.printf(" %p base1=%p, base2=%p, dereferenceVar=%p, oldestLifeTimeAllowedDepth=%d<%d, writeCount=%d, unmodel=%d, isScope=%d, isByRef=%d, mayEscapeInitialValue=%d" ,
243+ var, var.base1, var.base2, var.dereferenceVar, var.oldestLifeTimeAllowedDepth,
244+ var.youngestLifeTimeAllowedDepth, var.writeCount, var.unmodellable,
245+ var.isScope, var.isByRef, var.mayEscapeInitialValue);
246+
247+ if (var.var ! is null )
248+ {
249+ ob.printf(" , `%s` at " , var.var.ident.toChars);
250+ appendLoc(ob, var.var.loc);
251+ }
252+
253+ ob.printf(" \n " );
254+ });
255+ dfaCommon.allocator.allObjects((DFAObject* obj) {
256+ prefix(" object" );
257+ 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 " ,
258+ obj, obj.base1, obj.base2, obj.storageFor, obj.derivedFrom,
259+ obj.inCell, obj.constrainedBy, obj.mayNotBeExactPointer, obj.minimumDeclaredAtDepth,
260+ obj.onTheStack, obj.lifeTimeUnderstood, obj.delayOnReadErrorOfEscape);
261+ });
262+ });
263+
264+ dfaCommon.printIfStructure((ref OutBuffer ob, scope PrintPrefixType prefix) {
265+ if (fd.parametersDFAInfo ! is null )
266+ printDFAParameters(fd.parametersDFAInfo);
267+ });
268+ }
269+
136270 dfaCommon.printIfStructure((ref OutBuffer ob, scope PrintPrefixType prefix) {
137271 ob.printf(" ============================== %s : %s = %s at " ,
138272 fd.getModule.ident.toChars, mangleExact (fd), fd.toFullSignature);
@@ -151,13 +285,6 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
151285 }
152286 }
153287
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-
161288 version (none )
162289 {
163290 import dmd.hdrgen;
@@ -169,20 +296,151 @@ void fastDFA(FuncDeclaration fd, Scope* sc)
169296 printf(buf.extractChars);
170297 }
171298
172- stmtWalker.start(fd) ;
299+ int currentErrors = global.errors ;
173300
174- version ( none )
301+ try
175302 {
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);
303+ timeTraceBeginEvent(TimeTraceEventType.dfa);
304+ stmtWalker.start(fd);
305+ }
306+ finally
307+ {
308+ timeTraceEndEvent(TimeTraceEventType.dfa, fd);
179309 }
180310
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);
311+ if (currentErrors != global.errors)
312+ {
313+ version (none )
314+ {
315+ printf(" function dfa %s : %s = %s at %s\n " , fd.getModule.ident.toChars,
316+ mangleExact(fd), fd.toFullSignature, fd.loc.toChars);
317+ }
184318
185- appendLoc(ob, fd.loc);
186- ob.writestring(" \n " );
319+ printOnError;
320+ }
321+
322+ version (all )
323+ printOnError;
324+
325+ version (all )
326+ {
327+ if (checkEscapes(fd, sc))
328+ printOnError;
329+ }
330+ }
331+
332+ bool checkEscapes (FuncDeclaration fd, Scope* sc)
333+ {
334+ import dmd.dfa.utils;
335+ import dmd.printast;
336+
337+ if (fd.getModule.ident.toString != " __fastdfa_escape_test" )
338+ return false ;
339+
340+ Expression[] expecteds;
341+ bool found, error;
342+
343+ foreachUda(fd, sc, (Expression uda) {
344+ if (auto sl = uda.isStructLiteralExp)
345+ {
346+ ArrayLiteralExp al;
347+
348+ if (sl.sd.ident.toString() == " __FastDFAEscapeTest" )
349+ {
350+ if ((al = (* sl.elements)[0 ].isArrayLiteralExp) ! is null )
351+ {
352+ if (al.elements ! is null )
353+ expecteds = (* al.elements)[];
354+ }
355+
356+ found = true ;
357+ }
358+ }
359+
360+ return 0 ;
187361 });
362+
363+ if (found)
364+ {
365+ struct TestParam
366+ {
367+ bool present;
368+ bool escapeIntoNothing;
369+ bool escapeIntoUnknown;
370+ ParameterDFAInfo.Inferrable inferrable;
371+ }
372+
373+ TestParam nextTestParam ()
374+ {
375+ if (expecteds.length == 0 )
376+ return TestParam (false );
377+
378+ TestParam ret = TestParam(true );
379+
380+ StructLiteralExp sl = expecteds[0 ].isStructLiteralExp;
381+ expecteds = expecteds[1 .. $];
382+ if (sl is null || sl.elements is null )
383+ return TestParam (true );
384+ else if (sl.elements.length != 2 )
385+ return TestParam (false );
386+
387+ IntegerExp ie;
388+
389+ ret.escapeIntoNothing = (ie = (* sl.elements)[0 ].isIntegerExp) ! is null && ie.value == 1 ;
390+ ret.inferrable.escapesInto = (ie = (* sl.elements)[1 ].isIntegerExp) ! is null ? ie.value
391+ : 0 ;
392+
393+ return ret;
394+ }
395+
396+ void checkEscapeTest (ref ParameterDFAInfo paramDFAInfo)
397+ {
398+ TestParam tp = nextTestParam();
399+ if (! tp.present)
400+ {
401+ printf(" Missing UDA param info for param %d\n " , paramDFAInfo.parameterId);
402+ error = true ;
403+ return ;
404+ }
405+
406+ if (tp.escapeIntoNothing && ! paramDFAInfo.inferred.escapeIntoNothing)
407+ {
408+ printf(" UDA param info param %d missing escapeIntoNothing\n " ,
409+ paramDFAInfo.parameterId);
410+ error = true ;
411+ }
412+
413+ if (tp.inferrable.escapesInto != 0 && paramDFAInfo.inferred.escapesInto == 0 )
414+ {
415+ printf(" UDA param info param %d missing escapesInto\n " , paramDFAInfo.parameterId);
416+ error = true ;
417+ }
418+ else if (tp.inferrable.escapesInto != paramDFAInfo.inferred.escapesInto)
419+ {
420+ printf(" UDA param info param %d incorrect escapesInto\n " , paramDFAInfo.parameterId);
421+ error = true ;
422+ }
423+ }
424+
425+ if (fd.parametersDFAInfo.thisPointer.parameterId == - 2 )
426+ checkEscapeTest(fd.parametersDFAInfo.thisPointer);
427+
428+ foreach (ref paramDFAInfo; fd.parametersDFAInfo.parameters)
429+ checkEscapeTest(paramDFAInfo);
430+
431+ foreach (expected; expecteds)
432+ printAST(expected);
433+ }
434+ else
435+ error = true ;
436+
437+ if (error && ! fd.isGenerated && fd.loc.linnum > 999 )
438+ {
439+ printf(" %s test UDA: function %s : %s = %s at #%d\n " , found ? " Incompatible" .ptr : " Missing" .ptr,
440+ fd.getModule.ident.toChars, mangleExact (fd), fd.toFullSignature, fd.loc.linnum);
441+ printDFAParameters(fd.parametersDFAInfo);
442+ return true ;
443+ }
444+ else
445+ return false ;
188446}
0 commit comments