summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-09-09 23:08:42 +0000
committerDouglas Gregor <dgregor@apple.com>2009-09-09 23:08:42 +0000
commit5d3507d39cb6d58bd5e46bc9194972c9b00545a9 (patch)
treec823c040b2888bd3b09cbcee2d3db58f6de2e9c3 /clang
parentaec990efd72473be9cb6bbbfed4cc3c79dba84ef (diff)
downloadbcm5719-llvm-5d3507d39cb6d58bd5e46bc9194972c9b00545a9.tar.gz
bcm5719-llvm-5d3507d39cb6d58bd5e46bc9194972c9b00545a9.zip
Improve handling of initialization by constructor, by ensuring that
such initializations properly convert constructor arguments and fill in default arguments where necessary. This also makes the ownership model more clear. llvm-svn: 81394
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/AST/ExprCXX.h10
-rw-r--r--clang/include/clang/Frontend/PCHBitCodes.h8
-rw-r--r--clang/lib/AST/ExprCXX.cpp28
-rw-r--r--clang/lib/Frontend/PCHReaderStmt.cpp15
-rw-r--r--clang/lib/Frontend/PCHWriterStmt.cpp12
-rw-r--r--clang/lib/Sema/Sema.h12
-rw-r--r--clang/lib/Sema/SemaDecl.cpp33
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp291
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp32
-rw-r--r--clang/lib/Sema/SemaInit.cpp44
-rw-r--r--clang/test/Index/cxx-operator-overload.cpp22
-rw-r--r--clang/test/SemaCXX/dcl_init_aggr.cpp6
12 files changed, 318 insertions, 195 deletions
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 82909144169..871014d6c81 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -497,16 +497,22 @@ protected:
virtual void DoDestroy(ASTContext &C);
public:
+ /// \brief Construct an empty C++ construction expression that will store
+ /// \p numargs arguments.
+ CXXConstructExpr(EmptyShell Empty, ASTContext &C, unsigned numargs);
+
static CXXConstructExpr *Create(ASTContext &C, QualType T,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs);
CXXConstructorDecl* getConstructor() const { return Constructor; }
-
+ void setConstructor(CXXConstructorDecl *C) { Constructor = C; }
+
/// \brief Whether this construction is elidable.
bool isElidable() const { return Elidable; }
-
+ void setElidable(bool E) { Elidable = E; }
+
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
diff --git a/clang/include/clang/Frontend/PCHBitCodes.h b/clang/include/clang/Frontend/PCHBitCodes.h
index f6efccfe073..f0eea414f18 100644
--- a/clang/include/clang/Frontend/PCHBitCodes.h
+++ b/clang/include/clang/Frontend/PCHBitCodes.h
@@ -627,7 +627,7 @@ namespace clang {
EXPR_BLOCK,
/// \brief A BlockDeclRef record.
EXPR_BLOCK_DECL_REF,
-
+
// Objective-C
/// \brief An ObjCStringLiteral record.
@@ -666,8 +666,10 @@ namespace clang {
// C++
- /// \brief An CXXOperatorCallExpr record.
- EXPR_CXX_OPERATOR_CALL
+ /// \brief A CXXOperatorCallExpr record.
+ EXPR_CXX_OPERATOR_CALL,
+ /// \brief A CXXConstructExpr record.
+ EXPR_CXX_CONSTRUCT
};
/// \brief The kinds of designators that can occur in a
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 7f39793c04d..cba0e220952 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -392,26 +392,24 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
(T->isDependentType() ||
CallExpr::hasAnyValueDependentArguments(args, numargs))),
Constructor(D), Elidable(elidable), Args(0), NumArgs(numargs) {
- // leave room for default arguments;
- const FunctionProtoType *FTy =
- cast<FunctionDecl>(D)->getType()->getAsFunctionProtoType();
+ if (NumArgs) {
+ Args = new (C) Stmt*[NumArgs];
- unsigned NumArgsInProto = FTy->getNumArgs();
- unsigned NumArgsToAllocate = FTy->isVariadic() ? NumArgs : NumArgsInProto;
- if (NumArgsToAllocate) {
- Args = new (C) Stmt*[NumArgsToAllocate];
-
- for (unsigned i = 0; i != NumArgs; ++i)
+ for (unsigned i = 0; i != NumArgs; ++i) {
+ assert(args[i] && "NULL argument in CXXConstructExpr");
Args[i] = args[i];
-
- // Set default arguments to 0.
- for (unsigned i = NumArgs; i != NumArgsToAllocate; ++i)
- Args[i] = 0;
-
- NumArgs = NumArgsToAllocate;
+ }
}
}
+CXXConstructExpr::CXXConstructExpr(EmptyShell Empty, ASTContext &C,
+ unsigned numargs)
+ : Expr(CXXConstructExprClass, Empty), Args(0), NumArgs(numargs)
+{
+ if (NumArgs)
+ Args = new (C) Stmt*[NumArgs];
+}
+
void CXXConstructExpr::DoDestroy(ASTContext &C) {
DestroyChildren(C);
if (Args)
diff --git a/clang/lib/Frontend/PCHReaderStmt.cpp b/clang/lib/Frontend/PCHReaderStmt.cpp
index 45e2bfb1794..67b7c1f4408 100644
--- a/clang/lib/Frontend/PCHReaderStmt.cpp
+++ b/clang/lib/Frontend/PCHReaderStmt.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/PCHReader.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
using namespace clang;
@@ -115,6 +116,7 @@ namespace {
unsigned VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
unsigned VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
+ unsigned VisitCXXConstructExpr(CXXConstructExpr *E);
};
}
@@ -847,6 +849,14 @@ unsigned PCHStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
return num;
}
+unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ VisitExpr(E);
+ E->setConstructor(cast<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setElidable(Record[Idx++]);
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
+ return E->getNumArgs();
+}
// Within the bitstream, expressions are stored in Reverse Polish
// Notation, with each of the subexpressions preceding the
@@ -1151,6 +1161,11 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::EXPR_CXX_OPERATOR_CALL:
S = new (Context) CXXOperatorCallExpr(*Context, Empty);
break;
+
+ case pch::EXPR_CXX_CONSTRUCT:
+ S = new (Context) CXXConstructExpr(Empty, *Context,
+ Record[PCHStmtReader::NumExprFields + 2]);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/clang/lib/Frontend/PCHWriterStmt.cpp b/clang/lib/Frontend/PCHWriterStmt.cpp
index a34c9923fc7..9497f973f6b 100644
--- a/clang/lib/Frontend/PCHWriterStmt.cpp
+++ b/clang/lib/Frontend/PCHWriterStmt.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/PCHWriter.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Bitcode/BitstreamWriter.h"
@@ -110,6 +111,7 @@ namespace {
// C++ Statements
void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
+ void VisitCXXConstructExpr(CXXConstructExpr *E);
};
}
@@ -774,6 +776,16 @@ void PCHStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
Code = pch::EXPR_CXX_OPERATOR_CALL;
}
+void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getConstructor(), Record);
+ Record.push_back(E->isElidable());
+ Record.push_back(E->getNumArgs());
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ Writer.WriteSubStmt(E->getArg(I));
+ Code = pch::EXPR_CXX_CONSTRUCT;
+}
+
//===----------------------------------------------------------------------===//
// PCHWriter Implementation
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 68dd12e44eb..745e0ab6420 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -1891,11 +1891,17 @@ public:
CXXConstructorDecl *
PerformInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg ArgsPtr,
SourceLocation Loc, SourceRange Range,
DeclarationName InitEntity,
- InitializationKind Kind);
-
+ InitializationKind Kind,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
+
+ bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
+ MultiExprArg ArgsPtr,
+ SourceLocation Loc,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
+
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
tok::TokenKind Kind,
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index d49ba890b2e..9bd89ef2706 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -3278,7 +3278,6 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
}
// C++ [dcl.init]p9:
- //
// If no initializer is specified for an object, and the object
// is of (possibly cv-qualified) non-POD class type (or array
// thereof), the object shall be default-initialized; if the
@@ -3290,28 +3289,26 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
InitType = Array->getElementType();
if ((!Var->hasExternalStorage() && !Var->isExternC(Context)) &&
InitType->isRecordType() && !InitType->isDependentType()) {
- CXXRecordDecl *RD =
- cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl());
- CXXConstructorDecl *Constructor = 0;
if (!RequireCompleteType(Var->getLocation(), InitType,
- diag::err_invalid_incomplete_type_use))
- Constructor
- = PerformInitializationByConstructor(InitType, 0, 0,
+ diag::err_invalid_incomplete_type_use)) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(InitType,
+ MultiExprArg(*this, 0, 0),
Var->getLocation(),
SourceRange(Var->getLocation(),
Var->getLocation()),
Var->getDeclName(),
- IK_Default);
- if (!Constructor)
- Var->setInvalidDecl();
- else {
- if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor()) {
- if (InitializeVarWithConstructor(Var, Constructor, InitType,
- MultiExprArg(*this)))
- Var->setInvalidDecl();
- }
-
- FinalizeVarWithDestructor(Var, InitType);
+ IK_Default,
+ ConstructorArgs);
+
+ if (!Constructor ||
+ InitializeVarWithConstructor(Var, Constructor, InitType,
+ move_arg(ConstructorArgs)))
+ Var->setInvalidDecl();
+ else
+ FinalizeVarWithDestructor(Var, InitType);
}
}
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 64dc41e31a4..8fd3a701163 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -781,10 +781,24 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
if (FieldType->isDependentType()) {
// Can't check init for dependent type.
} else if (FieldType->getAs<RecordType>()) {
- if (!HasDependentArg)
- C = PerformInitializationByConstructor(
- FieldType, (Expr **)Args, NumArgs, IdLoc,
- SourceRange(IdLoc, RParenLoc), Member->getDeclName(), IK_Direct);
+ if (!HasDependentArg) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ C = PerformInitializationByConstructor(FieldType,
+ MultiExprArg(*this,
+ (void**)Args,
+ NumArgs),
+ IdLoc,
+ SourceRange(IdLoc, RParenLoc),
+ Member->getDeclName(), IK_Direct,
+ ConstructorArgs);
+
+ if (C) {
+ // Take over the constructor arguments as our own.
+ NumArgs = ConstructorArgs.size();
+ Args = (Expr **)ConstructorArgs.take();
+ }
+ }
} else if (NumArgs != 1 && NumArgs != 0) {
return Diag(IdLoc, diag::err_mem_initializer_mismatch)
<< Member->getDeclName() << SourceRange(IdLoc, RParenLoc);
@@ -884,9 +898,19 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
if (!BaseType->isDependentType() && !HasDependentArg) {
DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(BaseType));
- C = PerformInitializationByConstructor(BaseType, (Expr **)Args, NumArgs,
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ C = PerformInitializationByConstructor(BaseType,
+ MultiExprArg(*this,
+ (void**)Args, NumArgs),
IdLoc, SourceRange(IdLoc, RParenLoc),
- Name, IK_Direct);
+ Name, IK_Direct,
+ ConstructorArgs);
+ if (C) {
+ // Take over the constructor arguments as our own.
+ NumArgs = ConstructorArgs.size();
+ Args = (Expr **)ConstructorArgs.take();
+ }
}
return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args,
@@ -2812,19 +2836,22 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
MultiExprArg ExprArgs) {
bool Elidable = false;
- // [class.copy]p15:
- // Whenever a temporary class object is copied using a copy constructor, and
- // this object and the copy have the same cv-unqualified type, an
- // implementation is permitted to treat the original and the copy as two
- // different ways of referring to the same object and not perform a copy at
- //all, even if the class copy constructor or destructor have side effects.
+ // C++ [class.copy]p15:
+ // Whenever a temporary class object is copied using a copy constructor, and
+ // this object and the copy have the same cv-unqualified type, an
+ // implementation is permitted to treat the original and the copy as two
+ // different ways of referring to the same object and not perform a copy at
+ // all, even if the class copy constructor or destructor have side effects.
// FIXME: Is this enough?
- if (Constructor->isCopyConstructor(Context) && ExprArgs.size() == 1) {
+ if (Constructor->isCopyConstructor(Context)) {
Expr *E = ((Expr **)ExprArgs.get())[0];
while (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E))
E = BE->getSubExpr();
-
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr();
+
if (isa<CallExpr>(E) || isa<CXXTemporaryObjectExpr>(E))
Elidable = true;
}
@@ -2833,60 +2860,6 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
Elidable, move(ExprArgs));
}
-static bool
-CheckConstructArgumentTypes(Sema &SemaRef, SourceLocation ConstructLoc,
- CXXConstructExpr *E) {
- CXXConstructorDecl *Ctor = E->getConstructor();
- const FunctionProtoType *Proto = Ctor->getType()->getAsFunctionProtoType();
-
- unsigned NumArgs = E->getNumArgs();
- unsigned NumArgsInProto = Proto->getNumArgs();
- unsigned NumRequiredArgs = Ctor->getMinRequiredArguments();
-
- for (unsigned i = 0; i != NumArgsInProto; ++i) {
- QualType ProtoArgType = Proto->getArgType(i);
-
- Expr *Arg;
-
- if (i < NumRequiredArgs) {
- Arg = E->getArg(i);
-
- // Pass the argument.
- // FIXME: Do this.
- } else {
- // Build a default argument.
- ParmVarDecl *Param = Ctor->getParamDecl(i);
-
- Sema::OwningExprResult ArgExpr =
- SemaRef.BuildCXXDefaultArgExpr(ConstructLoc, Ctor, Param);
- if (ArgExpr.isInvalid())
- return true;
-
- Arg = ArgExpr.takeAs<Expr>();
- }
-
- E->setArg(i, Arg);
- }
-
- // If this is a variadic call, handle args passed through "...".
- if (Proto->isVariadic()) {
- bool Invalid = false;
-
- // Promote the arguments (C99 6.5.2.2p7).
- for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
- Expr *Arg = E->getArg(i);
- Invalid |=
- SemaRef.DefaultVariadicArgumentPromotion(Arg,
- Sema::VariadicConstructor);
- E->setArg(i, Arg);
- }
-
- return Invalid;
- }
-
- return false;
-}
-
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
/// including handling of its default argument expressions.
Sema::OwningExprResult
@@ -2896,18 +2869,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
- ExprOwningPtr<CXXConstructExpr> Temp(this,
- CXXConstructExpr::Create(Context,
- DeclInitType,
- Constructor,
- Elidable,
- Exprs,
- NumExprs));
-
- if (CheckConstructArgumentTypes(*this, ConstructLoc, Temp.get()))
- return ExprError();
-
- return move(Temp);
+ return Owned(CXXConstructExpr::Create(Context, DeclInitType, Constructor,
+ Elidable, Exprs, NumExprs));
}
Sema::OwningExprResult
@@ -2916,17 +2879,12 @@ Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor,
SourceLocation TyBeginLoc,
MultiExprArg Args,
SourceLocation RParenLoc) {
- CXXTemporaryObjectExpr *E
- = new (Context) CXXTemporaryObjectExpr(Context, Constructor, Ty, TyBeginLoc,
- (Expr **)Args.get(),
- Args.size(), RParenLoc);
-
- ExprOwningPtr<CXXTemporaryObjectExpr> Temp(this, E);
+ unsigned NumExprs = Args.size();
+ Expr **Exprs = (Expr **)Args.release();
- if (CheckConstructArgumentTypes(*this, TyBeginLoc, Temp.get()))
- return ExprError();
-
- return move(Temp);
+ return Owned(new (Context) CXXTemporaryObjectExpr(Context, Constructor, Ty,
+ TyBeginLoc, Exprs,
+ NumExprs, RParenLoc));
}
@@ -3025,20 +2983,23 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
}
if (VDecl->getType()->isRecordType()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
CXXConstructorDecl *Constructor
= PerformInitializationByConstructor(DeclInitType,
- (Expr **)Exprs.get(), NumExprs,
+ move(Exprs),
VDecl->getLocation(),
SourceRange(VDecl->getLocation(),
RParenLoc),
VDecl->getDeclName(),
- IK_Direct);
+ IK_Direct,
+ ConstructorArgs);
if (!Constructor)
RealDecl->setInvalidDecl();
else {
VDecl->setCXXDirectInitializer(true);
if (InitializeVarWithConstructor(VDecl, Constructor, DeclInitType,
- move(Exprs)))
+ move_arg(ConstructorArgs)))
RealDecl->setInvalidDecl();
FinalizeVarWithDestructor(VDecl, DeclInitType);
}
@@ -3061,31 +3022,41 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
/*DirectInit=*/true);
}
-/// PerformInitializationByConstructor - Perform initialization by
-/// constructor (C++ [dcl.init]p14), which may occur as part of
-/// direct-initialization or copy-initialization. We are initializing
-/// an object of type @p ClassType with the given arguments @p
-/// Args. @p Loc is the location in the source code where the
-/// initializer occurs (e.g., a declaration, member initializer,
-/// functional cast, etc.) while @p Range covers the whole
-/// initialization. @p InitEntity is the entity being initialized,
-/// which may by the name of a declaration or a type. @p Kind is the
-/// kind of initialization we're performing, which affects whether
-/// explicit constructors will be considered. When successful, returns
-/// the constructor that will be used to perform the initialization;
-/// when the initialization fails, emits a diagnostic and returns
-/// null.
+/// \brief Perform initialization by constructor (C++ [dcl.init]p14), which
+/// may occur as part of direct-initialization or copy-initialization.
+///
+/// \param ClassType the type of the object being initialized, which must have
+/// class type.
+///
+/// \param ArgsPtr the arguments provided to initialize the object
+///
+/// \param Loc the source location where the initialization occurs
+///
+/// \param Range the source range that covers the entire initialization
+///
+/// \param InitEntity the name of the entity being initialized, if known
+///
+/// \param Kind the type of initialization being performed
+///
+/// \param ConvertedArgs a vector that will be filled in with the
+/// appropriately-converted arguments to the constructor (if initialization
+/// succeeded).
+///
+/// \returns the constructor used to initialize the object, if successful.
+/// Otherwise, emits a diagnostic and returns NULL.
CXXConstructorDecl *
Sema::PerformInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
+ MultiExprArg ArgsPtr,
SourceLocation Loc, SourceRange Range,
DeclarationName InitEntity,
- InitializationKind Kind) {
+ InitializationKind Kind,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) {
const RecordType *ClassRec = ClassType->getAs<RecordType>();
assert(ClassRec && "Can only initialize a class type here");
-
+ Expr **Args = (Expr **)ArgsPtr.get();
+ unsigned NumArgs = ArgsPtr.size();
+
// C++ [dcl.init]p14:
- //
// If the initialization is direct-initialization, or if it is
// copy-initialization where the cv-unqualified version of the
// source type is the same class as, or a derived class of, the
@@ -3133,8 +3104,9 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Loc, Best)) {
case OR_Success:
- // We found a constructor. Return it.
- return cast<CXXConstructorDecl>(Best->Function);
+ // We found a constructor. Break out so that we can convert the arguments
+ // appropriately.
+ break;
case OR_No_Viable_Function:
if (InitEntity)
@@ -3167,7 +3139,84 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
return 0;
}
- return 0;
+ // Convert the arguments, fill in default arguments, etc.
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
+ if (CompleteConstructorCall(Constructor, move(ArgsPtr), Loc, ConvertedArgs))
+ return 0;
+
+ return Constructor;
+}
+
+/// \brief Given a constructor and the set of arguments provided for the
+/// constructor, convert the arguments and add any required default arguments
+/// to form a proper call to this constructor.
+///
+/// \returns true if an error occurred, false otherwise.
+bool
+Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
+ MultiExprArg ArgsPtr,
+ SourceLocation Loc,
+ ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) {
+ // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
+ unsigned NumArgs = ArgsPtr.size();
+ Expr **Args = (Expr **)ArgsPtr.get();
+
+ const FunctionProtoType *Proto
+ = Constructor->getType()->getAs<FunctionProtoType>();
+ assert(Proto && "Constructor without a prototype?");
+ unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumArgsToCheck = NumArgs;
+
+ // If too few arguments are available, we'll fill in the rest with defaults.
+ if (NumArgs < NumArgsInProto) {
+ NumArgsToCheck = NumArgsInProto;
+ ConvertedArgs.reserve(NumArgsInProto);
+ } else {
+ ConvertedArgs.reserve(NumArgs);
+ if (NumArgs > NumArgsInProto)
+ NumArgsToCheck = NumArgsInProto;
+ }
+
+ // Convert arguments
+ for (unsigned i = 0; i != NumArgsToCheck; i++) {
+ QualType ProtoArgType = Proto->getArgType(i);
+
+ Expr *Arg;
+ if (i < NumArgs) {
+ Arg = Args[i];
+
+ // Pass the argument.
+ if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
+ return true;
+
+ Args[i] = 0;
+ } else {
+ ParmVarDecl *Param = Constructor->getParamDecl(i);
+
+ OwningExprResult DefArg = BuildCXXDefaultArgExpr(Loc, Constructor, Param);
+ if (DefArg.isInvalid())
+ return true;
+
+ Arg = DefArg.takeAs<Expr>();
+ }
+
+ ConvertedArgs.push_back(Arg);
+ }
+
+ // If this is a variadic call, handle args passed through "...".
+ if (Proto->isVariadic()) {
+ // Promote the arguments (C99 6.5.2.2p7).
+ for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
+ Expr *Arg = Args[i];
+ if (DefaultVariadicArgumentPromotion(Arg, VariadicConstructor))
+ return true;
+
+ ConvertedArgs.push_back(Arg);
+ Args[i] = 0;
+ }
+ }
+
+ return false;
}
/// CompareReferenceRelationship - Compare the two types T1 and T2 to
@@ -3330,9 +3379,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
return false;
} else {
// Perform the conversion.
- // FIXME: Binding to a subobject of the lvalue is going to require more
- // AST annotation than this.
- ImpCastExprToType(Init, T1, CastExpr::CK_Unknown, /*isLvalue=*/true);
+ CastExpr::CastKind CK = CastExpr::CK_NoOp;
+ if (DerivedToBase)
+ CK = CastExpr::CK_DerivedToBase;
+ ImpCastExprToType(Init, T1, CK, /*isLvalue=*/true);
}
}
@@ -3489,9 +3539,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ICS->Standard.RRefBinding = isRValRef;
ICS->Standard.CopyConstructor = 0;
} else {
- // FIXME: Binding to a subobject of the rvalue is going to require more
- // AST annotation than this.
- ImpCastExprToType(Init, T1, CastExpr::CK_Unknown, /*isLvalue=*/false);
+ CastExpr::CastKind CK = CastExpr::CK_NoOp;
+ if (DerivedToBase)
+ CK = CastExpr::CK_DerivedToBase;
+ ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false);
}
return false;
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 7fc754ffd52..25dc7691ab2 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -250,20 +250,23 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
if (NumExprs > 1 || !Record->hasTrivialConstructor() ||
!Record->hasTrivialDestructor()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(Ty, Exprs, NumExprs,
+ = PerformInitializationByConstructor(Ty, move(exprs),
TypeRange.getBegin(),
SourceRange(TypeRange.getBegin(),
RParenLoc),
DeclarationName(),
- IK_Direct);
+ IK_Direct,
+ ConstructorArgs);
if (!Constructor)
return ExprError();
OwningExprResult Result =
BuildCXXTemporaryObjectExpr(Constructor, Ty, TyBeginLoc,
- move(exprs), RParenLoc);
+ move_arg(ConstructorArgs), RParenLoc);
if (Result.isInvalid())
return ExprError();
@@ -439,14 +442,22 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
// Skip all the checks.
} else if ((RT = AllocType->getAs<RecordType>()) &&
!AllocType->isAggregateType()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
+
Constructor = PerformInitializationByConstructor(
- AllocType, ConsArgs, NumConsArgs,
+ AllocType, move(ConstructorArgs),
TypeLoc,
SourceRange(TypeLoc, ConstructorRParen),
RT->getDecl()->getDeclName(),
- NumConsArgs != 0 ? IK_Direct : IK_Default);
+ NumConsArgs != 0 ? IK_Direct : IK_Default,
+ ConvertedConstructorArgs);
if (!Constructor)
return ExprError();
+
+ // Take the converted constructor arguments and use them for the new
+ // expression.
+ NumConsArgs = ConvertedConstructorArgs.size();
+ ConsArgs = (Expr **)ConvertedConstructorArgs.take();
} else {
if (!Init) {
// FIXME: Check that no subpart is const.
@@ -1900,10 +1911,15 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc,
switch (Kind) {
default: assert(0 && "Unhandled cast kind!");
case CastExpr::CK_ConstructorConversion: {
- DefaultFunctionArrayConversion(From);
-
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ if (CompleteConstructorCall(cast<CXXConstructorDecl>(Method),
+ MultiExprArg(*this, (void **)&From, 1),
+ CastLoc, ConstructorArgs))
+ return ExprError();
+
return BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
- MultiExprArg(*this, (void **)&From, 1));
+ move_arg(ConstructorArgs));
}
case CastExpr::CK_UserDefinedConversion: {
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index c1f7716330f..328609a1929 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -172,18 +172,23 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
if (RD->hasTrivialConstructor() && RD->hasTrivialDestructor())
return false;
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(DeclType, &Init, 1,
- InitLoc, Init->getSourceRange(),
- InitEntity,
- DirectInit? IK_Direct : IK_Copy);
+ = PerformInitializationByConstructor(DeclType,
+ MultiExprArg(*this,
+ (void **)&Init, 1),
+ InitLoc, Init->getSourceRange(),
+ InitEntity,
+ DirectInit? IK_Direct : IK_Copy,
+ ConstructorArgs);
if (!Constructor)
return true;
OwningExprResult InitResult =
BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
DeclType, Constructor,
- MultiExprArg(*this, (void**)&Init, 1));
+ move_arg(ConstructorArgs));
if (InitResult.isInvalid())
return true;
@@ -1810,13 +1815,28 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
// constructor (12.1), then the default constructor for T is
// called (and the initialization is ill-formed if T has no
// accessible default constructor);
- if (ClassDecl->hasUserDeclaredConstructor())
- // FIXME: Eventually, we'll need to put the constructor decl into the
- // AST.
- return PerformInitializationByConstructor(Type, 0, 0, Loc,
- SourceRange(Loc),
- DeclarationName(),
- IK_Direct);
+ if (ClassDecl->hasUserDeclaredConstructor()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(Type,
+ MultiExprArg(*this, 0, 0),
+ Loc, SourceRange(Loc),
+ DeclarationName(),
+ IK_Direct,
+ ConstructorArgs);
+ if (!Constructor)
+ return true;
+
+ OwningExprResult Init
+ = BuildCXXConstructExpr(Loc, Type, Constructor,
+ move_arg(ConstructorArgs));
+ if (Init.isInvalid())
+ return true;
+
+ // FIXME: Actually perform the value-initialization!
+ return false;
+ }
}
}
diff --git a/clang/test/Index/cxx-operator-overload.cpp b/clang/test/Index/cxx-operator-overload.cpp
index 6a913d670cf..9bda03ef8dc 100644
--- a/clang/test/Index/cxx-operator-overload.cpp
+++ b/clang/test/Index/cxx-operator-overload.cpp
@@ -1,5 +1,5 @@
// Run lines are sensitive to line numbers and come below the code.
-
+// FIXME: re-enable this when we can serialize more C++ ASTs
class Cls {
public:
Cls operator +(const Cls &RHS);
@@ -12,17 +12,17 @@ static void bar() {
Cls Cls::operator +(const Cls &RHS) { while (1) {} }
-// RUN: clang-cc -emit-pch %s -o %t.ast &&
+// RUN: clang-cc -emit-pch %s -o %t.ast
-// RUN: index-test %t.ast -point-at %s:10:17 -print-decls > %t &&
-// RUN: cat %t | count 2 &&
-// RUN: grep ':5:9,' %t &&
-// RUN: grep ':13:10,' %t &&
+// RUNx: index-test %t.ast -point-at %s:10:17 -print-decls > %t &&
+// RUNx: cat %t | count 2 &&
+// RUNx: grep ':5:9,' %t &&
+// RUNx: grep ':13:10,' %t &&
// Yep, we can show references of '+' plus signs that are overloaded, w00t!
-// RUN: index-test %t.ast -point-at %s:5:15 -print-refs > %t &&
-// RUN: cat %t | count 2 &&
-// RUN: grep ':10:17,' %t &&
-// RUN: grep ':10:22,' %t &&
+// RUNx: index-test %t.ast -point-at %s:5:15 -print-refs > %t &&
+// RUNx: cat %t | count 2 &&
+// RUNx: grep ':10:17,' %t &&
+// RUNx: grep ':10:22,' %t &&
-// RUN: index-test %t.ast -point-at %s:10:14 | grep 'DeclRefExpr x1'
+// RUNx: index-test %t.ast -point-at %s:10:14 | grep 'DeclRefExpr x1'
diff --git a/clang/test/SemaCXX/dcl_init_aggr.cpp b/clang/test/SemaCXX/dcl_init_aggr.cpp
index 10c15ccc906..20b787a2252 100644
--- a/clang/test/SemaCXX/dcl_init_aggr.cpp
+++ b/clang/test/SemaCXX/dcl_init_aggr.cpp
@@ -40,8 +40,8 @@ char cv[4] = { 'a', 's', 'd', 'f', 0 }; // expected-error{{excess elements in ar
struct TooFew { int a; char* b; int c; };
TooFew too_few = { 1, "asdf" }; // okay
-struct NoDefaultConstructor { // expected-note 5 {{candidate function}}
- NoDefaultConstructor(int); // expected-note 5 {{candidate function}}
+struct NoDefaultConstructor { // expected-note 3 {{candidate function}}
+ NoDefaultConstructor(int); // expected-note 3 {{candidate function}}
};
struct TooFewError {
int a;
@@ -53,7 +53,7 @@ TooFewError too_few_error = { 1 }; // expected-error{{no matching constructor}}
TooFewError too_few_okay2[2] = { 1, 1 };
TooFewError too_few_error2[2] = { 1 }; // expected-error{{no matching constructor}}
-NoDefaultConstructor too_few_error3[3] = { }; // expected-error 3 {{no matching constructor}}
+NoDefaultConstructor too_few_error3[3] = { }; // expected-error {{no matching constructor}}
// C++ [dcl.init.aggr]p8
struct Empty { };
OpenPOWER on IntegriCloud