diff --git a/compiler/src/dmd/traits.d b/compiler/src/dmd/traits.d index c4ac8c06ca8d..81859371802a 100644 --- a/compiler/src/dmd/traits.d +++ b/compiler/src/dmd/traits.d @@ -90,6 +90,50 @@ private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg) return getDsymbol(oarg); } +private const(Dsymbol) recursiveCompilesKey(TraitsExp e, Scope* sc) +{ + if (!e.args || e.args.length != 1) + return null; + + const(Dsymbol) resolveKey(RootObject o) + { + if (auto ex = isExpression(o)) + { + if (const ve = ex.isVarExp()) + return ve.var; + + if (auto ie = ex.isIdentifierExp()) + { + Dsymbol scopesym; + return sc.search(ie.loc, ie.ident, scopesym); + } + + if (auto me = ex.isMixinExp()) + { + if (!me.exps || me.exps.length != 1) + return null; + + return resolveKey((*me.exps)[0]); + } + } + + if (auto tm = isType(o)) + { + if (auto tmixin = tm.isTypeMixin()) + { + if (!tmixin.exps || tmixin.exps.length != 1) + return null; + + return resolveKey((*tmixin.exps)[0]); + } + } + + return getDsymbolWithoutExpCtx(o); + } + + return resolveKey((*e.args)[0]); +} + /** * Fill an array of target size_t values that indicate possible pointer words in memory * if interpreted as the type given as argument. @@ -1877,6 +1921,24 @@ Expression semanticTraits(TraitsExp e, Scope* sc) /* Determine if all the objects - types, expressions, or symbols - * compile without error */ + __gshared const(Dsymbol)[] compilesStack; + bool popCompilesStack; + if (const key = recursiveCompilesKey(e, sc)) + { + foreach (prev; compilesStack) + { + if (prev is key) + { + error(e.loc, "recursive `__traits(compiles)` expression"); + return False(); + } + } + compilesStack ~= key; + popCompilesStack = true; + } + scope (exit) if (popCompilesStack) + compilesStack = compilesStack[0 .. $ - 1]; + if (!dim) return False(); diff --git a/compiler/test/compilable/ice19465.d b/compiler/test/compilable/ice19465.d new file mode 100644 index 000000000000..203640277b6e --- /dev/null +++ b/compiler/test/compilable/ice19465.d @@ -0,0 +1,6 @@ +enum string s = "__traits(compiles, mixin(s))"; + +static if (__traits(compiles, mixin(s))) +{ + enum b = 2; +}