diff --git a/changelog/dmd.default-init.dd b/changelog/dmd.default-init.dd new file mode 100644 index 000000000000..4b020a843386 --- /dev/null +++ b/changelog/dmd.default-init.dd @@ -0,0 +1,44 @@ +Keywords like `__FILE__` are always evaluated at the call site + +Default arguments for functions can contain the keywords `__FILE__`, +`__FILE_FULL_PATH__`, `__MODULE__`, `__LINE__`, `__FUNCTION__` +and `__PRETTY_FUNCTION__`. They are now evaluated at the source location +of the calling function in more complex expressions as long as used in +an initializer, directly or not. Previously they had to be used directly +in the initializer to be evaluated at the call site. Here are some +examples, where more complex initializers are now evaluated at the +call site: + +--- +void func1(const(char)* file = __FILE__.ptr, size_t line = __LINE__) +{ + // This now prints the filename of the calling function. + // Previously it was the filename of func1 itself. + printf("%s:%zd\n", file, line); +} + +struct Loc +{ + string file; + size_t line; +} + +void func2(Loc loc = Loc(__FILE__, __LINE__)) +{ + // Variable loc now contains file and line of the calling function. + // Previously it was the location of func2. + writeln(loc.file, ":", loc.line); +} + +Loc defaultLoc(string file = __FILE__, size_t line = __LINE__) +{ + return Loc(file, line); +} + +void func3(Loc loc = defaultLoc) +{ + // Variable loc contains file and line of the calling function of + // func3 and not the location of func3 or defaultLoc. + writeln(loc.file, ":", loc.line); +} +--- diff --git a/compiler/src/dmd/dscope.d b/compiler/src/dmd/dscope.d index 7e9499fd28f9..e02ba9a873ba 100644 --- a/compiler/src/dmd/dscope.d +++ b/compiler/src/dmd/dscope.d @@ -97,6 +97,7 @@ extern (C++) struct Scope Dsymbol inunion; /// != null if processing members of a union bool nofree; /// true if shouldn't free it bool inLoop; /// true if inside a loop (where constructor calls aren't allowed) + bool inDefaultArg; /// true if inside a default argument (where __FILE__, etc are evaluated at the call site) int intypeof; /// in typeof(exp) VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init ErrorSink eSink; /// sink for error messages diff --git a/compiler/src/dmd/dtemplate.d b/compiler/src/dmd/dtemplate.d index 5faebf9dd372..4fc4ebaf09ab 100644 --- a/compiler/src/dmd/dtemplate.d +++ b/compiler/src/dmd/dtemplate.d @@ -5632,7 +5632,11 @@ extern (C++) final class TemplateValueParameter : TemplateParameter if (e) { e = e.syntaxCopy(); - if ((e = e.expressionSemantic(sc)) is null) + Scope* sc2 = sc.push(); + sc2.inDefaultArg = true; + e = e.expressionSemantic(sc2); + sc2.pop(); + if (e is null) return null; if (auto te = e.isTemplateExp()) { @@ -6698,6 +6702,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (!tiargs) return true; bool err = false; + + // The arguments are not treated as part of a default argument, + // because they are evaluated at compile time. + sc = sc.push(); + sc.inDefaultArg = false; + for (size_t j = 0; j < tiargs.length; j++) { RootObject o = (*tiargs)[j]; @@ -6929,6 +6939,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); } + sc.pop(); version (none) { printf("-TemplateInstance.semanticTiargs()\n"); diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 52c0203b528e..ea2dc94715a5 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -7446,7 +7446,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = (cast(BinExp)e).reorderSettingAAElem(sc); } - private Expression compileIt(MixinExp exp) + private Expression compileIt(MixinExp exp, Scope *sc) { OutBuffer buf; if (expressionsToString(buf, sc, exp.exps)) @@ -7487,7 +7487,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("MixinExp::semantic('%s')\n", exp.toChars()); } - auto e = compileIt(exp); + // The expression is not treated as part of a default argument, + // because it is evaluated at compile time. + Scope* sc2 = sc.push(); + sc2.inDefaultArg = false; + + auto e = compileIt(exp, sc2); + sc2.pop(); if (!e) return setError(); result = e.expressionSemantic(sc); @@ -7730,7 +7736,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // if the assert condition is a mixin expression, try to compile it if (auto ce = exp.e1.isMixinExp()) { - if (auto e1 = compileIt(ce)) + if (auto e1 = compileIt(ce, sc)) exp.e1 = e1; } @@ -13933,45 +13939,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { //printf("FileInitExp::semantic()\n"); e.type = Type.tstring; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(LineInitExp e) { e.type = Type.tint32; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(ModuleInitExp e) { //printf("ModuleInitExp::semantic()\n"); e.type = Type.tstring; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(FuncInitExp e) { //printf("FuncInitExp::semantic()\n"); e.type = Type.tstring; - if (sc.func) - { - result = e.resolveLoc(Loc.initial, sc); - return; - } - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(PrettyFuncInitExp e) { //printf("PrettyFuncInitExp::semantic()\n"); e.type = Type.tstring; - if (sc.func) - { - result = e.resolveLoc(Loc.initial, sc); - return; - } - - result = e; + result = e.resolveLoc(e.loc, sc); } } @@ -15056,10 +15051,21 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) */ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) { + // Don't replace the special keywords, while we are inside a default + // argument. They are replaced later when copied to the call site. + if (sc.inDefaultArg) + return exp; + exp.loc = loc; Expression visit(Expression exp) { + if (auto binExp = exp.isBinExp()) + { + binExp.e1 = binExp.e1.resolveLoc(loc, sc); + binExp.e2 = binExp.e2.resolveLoc(loc, sc); + return binExp; + } if (auto unaExp = exp.isUnaExp()) { unaExp.e1 = unaExp.e1.resolveLoc(loc, sc); @@ -15068,10 +15074,121 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return exp; } + Expression visitCond(CondExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.e2 = exp.e2.resolveLoc(loc, sc); + exp.econd = exp.econd.resolveLoc(loc, sc); + return exp; + } + Expression visitCat(CatExp exp) { exp.e1 = exp.e1.resolveLoc(loc, sc); exp.e2 = exp.e2.resolveLoc(loc, sc); + if (exp.lowering) + exp.lowering = exp.lowering.resolveLoc(loc, sc); + return exp; + } + + Expression visitStructLiteral(StructLiteralExp exp) + { + foreach (ref element; *exp.elements) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitNew(NewExp exp) + { + if (exp.thisexp) + exp.thisexp = exp.thisexp.resolveLoc(loc, sc); + if (exp.argprefix) + exp.argprefix = exp.argprefix.resolveLoc(loc, sc); + if (exp.lowering) + exp.lowering = exp.lowering.resolveLoc(loc, sc); + + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitCall(CallExp exp) + { + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitArray(ArrayExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitSlice(SliceExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.lwr = exp.lwr.resolveLoc(loc, sc); + exp.upr = exp.upr.resolveLoc(loc, sc); + + return exp; + } + + Expression visitInterval(IntervalExp exp) + { + exp.lwr = exp.lwr.resolveLoc(loc, sc); + exp.upr = exp.upr.resolveLoc(loc, sc); + + return exp; + } + + Expression visitArrayLiteral(ArrayLiteralExp exp) + { + if (exp.basis) + exp.basis = exp.basis.resolveLoc(loc, sc); + + foreach (ref element; *exp.elements) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitAssocArrayLiteral(AssocArrayLiteralExp exp) + { + foreach (ref element; *exp.keys) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + foreach (ref element; *exp.values) + { + if (element) + element = element.resolveLoc(loc, sc); + } + return exp; } @@ -15088,20 +15205,20 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return e.expressionSemantic(sc); } - Expression visitLineInit(LineInitExp _) + Expression visitLineInit(LineInitExp exp) { Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); return e.expressionSemantic(sc); } - Expression visitModuleInit(ModuleInitExp _) + Expression visitModuleInit(ModuleInitExp exp) { const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString(); Expression e = new StringExp(loc, s); return e.expressionSemantic(sc); } - Expression visitFuncInit(FuncInitExp _) + Expression visitFuncInit(FuncInitExp exp) { const(char)* s; if (sc.callsc && sc.callsc.func) @@ -15114,7 +15231,7 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return e.expressionSemantic(sc); } - Expression visitPrettyFunc(PrettyFuncInitExp _) + Expression visitPrettyFunc(PrettyFuncInitExp exp) { FuncDeclaration fd = (sc.callsc && sc.callsc.func) ? sc.callsc.func @@ -15142,7 +15259,16 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) switch(exp.op) { default: return visit(exp); + case EXP.structLiteral: return visitStructLiteral(exp.isStructLiteralExp()); + case EXP.new_: return visitNew(exp.isNewExp()); case EXP.concatenate: return visitCat(exp.isCatExp()); + case EXP.call: return visitCall(exp.isCallExp()); + case EXP.question: return visitCond(exp.isCondExp()); + case EXP.array: return visitArray(exp.isArrayExp()); + case EXP.slice: return visitSlice(exp.isSliceExp()); + case EXP.interval: return visitInterval(exp.isIntervalExp()); + case EXP.arrayLiteral: return visitArrayLiteral(exp.isArrayLiteralExp()); + case EXP.assocArrayLiteral: return visitAssocArrayLiteral(exp.isAssocArrayLiteralExp()); case EXP.file: case EXP.fileFullPath: return visitFileInit(exp.isFileInitExp()); case EXP.line: return visitLineInit(exp.isLineInitExp); @@ -16202,7 +16328,10 @@ Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc) em.checkDisabled(loc, sc); if (em.depdecl && !em.depdecl._scope) + { em.depdecl._scope = sc; + em.depdecl._scope.setNoFree(); + } em.checkDeprecated(loc, sc); if (em.errors) diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index 361ca23e8b27..cf8d4b692f64 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -7268,6 +7268,7 @@ struct Scope final Dsymbol* inunion; bool nofree; bool inLoop; + bool inDefaultArg; int32_t intypeof; VarDeclaration* lastVar; ErrorSink* eSink; @@ -7309,6 +7310,7 @@ struct Scope final inunion(), nofree(), inLoop(), + inDefaultArg(), intypeof(), lastVar(), eSink(), @@ -7331,7 +7333,7 @@ struct Scope final aliasAsg() { } - Scope(Scope* enclosing, Module* _module = nullptr, ScopeDsymbol* scopesym = nullptr, FuncDeclaration* func = nullptr, VarDeclaration* varDecl = nullptr, Dsymbol* parent = nullptr, LabelStatement* slabel = nullptr, SwitchStatement* sw = nullptr, Statement* tryBody = nullptr, TryFinallyStatement* tf = nullptr, ScopeGuardStatement* os = nullptr, Statement* sbreak = nullptr, Statement* scontinue = nullptr, ForeachStatement* fes = nullptr, Scope* callsc = nullptr, Dsymbol* inunion = nullptr, bool nofree = false, bool inLoop = false, int32_t intypeof = 0, VarDeclaration* lastVar = nullptr, ErrorSink* eSink = nullptr, Module* minst = nullptr, TemplateInstance* tinst = nullptr, CtorFlow ctorflow = CtorFlow(), AlignDeclaration* aligndecl = nullptr, CPPNamespaceDeclaration* namespace_ = nullptr, LINK linkage = (LINK)1u, CPPMANGLE cppmangle = (CPPMANGLE)0u, PragmaDeclaration* inlining = nullptr, Visibility visibility = Visibility((Visibility::Kind)5u, nullptr), int32_t explicitVisibility = 0, uint64_t stc = 0LLU, DeprecatedDeclaration* depdecl = nullptr, uint32_t flags = 0u, UserAttributeDeclaration* userAttribDecl = nullptr, DocComment* lastdc = nullptr, void* anchorCounts = nullptr, Identifier* prevAnchor = nullptr, AliasDeclaration* aliasAsg = nullptr) : + Scope(Scope* enclosing, Module* _module = nullptr, ScopeDsymbol* scopesym = nullptr, FuncDeclaration* func = nullptr, VarDeclaration* varDecl = nullptr, Dsymbol* parent = nullptr, LabelStatement* slabel = nullptr, SwitchStatement* sw = nullptr, Statement* tryBody = nullptr, TryFinallyStatement* tf = nullptr, ScopeGuardStatement* os = nullptr, Statement* sbreak = nullptr, Statement* scontinue = nullptr, ForeachStatement* fes = nullptr, Scope* callsc = nullptr, Dsymbol* inunion = nullptr, bool nofree = false, bool inLoop = false, bool inDefaultArg = false, int32_t intypeof = 0, VarDeclaration* lastVar = nullptr, ErrorSink* eSink = nullptr, Module* minst = nullptr, TemplateInstance* tinst = nullptr, CtorFlow ctorflow = CtorFlow(), AlignDeclaration* aligndecl = nullptr, CPPNamespaceDeclaration* namespace_ = nullptr, LINK linkage = (LINK)1u, CPPMANGLE cppmangle = (CPPMANGLE)0u, PragmaDeclaration* inlining = nullptr, Visibility visibility = Visibility((Visibility::Kind)5u, nullptr), int32_t explicitVisibility = 0, uint64_t stc = 0LLU, DeprecatedDeclaration* depdecl = nullptr, uint32_t flags = 0u, UserAttributeDeclaration* userAttribDecl = nullptr, DocComment* lastdc = nullptr, void* anchorCounts = nullptr, Identifier* prevAnchor = nullptr, AliasDeclaration* aliasAsg = nullptr) : enclosing(enclosing), _module(_module), scopesym(scopesym), @@ -7350,6 +7352,7 @@ struct Scope final inunion(inunion), nofree(nofree), inLoop(inLoop), + inDefaultArg(inDefaultArg), intypeof(intypeof), lastVar(lastVar), eSink(eSink), diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index a012e0c7c5bf..268622a82fcc 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -1675,7 +1675,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) // = CondExpression { nextToken(); - tp_defaultvalue = parseDefaultInitExp(); + tp_defaultvalue = parseAssignExp(); } tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); } @@ -2969,7 +2969,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) // = defaultArg { nextToken(); - ae = parseDefaultInitExp(); + ae = parseAssignExp(); } auto param = new AST.Parameter(loc, storageClass | STC.parameter, at, ai, ae, null); if (udas) @@ -6949,33 +6949,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } } - /***************************************** - * Parses default argument initializer expression that is an assign expression, - * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__. - */ - private AST.Expression parseDefaultInitExp() - { - AST.Expression e = null; - const tv = peekNext(); - if (tv == TOK.comma || tv == TOK.rightParenthesis) - { - switch (token.value) - { - case TOK.file: e = new AST.FileInitExp(token.loc, EXP.file); break; - case TOK.fileFullPath: e = new AST.FileInitExp(token.loc, EXP.fileFullPath); break; - case TOK.line: e = new AST.LineInitExp(token.loc); break; - case TOK.moduleString: e = new AST.ModuleInitExp(token.loc); break; - case TOK.functionString: e = new AST.FuncInitExp(token.loc); break; - case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(token.loc); break; - default: goto LExp; - } - nextToken(); - return e; - } - LExp: - return parseAssignExp(); - } - /******************** * Parse inline assembler block. * Enters with token on the `asm`. @@ -8152,33 +8125,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; case TOK.file: - { - const(char)* s = loc.filename ? loc.filename : mod.ident.toChars(); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.FileInitExp(loc, EXP.file); + nextToken(); + break; case TOK.fileFullPath: - { - assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location"); - const s = FileName.toAbsolute(loc.filename); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.FileInitExp(loc, EXP.fileFullPath); + nextToken(); + break; case TOK.line: - e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32); + e = new AST.LineInitExp(loc); nextToken(); break; case TOK.moduleString: - { - const(char)* s = md ? md.toChars() : mod.toChars(); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.ModuleInitExp(loc); + nextToken(); + break; case TOK.functionString: e = new AST.FuncInitExp(loc); nextToken(); diff --git a/compiler/src/dmd/scope.h b/compiler/src/dmd/scope.h index 1535fd077554..4b157cc9ee7c 100644 --- a/compiler/src/dmd/scope.h +++ b/compiler/src/dmd/scope.h @@ -87,6 +87,7 @@ struct Scope Dsymbol *inunion; // !=null if processing members of a union d_bool nofree; // true if shouldn't free it d_bool inLoop; // true if inside a loop (where constructor calls aren't allowed) + d_bool inDefaultArg; // true if inside a default argument (where __FILE__, etc are evaluated at the call site) int intypeof; // in typeof(exp) VarDeclaration *lastVar; // Previous symbol used to prevent goto-skips-init ErrorSink *eSink; // sink for error messages diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index 40bfe2d7ea42..174d9b4dc147 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -345,6 +345,7 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.tf = null; sc2.os = null; sc2.inLoop = false; + sc2.inDefaultArg = false; sc2.userAttribDecl = null; if (sc2.intypeof == 1) sc2.intypeof = 2; diff --git a/compiler/src/dmd/typesem.d b/compiler/src/dmd/typesem.d index ba454dd717b2..3db56080134f 100644 --- a/compiler/src/dmd/typesem.d +++ b/compiler/src/dmd/typesem.d @@ -1725,9 +1725,12 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) else { e = inferType(e, fparam.type); + Scope* sc2 = sc.push(); + sc2.inDefaultArg = true; Initializer iz = new ExpInitializer(e.loc, e); - iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret); + iz = iz.initializerSemantic(sc2, fparam.type, INITnointerpret); e = iz.initializerToExpression(); + sc2.pop(); } if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820 { diff --git a/compiler/test/runnable/imports/issue18919b.d b/compiler/test/runnable/imports/issue18919b.d new file mode 100644 index 000000000000..4278f7f5cdee --- /dev/null +++ b/compiler/test/runnable/imports/issue18919b.d @@ -0,0 +1,250 @@ +module imports.issue18919b; + +import core.stdc.stdio; + +// Remove directories from paths. Used to make the output platform-independent. +string baseName(string path) +{ + foreach_reverse (i, char c; path) + { + if (c == '/' || c == '\\') + return path[i + 1 .. $]; + } + return path; +} +const(char)* baseName(const(char)* path) +{ + for (const(char)* ptr = path; *ptr; ptr++) + { + if (*ptr == '/' || *ptr == '\\') + path = ptr + 1; + } + return path; +} + +void func1(string file = __FILE__, size_t line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__) +{ + file = baseName(file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, cast(int) line, + cast(int) func.length, func.ptr, + cast(int) pfunc.length, pfunc.ptr, + cast(int) mod.length, mod.ptr); +} + +// https://issues.dlang.org/show_bug.cgi?id=21211 +void func2(const(char)* file = __FILE__.ptr, size_t line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr) +{ + file = baseName(file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + file, cast(int) line, func, pfunc, mod); +} + +// https://issues.dlang.org/show_bug.cgi?id=18919 +struct Loc3 +{ + string file; + size_t line; + string func; + string pfunc; + string mod; +} +void func3(Loc3 loc = Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +Loc3 defaultLoc3(string file = __FILE__, size_t line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__) +{ + return Loc3(file, line, func, pfunc, mod); +} +void func3b(Loc3 loc = defaultLoc3) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +enum Loc3Mixin = q{Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)}; +void func3c(Loc3 loc = mixin(Loc3Mixin)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +void func3d(Loc3* loc = new Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} + +struct Loc4 +{ + const(char)* file; + size_t line; + const(char)* func; + const(char)* pfunc; + const(char)* mod; +} +void func4(Loc4 loc = Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +Loc4 defaultLoc4(const(char)* file = __FILE__.ptr, size_t line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr) +{ + return Loc4(file, line, func, pfunc, mod); +} +void func4b(Loc4 loc = defaultLoc4) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +enum Loc4Mixin = q{Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)}; +void func4c(Loc4 loc = mixin(Loc4Mixin)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +void func4d(Loc4* loc = new Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} + +void func5(string file = baseName(__FILE__), int line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__)() +{ + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, line, + cast(int) func.length, func.ptr, + cast(int) pfunc.length, pfunc.ptr, + cast(int) mod.length, mod.ptr); +} + +void func6(string file = baseName(__FILE__), int line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr)() +{ + printf("%s: %.*s:%d %s %s %s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, line, func, pfunc, mod); +} + +void func7(int expr1 = 1000 + __LINE__ * 2, + string expr2 = "file=" ~ baseName(__FILE__) ~ " func=" ~ __FUNCTION__, + int expr3 = __LINE__ > 5 ? 1 : 2) +{ + printf("%s: expr1=%d, %.*s, expr3=%d\n", __FUNCTION__.ptr, expr1, cast(int) expr2.length, expr2.ptr, expr3); +} + +immutable string[2] constants = ["constant1", "constant2"]; +void func8(int[] expr1 = [__LINE__, __LINE__ + 1000], + int[string] expr2 = [baseName(__FILE__): __LINE__], + string expr3 = constants[__LINE__ > 5], + string expr4 = __FILE__[0 .. __FILE__.length - 2]) +{ + expr4 = baseName(expr4); + printf("%s: expr1=[", __FUNCTION__.ptr); + foreach (i, x; expr1) + printf("%d, ", x); + printf("], expr2=["); + foreach (k, v; expr2) + printf("%.*s: %d, ", cast(int) k.length, k.ptr, v); + printf("], expr3=%.*s", cast(int) expr3.length, expr3.ptr); + printf(", expr4=%.*s\n", cast(int) expr4.length, expr4.ptr); +} + +void func9(void function(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__) + fp = (string file, size_t line, string mod) + { + file = baseName(file); + printf("imports.issue18919b.func9.fp: %.*s:%d %.*s\n", + cast(int) file.length, file.ptr, cast(int) line, + cast(int) mod.length, mod.ptr); + }) +{ + fp(); +} + +void func10(string expr1 = mixin(() { return "\"expr1=" ~ __MODULE__ ~ "\""; } ()), + string expr2 = mixin("\"expr2=" ~ __MODULE__ ~ "\"")) +{ + printf("%s: %.*s, %.*s\n", __FUNCTION__.ptr, + cast(int) expr1.length, expr1.ptr, + cast(int) expr2.length, expr2.ptr); +} + +template ctLoc3(string file, int line, + string func, string pfunc, string mod) +{ + enum Loc3 ctLoc3 = Loc3(file, line, func, pfunc, mod); +} + +void func11(Loc3 loc = ctLoc3!(baseName(__FILE__), __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} + +void func12(const(char)*[] args = [baseName(__FILE__.ptr), + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr]) +{ + printf("%s:", __FUNCTION__.ptr); + foreach (arg; args) + printf(" %s", arg); + printf("\n"); +} diff --git a/compiler/test/runnable/issue18919.d b/compiler/test/runnable/issue18919.d new file mode 100644 index 000000000000..815e018d649c --- /dev/null +++ b/compiler/test/runnable/issue18919.d @@ -0,0 +1,47 @@ +/* +EXTRA_SOURCES: imports/issue18919b.d +RUN_OUTPUT: +--- +imports.issue18919b.func1: issue18919.d:29 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func2: issue18919.d:30 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3: issue18919.d:31 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3b: issue18919.d:32 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3c: issue18919.d:33 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3d: issue18919.d:34 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4: issue18919.d:35 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4b: issue18919.d:36 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4c: issue18919.d:37 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4d: issue18919.d:38 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func5!("issue18919.d", 39, "issue18919.main", "void issue18919.main()", "issue18919").func5: issue18919.d:39 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func6!("issue18919.d", 40, "issue18919.main", "void issue18919.main()", "issue18919").func6: issue18919.d:40 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func7: expr1=1082, file=issue18919.d func=issue18919.main, expr3=1 +imports.issue18919b.func8: expr1=[42, 1042, ], expr2=[issue18919.d: 42, ], expr3=constant2, expr4=issue18919 +imports.issue18919b.func9.fp: issue18919b.d:216 imports.issue18919b +imports.issue18919b.func10: expr1=imports.issue18919b, expr2=imports.issue18919b +imports.issue18919b.func11: issue18919b.d:233 imports.issue18919b +imports.issue18919b.func12: issue18919.d issue18919.main void issue18919.main() issue18919 +--- +*/ +import imports.issue18919b; + +void main() +{ + func1(); + func2(); + func3(); + func3b(); + func3c(); + func3d(); + func4(); + func4b(); + func4c(); + func4d(); + func5(); + func6(); + func7(); + func8(); + func9(); + func10(); + func11(); + func12(); +} diff --git a/compiler/test/runnable/test18916.d b/compiler/test/runnable/test18916.d index 0e844ada15a3..f14f32c31ebd 100644 --- a/compiler/test/runnable/test18916.d +++ b/compiler/test/runnable/test18916.d @@ -11,9 +11,9 @@ struct Line void foo(Line line1 = __LINE__, int line2 = __LINE__, int line3 = int(__LINE__)) { - assert(line1 == 12); + assert(line1 == 21); assert(line2 == 21); - assert(line3 == 12); + assert(line3 == 21); } void main() diff --git a/compiler/test/runnable/xtest46.d b/compiler/test/runnable/xtest46.d index aeb2aab8336a..cf22f40d3e3a 100644 --- a/compiler/test/runnable/xtest46.d +++ b/compiler/test/runnable/xtest46.d @@ -179,7 +179,7 @@ void test7() void foo8(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__) { - assert(n1 < n2); + assert(n1 == n2); printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr); } @@ -192,7 +192,7 @@ void test8() void foo9(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__)() { - assert(n1 < n2); + assert(n1 == n2); printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr); }