diff --git a/compiler/src/dmd/func.d b/compiler/src/dmd/func.d index 55974f16e53f..cb19b14dfb41 100644 --- a/compiler/src/dmd/func.d +++ b/compiler/src/dmd/func.d @@ -1557,58 +1557,6 @@ extern (C++) class FuncDeclaration : Declaration return fd; } - /*********************************************** - * Check all return statements for a function to verify that returning - * using NRVO is possible. - * - * Returns: - * `false` if the result cannot be returned by hidden reference. - */ - extern (D) final bool checkNRVO() - { - if (!isNRVO() || returns is null) - return false; - - auto tf = type.toTypeFunction(); - if (tf.isref) - return false; - - foreach (rs; *returns) - { - if (auto ve = rs.exp.isVarExp()) - { - auto v = ve.var.isVarDeclaration(); - if (!v || v.isReference()) - return false; - else if (nrvo_var is null) - { - // Variables in the data segment (e.g. globals, TLS or not), - // parameters and closure variables cannot be NRVOed. - if (v.isDataseg() || v.isParameter() || v.toParent2() != this) - return false; - if (v.nestedrefs.length && needsClosure()) - return false; - // don't know if the return storage is aligned - version (MARS) - { - if (alignSectionVars && (*alignSectionVars).contains(v)) - return false; - } - // The variable type needs to be equivalent to the return type. - if (!v.type.equivalent(tf.next)) - return false; - //printf("Setting nrvo to %s\n", v.toChars()); - nrvo_var = v; - } - else if (nrvo_var != v) - return false; - } - else //if (!exp.isLvalue()) // keep NRVO-ability - return false; - } - return true; - } - override final inout(FuncDeclaration) isFuncDeclaration() inout { return this; diff --git a/compiler/src/dmd/funcsem.d b/compiler/src/dmd/funcsem.d index 8e0ffa61278e..ee36a165d62c 100644 --- a/compiler/src/dmd/funcsem.d +++ b/compiler/src/dmd/funcsem.d @@ -65,6 +65,10 @@ import dmd.tokens; import dmd.typesem; import dmd.visitor; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO. */ extern (C++) final class NrvoWalker : StatementRewriteWalker @@ -3006,3 +3010,55 @@ extern (D) void checkMain(FuncDeclaration fd) if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn) .error(fd.loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", fd.kind, fd.toPrettyChars, tf.nextOf().toChars()); } + +/*********************************************** + * Check all return statements for a function to verify that returning + * using NRVO is possible. + * + * Returns: + * `false` if the result cannot be returned by hidden reference. + */ +extern (D) bool checkNRVO(FuncDeclaration fd) +{ + if (!fd.isNRVO() || fd.returns is null) + return false; + + auto tf = fd.type.toTypeFunction(); + if (tf.isref) + return false; + + foreach (rs; *fd.returns) + { + if (auto ve = rs.exp.isVarExp()) + { + auto v = ve.var.isVarDeclaration(); + if (!v || v.isReference()) + return false; + else if (fd.nrvo_var is null) + { + // Variables in the data segment (e.g. globals, TLS or not), + // parameters and closure variables cannot be NRVOed. + if (v.isDataseg() || v.isParameter() || v.toParent2() != fd) + return false; + if (v.nestedrefs.length && fd.needsClosure()) + return false; + // don't know if the return storage is aligned + version (MARS) + { + if (fd.alignSectionVars && (*fd.alignSectionVars).contains(v)) + return false; + } + // The variable type needs to be equivalent to the return type. + if (!v.type.equivalent(tf.next)) + return false; + //printf("Setting nrvo to %s\n", v.toChars()); + fd.nrvo_var = v; + } + else if (fd.nrvo_var != v) + return false; + } + else //if (!exp.isLvalue()) // keep NRVO-ability + return false; + } + return true; +}