aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2020-07-24 18:06:51 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2020-08-26 10:03:56 +0200
commit87e36d9baf41a8642ca8687e846764e0828a088b (patch)
tree4f47a339a73c3f4f6adeba766237380e15558dc6 /gcc/d/dmd
parent27e5d7c77218c0b5dd1a421a55234573e687e927 (diff)
downloadgcc-87e36d9baf41a8642ca8687e846764e0828a088b.zip
gcc-87e36d9baf41a8642ca8687e846764e0828a088b.tar.gz
gcc-87e36d9baf41a8642ca8687e846764e0828a088b.tar.bz2
d: Fix no RVO when returning struct literals initialized with constructor.
Backports a change from upstream dmd that moves front-end NRVO checking from ReturnStatement semantic to the end of FuncDeclaration semantic. In the codegen, retStyle has been partially implemented so that only structs and static arrays return RETstack. This isn't accurate, but don't need to be for the purposes of semantic analysis. If a function either has TREE_ADDRESSABLE or must return in memory, then DECL_RESULT is set as the shidden field for the function. This is used in the codegen pass for ReturnStatement where it is now detected whether a function is returning a struct literal or a constructor function, then the DECL_RESULT is used to directly construct the return value, instead of doing so via temporaries. Reviewed-on: https://github.com/dlang/dmd/pull/11622 gcc/d/ChangeLog: PR d/96156 * d-frontend.cc (retStyle): Only return RETstack for struct and static array types. * decl.cc (DeclVisitor::visit (FuncDeclaration *)): Use NRVO return for all TREE_ADDRESSABLE types. Set shidden to the RESULT_DECL. * expr.cc (ExprVisitor::visit (CallExp *)): Force TARGET_EXPR if the 'this' pointer reference is a CONSTRUCTOR. (ExprVisitor::visit (StructLiteralExp *)): Generate assignment to the symbol to initialize with literal. * toir.cc (IRVisitor::visit (ReturnStatement *)): Detect returning struct literals and write directly into the RESULT_DECL. * dmd/MERGE: Merge upstream dmd fe5f388d8. gcc/testsuite/ChangeLog: PR d/96156 * gdc.dg/pr96156.d: New test.
Diffstat (limited to 'gcc/d/dmd')
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/declaration.h1
-rw-r--r--gcc/d/dmd/func.c52
-rw-r--r--gcc/d/dmd/statementsem.c33
4 files changed, 50 insertions, 38 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 2dc2ef3..276406c 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-cb4a96faecb6b521ac4749581bcfa39f61143db0
+fe5f388d8e5d97dccaa4ef1349f931c36a2cbc46
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 251c407..65ac3f7 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -669,6 +669,7 @@ public:
static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0);
static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0);
void checkDmain();
+ bool checkNrvo();
FuncDeclaration *isFuncDeclaration() { return this; }
diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c
index 30ba8dd..f8e9601 100644
--- a/gcc/d/dmd/func.c
+++ b/gcc/d/dmd/func.c
@@ -1704,9 +1704,6 @@ void FuncDeclaration::semantic3(Scope *sc)
}
}
- if (!inferRetType && retStyle(f) != RETstack)
- nrvo_can = 0;
-
bool inferRef = (f->isref && (storage_class & STCauto));
fbody = ::semantic(fbody, sc2);
@@ -1761,7 +1758,7 @@ void FuncDeclaration::semantic3(Scope *sc)
if (storage_class & STCauto)
storage_class &= ~STCauto;
}
- if (retStyle(f) != RETstack)
+ if (retStyle(f) != RETstack || checkNrvo())
nrvo_can = 0;
if (fbody->isErrorStatement())
@@ -4293,6 +4290,53 @@ void FuncDeclaration::checkDmain()
error("parameters must be main() or main(string[] args)");
}
+/***********************************************
+ * Check all return statements for a function to verify that returning
+ * using NRVO is possible.
+ *
+ * Returns:
+ * true if the result cannot be returned by hidden reference.
+ */
+bool FuncDeclaration::checkNrvo()
+{
+ if (!nrvo_can)
+ return true;
+
+ if (returns == NULL)
+ return true;
+
+ TypeFunction *tf = type->toTypeFunction();
+ if (tf->isref)
+ return true;
+
+ for (size_t i = 0; i < returns->length; i++)
+ {
+ ReturnStatement *rs = (*returns)[i];
+
+ if (VarExp *ve = rs->exp->isVarExp())
+ {
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ if (!v || v->isOut() || v->isRef())
+ return true;
+ else if (nrvo_var == NULL)
+ {
+ if (!v->isDataseg() && !v->isParameter() && v->toParent2() == this)
+ {
+ //printf("Setting nrvo to %s\n", v->toChars());
+ nrvo_var = v;
+ }
+ else
+ return true;
+ }
+ else if (nrvo_var != v)
+ return true;
+ }
+ else //if (!exp->isLvalue()) // keep NRVO-ability
+ return true;
+ }
+ return false;
+}
+
const char *FuncDeclaration::kind() const
{
return generated ? "generated function" : "function";
diff --git a/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c
index 599c52e..9049347 100644
--- a/gcc/d/dmd/statementsem.c
+++ b/gcc/d/dmd/statementsem.c
@@ -2861,42 +2861,9 @@ public:
* return x; return 3; // ok, x can be a value
*/
}
-
- // handle NRVO
- if (fd->nrvo_can && rs->exp->op == TOKvar)
- {
- VarExp *ve = (VarExp *)rs->exp;
- VarDeclaration *v = ve->var->isVarDeclaration();
-
- if (tf->isref)
- {
- // Function returns a reference
- if (!inferRef)
- fd->nrvo_can = 0;
- }
- else if (!v || v->isOut() || v->isRef())
- fd->nrvo_can = 0;
- else if (fd->nrvo_var == NULL)
- {
- if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
- {
- //printf("Setting nrvo to %s\n", v->toChars());
- fd->nrvo_var = v;
- }
- else
- fd->nrvo_can = 0;
- }
- else if (fd->nrvo_var != v)
- fd->nrvo_can = 0;
- }
- else //if (!exp->isLvalue()) // keep NRVO-ability
- fd->nrvo_can = 0;
}
else
{
- // handle NRVO
- fd->nrvo_can = 0;
-
// infer return type
if (fd->inferRetType)
{