aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaInit.cpp22
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p16-cxx0x-no-extra-copy.cpp3
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp16
3 files changed, 33 insertions, 8 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 59f4393e55..7929b588b6 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -3264,10 +3264,26 @@ static Sema::OwningExprResult CopyObject(Sema &S,
if (IsExtraneousCopy) {
// If this is a totally extraneous copy for C++03 reference
// binding purposes, just return the original initialization
- // expression.
+ // expression. We don't generate an (elided) copy operation here
+ // because doing so would require us to pass down a flag to avoid
+ // infinite recursion, where each step adds another extraneous,
+ // elidable copy.
+
+ // Instantiate the default arguments of any extra parameters in
+ // the selected copy constructor, as if we were going to create a
+ // proper call to the copy constructor.
+ for (unsigned I = 1, N = Constructor->getNumParams(); I != N; ++I) {
+ ParmVarDecl *Parm = Constructor->getParamDecl(I);
+ if (S.RequireCompleteType(Loc, Parm->getType(),
+ S.PDiag(diag::err_call_incomplete_argument)))
+ break;
+
+ // Build the default argument expression; we don't actually care
+ // if this succeeds or not, because this routine will complain
+ // if there was a problem.
+ S.BuildCXXDefaultArgExpr(Loc, Constructor, Parm);
+ }
- // FIXME: We'd like to call CompleteConstructorCall below, so that
- // we instantiate default arguments and such.
return S.Owned(CurInitExpr);
}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p16-cxx0x-no-extra-copy.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p16-cxx0x-no-extra-copy.cpp
index 38bf9f7143..5a342d423a 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p16-cxx0x-no-extra-copy.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p16-cxx0x-no-extra-copy.cpp
@@ -27,8 +27,7 @@ private:
template<typename T>
T get_value_badly() {
double *dp = 0;
- T *tp = dp; // FIXME: Should get an error here, from instantiating the
- // default argument of X4<int>
+ T *tp = dp;
return T();
}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
index 5dd6861357..16394110d0 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
@@ -24,28 +24,38 @@ private:
X3(X3&); // expected-note{{candidate constructor not viable: no known conversion from 'X3' to 'X3 &' for 1st argument}}
};
+// Check for instantiation of default arguments
template<typename T>
T get_value_badly() {
double *dp = 0;
- T *tp = dp; // FIXME: Should get an error here, from instantiating the
- // default argument of X4<int>
+ T *tp = dp; // expected-error{{ cannot initialize a variable of type 'int *' with an lvalue of type 'double *'}}
return T();
}
template<typename T>
struct X4 {
X4();
- X4(const X4&, T = get_value_badly<T>());
+ X4(const X4&, T = get_value_badly<T>()); // expected-note{{in instantiation of}}
+};
+
+// Check for "dangerous" default arguments that could cause recursion.
+struct X5 {
+ X5();
+ X5(const X5&, const X5& = X5()); // expected-error{{no viable constructor copying parameter of type 'X5'}}
};
void g1(const X1&);
void g2(const X2&);
void g3(const X3&);
void g4(const X4<int>&);
+void g5(const X5&);
void test() {
g1(X1()); // expected-error{{no viable constructor copying parameter of type 'X1'}}
g2(X2()); // expected-error{{calling a private constructor of class 'X2'}}
g3(X3()); // expected-error{{no viable constructor copying parameter of type 'X3'}}
g4(X4<int>());
+ g5(X5()); // expected-error{{no viable constructor copying parameter of type 'X5'}}
}
+
+// Check for dangerous recursion in default arguments.