aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td15
-rw-r--r--lib/CodeGen/CGCXX.cpp9
-rw-r--r--lib/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaDeclCXX.cpp3
-rw-r--r--lib/Sema/SemaExprCXX.cpp2
-rw-r--r--lib/Sema/SemaInit.cpp299
-rw-r--r--lib/Sema/SemaInit.h31
-rw-r--r--lib/Sema/SemaStmt.cpp48
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp4
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp2
-rw-r--r--test/CodeGenCXX/temporaries.cpp14
-rw-r--r--test/SemaCXX/conversion-function.cpp14
-rw-r--r--test/SemaCXX/decl-init-ref.cpp2
-rw-r--r--test/SemaCXX/ref-init-ambiguous.cpp7
-rw-r--r--test/SemaCXX/rval-references-xfail.cpp14
-rw-r--r--test/SemaCXX/rval-references.cpp14
-rw-r--r--test/SemaTemplate/class-template-id.cpp6
-rw-r--r--test/SemaTemplate/constructor-template.cpp8
-rw-r--r--test/SemaTemplate/instantiate-expr-4.cpp2
-rw-r--r--test/SemaTemplate/instantiate-function-1.cpp2
-rw-r--r--test/SemaTemplate/instantiate-member-template.cpp4
-rw-r--r--test/SemaTemplate/instantiate-typedef.cpp2
22 files changed, 427 insertions, 78 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 9123c345c7..b9c1897a1e 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -527,6 +527,11 @@ def err_destructor_name : Error<
"expected the class name after '~' to name the enclosing class">;
// C++ initialization
+def err_init_conversion_failed : Error<
+ "cannot initialize %select{a variable|a parameter|return object|an "
+ "exception object|a value|a base class|a member subobject|an array element}0"
+ " of type %1 with an %select{rvalue|lvalue}2 of type %3">;
+
def err_lvalue_to_rvalue_ref : Error<"rvalue reference cannot bind to lvalue">;
def err_invalid_initialization : Error<
"invalid initialization of reference of type %0 from expression of type %1">;
@@ -572,6 +577,16 @@ def note_uninit_reference_member : Note<
def warn_field_is_uninit : Warning<"field is uninitialized when used here">,
InGroup<DiagGroup<"uninitialized">>;
+def err_temp_copy_no_viable : Error<
+ "no viable copy constructor %select{throwing|returning}0 object of type %1">;
+def err_temp_copy_ambiguous : Error<
+ "ambiguous copy constructor call when %select{throwing|returning}0 object of "
+ "type %1">;
+def err_temp_copy_deleted : Error<
+ "%select{throwing|returning}0 object of type %1 invokes deleted copy "
+ "constructor">;
+
+
// C++0x decltype
def err_cannot_determine_declared_type_of_overloaded_function : Error<
"can't determine the declared type of an overloaded function">;
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index e1a5004c91..21f3e00ac0 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -577,9 +577,12 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
// its first argument instead.
if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
const Expr *Arg = E->getArg(0);
-
- if (const CXXBindTemporaryExpr *BindExpr =
- dyn_cast<CXXBindTemporaryExpr>(Arg))
+
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+ if (isa<CXXBindTemporaryExpr>(ICE->getSubExpr()))
+ Arg = cast<CXXBindTemporaryExpr>(ICE->getSubExpr())->getSubExpr();
+ } else if (const CXXBindTemporaryExpr *BindExpr =
+ dyn_cast<CXXBindTemporaryExpr>(Arg))
Arg = BindExpr->getSubExpr();
EmitAggExpr(Arg, Dest, false);
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3d03dfd8ce..9d40a13786 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -935,6 +935,9 @@ public:
bool PerformCopyInitialization(Expr *&From, QualType ToType,
AssignmentAction Action, bool Elidable = false);
+ OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity,
+ SourceLocation EqualLoc,
+ OwningExprResult Init);
ImplicitConversionSequence
TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method,
CXXRecordDecl *ActingContext);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index afddd9f02c..565fce8b5f 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3776,6 +3776,9 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
// FIXME: Is this enough?
if (Constructor->isCopyConstructor(Context)) {
Expr *E = ((Expr **)ExprArgs.get())[0];
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr();
while (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E))
E = BE->getSubExpr();
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 9108137a00..7c4ab890d0 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -450,7 +450,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
TypeSourceInfo *TInfo
= Context.getTrivialTypeSourceInfo(AllocType, TypeLoc);
InitializedEntity Entity
- = InitializedEntity::InitializeTemporary(TInfo->getTypeLoc());
+ = InitializedEntity::InitializeNew(StartLoc, TInfo->getTypeLoc());
InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs);
if (!InitSeq) {
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 629ab9adb3..60de672c0a 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2003,6 +2003,7 @@ DeclarationName InitializedEntity::getName() const {
case EK_Result:
case EK_Exception:
+ case EK_New:
case EK_Temporary:
case EK_Base:
case EK_ArrayOrVectorElement:
@@ -2030,6 +2031,7 @@ void InitializationSequence::Step::Destroy() {
case SK_ListInitialization:
case SK_ConstructorInitialization:
case SK_ZeroInitialization:
+ case SK_CAssignment:
break;
case SK_ConversionSequence:
@@ -2115,6 +2117,13 @@ void InitializationSequence::AddZeroInitializationStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddCAssignmentStep(QualType T) {
+ Step S;
+ S.Kind = SK_CAssignment;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
OverloadingResult Result) {
SequenceKind = FailedSequence;
@@ -2496,7 +2505,12 @@ static void TryReferenceInitialization(Sema &S,
// this into an overloading ambiguity diagnostic. However, we need
// to keep that set as an OverloadCandidateSet rather than as some
// other kind of set.
- Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
+ if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_ReferenceInitOverloadFailed,
+ ConvOvlResult);
+ else
+ Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
return;
}
@@ -2534,7 +2548,10 @@ static void TryConstructorInitialization(Sema &S,
Expr **Args, unsigned NumArgs,
QualType DestType,
InitializationSequence &Sequence) {
- Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
+ if (Kind.getKind() == InitializationKind::IK_Copy)
+ Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion);
+ else
+ Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
@@ -2594,9 +2611,13 @@ static void TryConstructorInitialization(Sema &S,
// Add the constructor initialization step. Any cv-qualification conversion is
// subsumed by the initialization.
- Sequence.AddConstructorInitializationStep(
+ if (Kind.getKind() == InitializationKind::IK_Copy) {
+ Sequence.AddUserConversionStep(Best->Function, DestType);
+ } else {
+ Sequence.AddConstructorInitializationStep(
cast<CXXConstructorDecl>(Best->Function),
- DestType);
+ DestType);
+ }
}
/// \brief Attempt value initialization (C++ [dcl.init]p7).
@@ -2898,6 +2919,13 @@ InitializationSequence::InitializationSequence(Sema &S,
TryDefaultInitialization(S, Entity, Kind, *this);
return;
}
+
+ // Handle initialization in C
+ if (!S.getLangOptions().CPlusPlus) {
+ setSequenceKind(CAssignment);
+ AddCAssignmentStep(DestType);
+ return;
+ }
// - Otherwise, if the destination type is an array, the program is
// ill-formed.
@@ -2965,6 +2993,151 @@ InitializationSequence::~InitializationSequence() {
//===----------------------------------------------------------------------===//
// Perform initialization
//===----------------------------------------------------------------------===//
+static Sema::AssignmentAction
+getAssignmentAction(const InitializedEntity &Entity) {
+ switch(Entity.getKind()) {
+ case InitializedEntity::EK_Variable:
+ case InitializedEntity::EK_New:
+ return Sema::AA_Initializing;
+
+ case InitializedEntity::EK_Parameter:
+ // FIXME: Can we tell when we're sending vs. passing?
+ return Sema::AA_Passing;
+
+ case InitializedEntity::EK_Result:
+ return Sema::AA_Returning;
+
+ case InitializedEntity::EK_Exception:
+ case InitializedEntity::EK_Base:
+ llvm_unreachable("No assignment action for C++-specific initialization");
+ break;
+
+ case InitializedEntity::EK_Temporary:
+ // FIXME: Can we tell apart casting vs. converting?
+ return Sema::AA_Casting;
+
+ case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_ArrayOrVectorElement:
+ return Sema::AA_Initializing;
+ }
+
+ return Sema::AA_Converting;
+}
+
+static bool shouldBindAsTemporary(const InitializedEntity &Entity,
+ bool IsCopy) {
+ switch (Entity.getKind()) {
+ case InitializedEntity::EK_Result:
+ case InitializedEntity::EK_Exception:
+ return !IsCopy;
+
+ case InitializedEntity::EK_New:
+ case InitializedEntity::EK_Variable:
+ case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_ArrayOrVectorElement:
+ return false;
+
+ case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Temporary:
+ return true;
+ }
+
+ llvm_unreachable("missed an InitializedEntity kind?");
+}
+
+/// \brief If we need to perform an additional copy of the initialized object
+/// for this kind of entity (e.g., the result of a function or an object being
+/// thrown), make the copy.
+static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
+ const InitializedEntity &Entity,
+ Sema::OwningExprResult CurInit) {
+ SourceLocation Loc;
+ bool isReturn = false;
+
+ switch (Entity.getKind()) {
+ case InitializedEntity::EK_Result:
+ if (Entity.getType().getType()->isReferenceType())
+ return move(CurInit);
+ isReturn = true;
+ Loc = Entity.getReturnLoc();
+ break;
+
+ case InitializedEntity::EK_Exception:
+ isReturn = false;
+ Loc = Entity.getThrowLoc();
+ break;
+
+ case InitializedEntity::EK_Variable:
+ case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_New:
+ case InitializedEntity::EK_Temporary:
+ case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_ArrayOrVectorElement:
+ // We don't need to copy for any of these initialized entities.
+ return move(CurInit);
+ }
+
+ Expr *CurInitExpr = (Expr *)CurInit.get();
+ CXXRecordDecl *Class = 0;
+ if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>())
+ Class = cast<CXXRecordDecl>(Record->getDecl());
+ if (!Class)
+ return move(CurInit);
+
+ // Perform overload resolution using the class's copy constructors.
+ DeclarationName ConstructorName
+ = S.Context.DeclarationNames.getCXXConstructorName(
+ S.Context.getCanonicalType(S.Context.getTypeDeclType(Class)));
+ DeclContext::lookup_iterator Con, ConEnd;
+ OverloadCandidateSet CandidateSet;
+ for (llvm::tie(Con, ConEnd) = Class->lookup(ConstructorName);
+ Con != ConEnd; ++Con) {
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con);
+ if (!Constructor || Constructor->isInvalidDecl() ||
+ !Constructor->isCopyConstructor(S.Context))
+ continue;
+
+ S.AddOverloadCandidate(Constructor, &CurInitExpr, 1, CandidateSet);
+ }
+
+ OverloadCandidateSet::iterator Best;
+ switch (S.BestViableFunction(CandidateSet, Loc, Best)) {
+ case OR_Success:
+ break;
+
+ case OR_No_Viable_Function:
+ S.Diag(Loc, diag::err_temp_copy_no_viable)
+ << isReturn << CurInitExpr->getType()
+ << CurInitExpr->getSourceRange();
+ S.PrintOverloadCandidates(CandidateSet, false);
+ return S.ExprError();
+
+ case OR_Ambiguous:
+ S.Diag(Loc, diag::err_temp_copy_ambiguous)
+ << isReturn << CurInitExpr->getType()
+ << CurInitExpr->getSourceRange();
+ S.PrintOverloadCandidates(CandidateSet, true);
+ return S.ExprError();
+
+ case OR_Deleted:
+ S.Diag(Loc, diag::err_temp_copy_deleted)
+ << isReturn << CurInitExpr->getType()
+ << CurInitExpr->getSourceRange();
+ S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
+ << Best->Function->isDeleted();
+ return S.ExprError();
+ }
+
+ CurInit.release();
+ return S.BuildCXXConstructExpr(Loc, CurInitExpr->getType(),
+ cast<CXXConstructorDecl>(Best->Function),
+ /*Elidable=*/true,
+ Sema::MultiExprArg(S,
+ (void**)&CurInitExpr, 1));
+}
Action::OwningExprResult
InitializationSequence::Perform(Sema &S,
@@ -3040,26 +3213,26 @@ InitializationSequence::Perform(Sema &S,
// grab the only argument out the Args and place it into the "current"
// initializer.
switch (Steps.front().Kind) {
- case SK_ResolveAddressOfOverloadedFunction:
- case SK_CastDerivedToBaseRValue:
- case SK_CastDerivedToBaseLValue:
- case SK_BindReference:
- case SK_BindReferenceToTemporary:
- case SK_UserConversion:
- case SK_QualificationConversionLValue:
- case SK_QualificationConversionRValue:
- case SK_ConversionSequence:
- case SK_ListInitialization:
- assert(Args.size() == 1);
- CurInit = Sema::OwningExprResult(S,
- ((Expr **)(Args.get()))[0]->Retain());
- if (CurInit.isInvalid())
- return S.ExprError();
- break;
-
- case SK_ConstructorInitialization:
- case SK_ZeroInitialization:
- break;
+ case SK_ResolveAddressOfOverloadedFunction:
+ case SK_CastDerivedToBaseRValue:
+ case SK_CastDerivedToBaseLValue:
+ case SK_BindReference:
+ case SK_BindReferenceToTemporary:
+ case SK_UserConversion:
+ case SK_QualificationConversionLValue:
+ case SK_QualificationConversionRValue:
+ case SK_ConversionSequence:
+ case SK_ListInitialization:
+ case SK_CAssignment:
+ assert(Args.size() == 1);
+ CurInit = Sema::OwningExprResult(S, ((Expr **)(Args.get()))[0]->Retain());
+ if (CurInit.isInvalid())
+ return S.ExprError();
+ break;
+
+ case SK_ConstructorInitialization:
+ case SK_ZeroInitialization:
+ break;
}
// Walk through the computed steps for the initialization sequence,
@@ -3131,6 +3304,7 @@ InitializationSequence::Perform(Sema &S,
// We have a user-defined conversion that invokes either a constructor
// or a conversion function.
CastExpr::CastKind CastKind = CastExpr::CK_Unknown;
+ bool IsCopy = false;
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Step->Function)) {
// Build a call to the selected constructor.
@@ -3154,10 +3328,14 @@ InitializationSequence::Perform(Sema &S,
return S.ExprError();
CastKind = CastExpr::CK_ConstructorConversion;
+ QualType Class = S.Context.getTypeDeclType(Constructor->getParent());
+ if (S.Context.hasSameUnqualifiedType(SourceType, Class) ||
+ S.IsDerivedFrom(SourceType, Class))
+ IsCopy = true;
} else {
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Step->Function);
-
+
// FIXME: Should we move this initialization into a separate
// derived-to-base conversion? I believe the answer is "no", because
// we don't want to turn off access control here for c-style casts.
@@ -3176,12 +3354,17 @@ InitializationSequence::Perform(Sema &S,
CastKind = CastExpr::CK_UserDefinedConversion;
}
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ if (shouldBindAsTemporary(Entity, IsCopy))
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+
CurInitExpr = CurInit.takeAs<Expr>();
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(),
CastKind,
CurInitExpr,
- false));
+ false));
+
+ if (!IsCopy)
+ CurInit = CopyIfRequiredForEntity(S, Entity, move(CurInit));
break;
}
@@ -3235,7 +3418,14 @@ InitializationSequence::Perform(Sema &S,
ConstructorInitRequiresZeroInit);
if (CurInit.isInvalid())
return S.ExprError();
-
+
+ bool Elidable
+ = cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable();
+ if (shouldBindAsTemporary(Entity, Elidable))
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+
+ if (!Elidable)
+ CurInit = CopyIfRequiredForEntity(S, Entity, move(CurInit));
break;
}
@@ -3258,6 +3448,20 @@ InitializationSequence::Perform(Sema &S,
}
break;
}
+
+ case SK_CAssignment: {
+ QualType SourceType = CurInitExpr->getType();
+ Sema::AssignConvertType ConvTy =
+ S.CheckSingleAssignmentConstraints(Step->Type, CurInitExpr);
+ if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(),
+ Step->Type, SourceType,
+ CurInitExpr, getAssignmentAction(Entity)))
+ return S.ExprError();
+
+ CurInit.release();
+ CurInit = S.Owned(CurInitExpr);
+ break;
+ }
}
}
@@ -3297,9 +3501,15 @@ bool InitializationSequence::Diagnose(Sema &S,
case FK_UserConversionOverloadFailed:
switch (FailedOverloadResult) {
case OR_Ambiguous:
- S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
- << Args[0]->getType() << DestType.getNonReferenceType()
- << Args[0]->getSourceRange();
+ if (Failure == FK_UserConversionOverloadFailed)
+ S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
+ << Args[0]->getType() << DestType
+ << Args[0]->getSourceRange();
+ else
+ S.Diag(Kind.getLocation(), diag::err_ref_init_ambiguous)
+ << DestType << Args[0]->getType()
+ << Args[0]->getSourceRange();
+
S.PrintOverloadCandidates(FailedCandidateSet, true);
break;
@@ -3365,7 +3575,8 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
case FK_ConversionFailed:
- S.Diag(Kind.getLocation(), diag::err_cannot_initialize_decl_noname)
+ S.Diag(Kind.getLocation(), diag::err_init_conversion_failed)
+ << (int)Entity.getKind()
<< DestType
<< (Args[0]->isLvalue(S.Context) == Expr::LV_Valid)
<< Args[0]->getType()
@@ -3448,3 +3659,27 @@ bool InitializationSequence::Diagnose(Sema &S,
return true;
}
+
+//===----------------------------------------------------------------------===//
+// Initialization helper functions
+//===----------------------------------------------------------------------===//
+Sema::OwningExprResult
+Sema::PerformCopyInitialization(const InitializedEntity &Entity,
+ SourceLocation EqualLoc,
+ OwningExprResult Init) {
+ if (Init.isInvalid())
+ return ExprError();
+
+ Expr *InitE = (Expr *)Init.get();
+ assert(InitE && "No initialization expression?");
+
+ if (EqualLoc.isInvalid())
+ EqualLoc = InitE->getLocStart();
+
+ InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(),
+ EqualLoc);
+ InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
+ Init.release();
+ return Seq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, (void**)&InitE, 1));
+}
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index da6587bcca..c42badd3f8 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -47,6 +47,9 @@ public:
/// \brief The entity being initialized is an exception object that
/// is being thrown.
EK_Exception,
+ /// \brief The entity being initialized is an object (or array of
+ /// objects) allocated via new.
+ EK_New,
/// \brief The entity being initialized is a temporary object.
EK_Temporary,
/// \brief The entity being initialized is a base member subobject.
@@ -76,9 +79,10 @@ private:
/// the VarDecl, ParmVarDecl, or FieldDecl, respectively.
DeclaratorDecl *VariableOrMember;
- /// \brief When Kind == EK_Result or EK_Exception, the location of the
- /// 'return' or 'throw' keyword, respectively. When Kind == EK_Temporary,
- /// the location where the temporary is being created.
+ /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the
+ /// location of the 'return', 'throw', or 'new' keyword,
+ /// respectively. When Kind == EK_Temporary, the location where
+ /// the temporary is being created.
unsigned Location;
/// \brief When Kind == EK_Base, the base specifier that provides the
@@ -150,6 +154,11 @@ public:
TypeLoc TL) {
return InitializedEntity(EK_Exception, ThrowLoc, TL);
}
+
+ /// \brief Create the initialization entity for an object allocated via new.
+ static InitializedEntity InitializeNew(SourceLocation NewLoc, TypeLoc TL) {
+ return InitializedEntity(EK_New, NewLoc, TL);
+ }
/// \brief Create the initialization entity for a temporary.
static InitializedEntity InitializeTemporary(TypeLoc TL) {
@@ -373,7 +382,10 @@ public:
NoInitialization,
/// \brief Standard conversion sequence.
- StandardConversion
+ StandardConversion,
+
+ /// \brief C conversion sequence.
+ CAssignment
};
/// \brief Describes the kind of a particular step in an initialization
@@ -404,7 +416,9 @@ public:
/// \brief Perform initialization via a constructor.
SK_ConstructorInitialization,
/// \brief Zero-initialize the object
- SK_ZeroInitialization
+ SK_ZeroInitialization,
+ /// \brief C assignment
+ SK_CAssignment
};
/// \brief A single step in the initialization sequence.
@@ -607,6 +621,13 @@ public:
/// \brief Add a zero-initialization step.
void AddZeroInitializationStep(QualType T);
+ /// \brief Add a C assignment step.
+ //
+ // FIXME: It isn't clear whether this should ever be needed;
+ // ideally, we would handle everything needed in C in the common
+ // path. However, that isn't the case yet.
+ void AddCAssignmentStep(QualType T);
+
/// \brief Note that this initialization sequence failed.
void SetFailed(FailureKind Failure) {
SequenceKind = FailedSequence;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 10f0be6e67..e09243372e 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -1027,11 +1028,23 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
QualType FnRetType;
+ TypeLoc FnRetTypeLoc;
if (const FunctionDecl *FD = getCurFunctionDecl()) {
FnRetType = FD->getResultType();
if (FD->hasAttr<NoReturnAttr>())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
<< getCurFunctionOrMethodDecl()->getDeclName();
+
+#if 0
+ // FIXME: Useful, once we're sure it has all of the information we
+ // need.
+ if (TypeSourceInfo *TInfo = FD->getTypeSourceInfo()) {
+ TypeLoc TL = TInfo->getTypeLoc();
+ if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL))
+ FnRetTypeLoc = FTL->getResultLoc();
+ }
+#endif
+
} else if (ObjCMethodDecl *MD = getCurMethodDecl())
FnRetType = MD->getResultType();
else // If we don't have a function/method context, bail.
@@ -1092,17 +1105,40 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
bool Elidable = getLangOptions().CPlusPlus0x ?
IsReturnCopyElidable(Context, FnRetType, RetValExp) :
false;
+ // FIXME: Elidable
+ (void)Elidable;
+
+ // If we somehow didn't get a
+
+ // FIXME: Should we allocate the TypeSourceInfo and attach it to
+ // the declaration? Alternatively, we could require that all
+ // function and method declarations have TypeSourceInfos, so that
+ // this is never required. FIXME: Also, the allocated TInfo goes
+ // into the bump pointer, so it cannot actually be freed.
+ TypeSourceInfo *AllocatedTInfo = 0;
+ if (!FnRetTypeLoc) {
+ const FunctionDecl *FD = getCurFunctionDecl();
+ SourceLocation Loc = FD? FD->getLocation()
+ : getCurMethodDecl()->getLocation();
+ AllocatedTInfo = Context.getTrivialTypeSourceInfo(FnRetType, Loc);
+ FnRetTypeLoc = AllocatedTInfo->getTypeLoc();
+ }
// In C++ the return statement is handled via a copy initialization.
// the C version of which boils down to CheckSingleAssignmentConstraints.
- // FIXME: Leaks RetValExp on error.
- if (PerformCopyInitialization(RetValExp, FnRetType, AA_Returning, Elidable)){
- // We should still clean up our temporaries, even when we're failing!
- RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
+ rex = PerformCopyInitialization(
+ InitializedEntity::InitializeResult(ReturnLoc,
+ FnRetTypeLoc),
+ SourceLocation(),
+ Owned(RetValExp));
+ if (rex.isInvalid()) {
+ // FIXME: Cleanup temporaries here, anyway?
return StmtError();
}
-
- if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+
+ RetValExp = rex.takeAs<Expr>();
+ if (RetValExp)
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
if (RetValExp)
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
index e55fcc4245..a090418916 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
@@ -91,7 +91,7 @@ void bind_lvalue_to_conv_lvalue() {
void bind_lvalue_to_conv_lvalue_ambig(ConvertibleToBothDerivedRef both) {
Derived &dr1 = both;
- Base &br1 = both; // expected-error{{error: conversion from 'struct ConvertibleToBothDerivedRef' to 'struct Base' is ambiguous}}
+ Base &br1 = both; // expected-error{{reference initialization of type 'struct Base &' with initializer of type 'struct ConvertibleToBothDerivedRef' is ambiguous}}
}
struct IntBitfield {
@@ -125,5 +125,5 @@ void bind_const_lvalue_to_class_conv_temporary() {
}
void bind_lvalue_to_conv_rvalue_ambig(ConvertibleToBothDerived both) {
const Derived &dr1 = both;
- const Base &br1 = both; // expected-error{{error: conversion from 'struct ConvertibleToBothDerived' to 'struct Base const' is ambiguous}}
+ const Base &br1 = both; // expected-error{{reference initialization of type 'struct Base const &' with initializer of type 'struct ConvertibleToBothDerived' is ambiguous}}
}
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
index 88cca39e28..58479cda26 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
@@ -17,7 +17,7 @@ struct X2 { };
int& get_int() { return X0<int>::value; }
X1& get_X1() { return X0<X1>::value; }
-double*& get_double_ptr() { return X0<int*>::value; } // expected-error{{initialized}}
+double*& get_double_ptr() { return X0<int*>::value; } // expected-error{{non-const lvalue reference to type 'double *' cannot bind to a value of unrelated type 'int *'}}
X2& get_X2() {
return X0<X2>::value; // expected-note{{instantiation}}
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index f6b183fc84..f83bbeeac8 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -202,3 +202,17 @@ void f11(H h) {
// CHECK: ret void
f10(h);
}
+
+// PR5808
+struct I {
+ I(const char *);
+ ~I();
+};
+
+// CHECK: _Z3f12v
+I f12() {
+ // CHECK: call void @_ZN1IC1EPKc
+ // CHECK-NOT: call void @_ZN1ID1Ev
+ // CHECK: ret void
+ return "Hello";
+}
diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp
index 997e19c388..fca5a4a72a 100644
--- a/test/SemaCXX/conversion-function.cpp
+++ b/test/SemaCXX/conversion-function.cpp
@@ -99,7 +99,7 @@ class AutoPtrRef { };
class AutoPtr {
// FIXME: Using 'unavailable' since we do not have access control yet.
// FIXME: The error message isn't so good.
- AutoPtr(AutoPtr &) __attribute__((unavailable));
+ AutoPtr(AutoPtr &) __attribute__((unavailable)); // expected-note{{explicitly marked}}
public:
AutoPtr();
@@ -115,9 +115,19 @@ AutoPtr test_auto_ptr(bool Cond) {
AutoPtr p;
if (Cond)
- return p; // expected-error{{incompatible type returning}}
+ return p; // expected-error{{call to deleted constructor}}
return AutoPtr();
}
+struct A1 {
+ A1(const char *);
+ ~A1();
+private:
+ A1(const A1&) __attribute__((unavailable)); // expected-note{{here}}
+};
+
+A1 f() {
+ return "Hello"; // expected-error{{invokes deleted copy constructor}}
+}
diff --git a/test/SemaCXX/decl-init-ref.cpp b/test/SemaCXX/decl-init-ref.cpp
index 4200b169ab..294543f495 100644
--- a/test/SemaCXX/decl-init-ref.cpp
+++ b/test/SemaCXX/decl-init-ref.cpp
@@ -21,6 +21,6 @@ extern B f();
const int& ri = (void)0; // expected-error {{reference to type 'int const' could not bind to an rvalue of type 'void'}}
int main() {
- const A& rca = f(); // expected-error {{conversion from 'class B' to 'struct A const' is ambiguous}}
+ const A& rca = f(); // expected-error {{reference initialization of type 'struct A const &' with initializer of type 'class B' is ambiguous}}
A& ra = f(); // expected-error {{non-const lvalue reference to type 'struct A' cannot bind to a temporary of type 'class B'}}
}
diff --git a/test/SemaCXX/ref-init-ambiguous.cpp b/test/SemaCXX/ref-init-ambiguous.cpp
index c17d613cae..976879ecd0 100644
--- a/test/SemaCXX/ref-init-ambiguous.cpp
+++ b/test/SemaCXX/ref-init-ambiguous.cpp
@@ -3,19 +3,18 @@
enum E2 { };
struct A {
- operator E2&(); // expected-note 2 {{candidate function}}
+ operator E2&(); // expected-note 3 {{candidate function}}
};
struct B {
- operator E2&(); // expected-note 2 {{candidate function}}
+ operator E2&(); // expected-note 3 {{candidate function}}
};
struct C : B, A {
};
void test(C c) {
- // FIXME: state that there was an ambiguity in the conversion!
- const E2 &e2 = c; // expected-error {{reference to type 'enum E2 const' could not bind to an lvalue of type 'struct C'}}
+ const E2 &e2 = c; // expected-error {{reference initialization of type 'enum E2 const &' with initializer of type 'struct C' is ambiguous}}
}
void foo(const E2 &);
diff --git a/test/SemaCXX/rval-references-xfail.cpp b/test/SemaCXX/rval-references-xfail.cpp
new file mode 100644
index 0000000000..d41f8f141c
--- /dev/null
+++ b/test/SemaCXX/rval-references-xfail.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// XFAIL: *
+struct MoveOnly {
+ MoveOnly();
+ MoveOnly(const MoveOnly&) = delete; // expected-note {{candidate function}} \
+ // expected-note 3{{explicitly marked deleted here}}
+ MoveOnly(MoveOnly&&); // expected-note {{candidate function}}
+ MoveOnly(int&&); // expected-note {{candidate function}}
+};
+
+MoveOnly returning() {
+ MoveOnly mo;
+ return mo;
+}
diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp
index 17e7584a60..7ff3d584c0 100644
--- a/test/SemaCXX/rval-references.cpp
+++ b/test/SemaCXX/rval-references.cpp
@@ -65,27 +65,23 @@ int&& should_not_warn(int&& i) { // But GCC 4.4 does
// Test the return dance. This also tests IsReturnCopyElidable.
struct MoveOnly {
MoveOnly();
- MoveOnly(const MoveOnly&) = delete; // expected-note {{candidate function}}
+ MoveOnly(const MoveOnly&) = delete; // expected-note {{candidate function}} \
+ // expected-note 3{{explicitly marked deleted here}}
MoveOnly(MoveOnly&&); // expected-note {{candidate function}}
MoveOnly(int&&); // expected-note {{candidate function}}
};
-MoveOnly returning() {
- MoveOnly mo;
- return mo;
-}
-
MoveOnly gmo;
MoveOnly returningNonEligible() {
int i;
static MoveOnly mo;
MoveOnly &r = mo;
if (0) // Copy from global can't be elided
- return gmo; // expected-error {{incompatible type returning}}
+ return gmo; // expected-error {{call to deleted constructor}}
else if (0) // Copy from local static can't be elided
- return mo; // expected-error {{incompatible type returning}}
+ return mo; // expected-error {{call to deleted constructor}}
else if (0) // Copy from reference can't be elided
- return r; // expected-error {{incompatible type returning}}
+ return r; // expected-error {{call to deleted constructor}}
else // Construction from different type can't be elided
return i; // expected-error {{no viable conversion from 'int' to 'struct MoveOnly'}}
}
diff --git a/test/SemaTemplate/class-template-id.cpp b/test/SemaTemplate/class-template-id.cpp
index bb9d39d82a..df5ef554f7 100644
--- a/test/SemaTemplate/class-template-id.cpp
+++ b/test/SemaTemplate/class-template-id.cpp
@@ -9,9 +9,9 @@ A<int, FLOAT> *foo(A<int> *ptr, A<int> const *ptr2, A<int, double> *ptr3) {
if (ptr)
return ptr; // okay
else if (ptr2)
- return ptr2; // expected-error{{incompatible type returning 'A<int> const *', expected 'A<int, FLOAT> *'}}
+ return ptr2; // expected-error{{cannot initialize return object of type 'A<int, FLOAT> *' with an lvalue of type 'A<int> const *'}}
else {
- return ptr3; // expected-error{{incompatible type returning 'A<int, double> *', expected 'A<int, FLOAT> *'}}
+ return ptr3; // expected-error{{cannot initialize return object of type 'A<int, FLOAT> *' with an lvalue of type 'A<int, double> *'}}
}
}
@@ -24,7 +24,7 @@ B<17 + 2> *bar(B<(19)> *ptr1, B< (::value + 7) > *ptr2, B<19 - 3> *ptr3) {
else if (ptr2)
return ptr2;
else
- return ptr3; // expected-error{{incompatible type returning 'B<19 - 3> *', expected 'B<17 + 2> *'}}
+ return ptr3; // expected-error{{cannot initialize return object of type 'B<17 + 2> *' with an lvalue of type 'B<19 - 3>}}
}
typedef B<5> B5;
diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp
index 68aaa646fb..139de9d686 100644
--- a/test/SemaTemplate/constructor-template.cpp
+++ b/test/SemaTemplate/constructor-template.cpp
@@ -52,7 +52,7 @@ template <> struct A<int>{A(const A<int>&);};
struct B { A<int> x; B(B& a) : x(a.x) {} };
struct X2 {
- X2();
+ X2(); // expected-note{{candidate function}}
X2(X2&); // expected-note {{candidate function}}
template<typename T> X2(T);
};
@@ -61,7 +61,7 @@ X2 test(bool Cond, X2 x2) {
if (Cond)
return x2; // okay, uses copy constructor
- return X2(); // expected-error{{no viable conversion from 'struct X2' to 'struct X2' is possible}}
+ return X2(); // expected-error{{no matching constructor}}
}
struct X3 {
@@ -71,7 +71,7 @@ struct X3 {
template<> X3::X3(X3); // expected-error{{must pass its first argument by reference}}
struct X4 {
- X4();
+ X4(); // expected-note{{candidate function}}
~X4();
X4(X4&); // expected-note {{candidate function}}
template<typename T> X4(const T&, int = 17);
@@ -80,7 +80,7 @@ struct X4 {
X4 test_X4(bool Cond, X4 x4) {
X4 a(x4, 17); // okay, constructor template
X4 b(x4); // okay, copy constructor
- return X4(); // expected-error{{no viable conversion}}
+ return X4(); // expected-error{{no matching constructor}}
}
// Instantiation of a non-dependent use of a constructor
diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp
index ffe1d58f28..e0042de50e 100644
--- a/test/SemaTemplate/instantiate-expr-4.cpp
+++ b/test/SemaTemplate/instantiate-expr-4.cpp
@@ -293,7 +293,7 @@ template struct NonDepMemberCall0<float&>; // expected-note{{instantiation}}
template<typename T>
struct QualifiedDeclRef0 {
T f() {
- return is_pod<X>::value; // expected-error{{initialized}}
+ return is_pod<X>::value; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'bool const'}}
}
};
diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp
index 52707ca63e..543b3cc197 100644
--- a/test/SemaTemplate/instantiate-function-1.cpp
+++ b/test/SemaTemplate/instantiate-function-1.cpp
@@ -66,7 +66,7 @@ template<typename T, typename U, typename V> struct X6 {
return u;
else {
if (t < 0)
- return v; // expected-error{{incompatible type}}
+ return v; // expected-error{{cannot initialize return object of type}}
}
if (T x = t) {
diff --git a/test/SemaTemplate/instantiate-member-template.cpp b/test/SemaTemplate/instantiate-member-template.cpp
index 6442ed417c..2b5ba5c891 100644
--- a/test/SemaTemplate/instantiate-member-template.cpp
+++ b/test/SemaTemplate/instantiate-member-template.cpp
@@ -50,7 +50,7 @@ struct X1 {
template<typename V>
V f1(T t, U u, V) {
- return t + u; // expected-error{{incompatible type}}
+ return t + u; // expected-error{{cannot initialize return object}}
}
};
@@ -75,7 +75,7 @@ template<typename T>
template<typename U>
template<typename V>
V X1<T>::Inner4<U>::f2(T t, U u, V) {
- return t + u; // expected-error{{incompatible type}}
+ return t + u; // expected-error{{cannot initialize return object}}
}
void test_X1(int *ip, int i, double *dp) {
diff --git a/test/SemaTemplate/instantiate-typedef.cpp b/test/SemaTemplate/instantiate-typedef.cpp
index be769c00ec..977fd08cc3 100644
--- a/test/SemaTemplate/instantiate-typedef.cpp
+++ b/test/SemaTemplate/instantiate-typedef.cpp
@@ -8,7 +8,7 @@ struct add_pointer {
add_pointer<int>::type test1(int * ptr) { return ptr; }
add_pointer<float>::type test2(int * ptr) {
- return ptr; // expected-error{{incompatible type returning 'int *', expected 'add_pointer<float>::type' (aka 'float *')}}
+ return ptr; // expected-error{{cannot initialize return object of type 'add_pointer<float>::type' (aka 'float *') with an lvalue of type 'int *'}}
}
add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}} \