diff options
25 files changed, 1860 insertions, 74 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index a84efb18504..5507e99e45a 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -108,6 +108,7 @@ class CXXBaseSpecifier { /// Range - The source code range that covers the full base /// specifier, including the "virtual" (if present) and access /// specifier (if present). + // FIXME: Move over to a TypeLoc! SourceRange Range; /// Virtual - Whether this is a virtual base class or not. diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 7b5598c4604..7c98403b6f5 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -813,8 +813,9 @@ public: bool isBooleanType() const; bool isCharType() const; bool isWideCharType() const; + bool isAnyCharacterType() const; bool isIntegralType() const; - + /// Floating point categories. bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) /// isComplexType() does *not* include complex integers (a GCC extension). diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6fadb00e1c9..d75c49b8992 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -445,6 +445,7 @@ def err_implicit_object_parameter_init : Error< "of type %1">; def note_field_decl : Note<"member is declared here">; +def note_bitfield_decl : Note<"bit-field is declared here">; def note_previous_decl : Note< "%0 declared here">; def note_member_synthesized_at : Note< @@ -525,14 +526,31 @@ def err_lvalue_to_rvalue_ambig_ref : Error<"rvalue reference cannot bind to lval def err_not_reference_to_const_init : Error< "non-const lvalue reference to type %0 cannot be initialized " "with a %1 of type %2">; +def err_lvalue_reference_bind_to_temporary : Error< + "non-const lvalue reference to type %0 cannot bind to a temporary of type " + "%1">; +def err_lvalue_reference_bind_to_unrelated : Error< + "non-const lvalue reference to type %0 cannot bind to a value of unrelated " + "type %1">; +def err_reference_bind_drops_quals : Error< + "binding of reference to type %0 to a value of type %1 drops qualifiers">; +def err_reference_bind_failed : Error< + "reference to type %0 could not bind to an %select{rvalue|lvalue}1 of type " + "%2">; + + // FIXME: passing in an English string as %1! def err_reference_init_drops_quals : Error< "initialization of reference to type %0 with a %1 of type %2 drops " "qualifiers">; +def err_reference_bind_to_bitfield : Error< + "%select{non-const|volatile}0 reference cannot bind to bit-field %1">; def err_reference_var_requires_init : Error< "declaration of reference variable %0 requires an initializer">; def err_const_var_requires_init : Error< "declaration of const variable '%0' requires an initializer">; +def err_reference_has_multiple_inits : Error< + "reference cannot be initialized with multiple values">; def err_init_non_aggr_init_list : Error< "initialization of non-aggregate type %0 with an initializer list">; def err_init_reference_member_uninitialized : Error< @@ -1575,6 +1593,9 @@ def warn_tentative_incomplete_array : Warning< def err_typecheck_incomplete_array_needs_initializer : Error< "definition of variable with array type needs an explicit size " "or an initializer">; +def err_array_init_not_init_list : Error< + "array initializater must be an initializer " + "list%select{| or string literal}0">; def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">; def err_typecheck_sclass_fscope : Error< @@ -1861,7 +1882,10 @@ def err_typecheck_bool_condition : Error< def err_typecheck_ambiguous_condition : Error< "conversion from %0 to %1 is ambiguous">; def err_typecheck_nonviable_condition : Error< - "no viable conversion from %0 to %1 is possible">; + "no viable conversion from %0 to %1">; +def err_typecheck_deleted_function : Error< + "conversion function from %0 to %1 invokes a deleted function">; + def err_expected_class_or_namespace : Error<"expected a class or namespace">; def err_invalid_declarator_scope : Error< "definition or redeclaration of %0 not in a namespace enclosing %1">; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 70387c73a7f..687beaea08c 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -434,6 +434,18 @@ bool Type::isWideCharType() const { return false; } +/// \brief Determine whether this type is any of the built-in character +/// types. +bool Type::isAnyCharacterType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return (BT->getKind() >= BuiltinType::Char_U && + BT->getKind() <= BuiltinType::Char32) || + (BT->getKind() >= BuiltinType::Char_S && + BT->getKind() <= BuiltinType::WChar); + + return false; +} + /// isSignedIntegerType - Return true if this is an integer type that is /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], /// an enum decl which has a signed representation, or a vector of signed diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 6f47cd0bc95..ad903a0816b 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -95,7 +95,10 @@ namespace clang { class CXXBasePaths; class CXXTemporary; class LookupResult; - + class InitializedEntity; + class InitializationKind; + class InitializationSequence; + /// BlockSemaInfo - When a block is being parsed, this contains information /// about the block. It is pointed to from Sema::CurBlock. struct BlockSemaInfo { @@ -812,16 +815,6 @@ public: return NULL; } - /// OverloadingResult - Capture the result of performing overload - /// resolution. - enum OverloadingResult { - OR_Success, ///< Overload resolution succeeded. - OR_No_Viable_Function, ///< No viable function found. - OR_Ambiguous, ///< Ambiguous candidates found. - OR_Deleted ///< Overload resoltuion refers to a deleted function. - }; - - /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, TypeSourceInfo *TInfo); @@ -1011,6 +1004,8 @@ public: FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + OwningExprResult FixOverloadedFunctionReference(OwningExprResult, + FunctionDecl *Fn); void AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*>& Callees, DeclarationName &UnqualifiedName, @@ -1854,14 +1849,6 @@ public: /// it simply returns the passed in expression. OwningExprResult MaybeBindToTemporary(Expr *E); - /// InitializationKind - Represents which kind of C++ initialization - /// [dcl.init] a routine is to perform. - enum InitializationKind { - IK_Direct, ///< Direct initialization - IK_Copy, ///< Copy initialization - IK_Default ///< Default initialization - }; - CXXConstructorDecl * TryInitializationByConstructor(QualType ClassType, Expr **Args, unsigned NumArgs, diff --git a/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp index f9138902a67..857241d7148 100644 --- a/clang/lib/Sema/SemaCXXCast.cpp +++ b/clang/lib/Sema/SemaCXXCast.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -864,7 +865,9 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, if (CXXConstructorDecl *Constructor = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1, OpRange.getBegin(), - Sema::IK_Direct)) { + InitializationKind::CreateDirect(OpRange.getBegin(), + OpRange.getBegin(), + OpRange.getEnd()))) { ConversionDecl = Constructor; Kind = CastExpr::CK_ConstructorConversion; return TC_Success; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 96b6c16485c..bf6863bbf4b 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" @@ -3486,8 +3487,35 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); } else if (!VDecl->isInvalidDecl()) { - if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), - VDecl->getDeclName(), DirectInit)) + if (VDecl->getType()->isReferenceType()) { + InitializedEntity Entity + = InitializedEntity::InitializeVariable(VDecl); + + // FIXME: Poor source location information. + InitializationKind Kind + = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(), + SourceLocation(), + SourceLocation()) + : InitializationKind::CreateCopy(VDecl->getLocation(), + SourceLocation()); + InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + if (InitSeq) { + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&Init, 1)); + if (Result.isInvalid()) { + VDecl->setInvalidDecl(); + return; + } + + Init = Result.takeAs<Expr>(); + } else { + InitSeq.Diagnose(*this, Entity, Kind, &Init, 1); + VDecl->setInvalidDecl(); + return; + } + + } else if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), + VDecl->getDeclName(), DirectInit)) VDecl->setInvalidDecl(); // C++ 3.6.2p2, allow dynamic initialization of static initializers. @@ -3677,7 +3705,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, SourceRange(Var->getLocation(), Var->getLocation()), Var->getDeclName(), - IK_Default, + InitializationKind::CreateDefault(Var->getLocation()), ConstructorArgs); // FIXME: Location info for the variable initialization? diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 6f8a4f16d3b..d977ad6000d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -1108,7 +1109,8 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, NumArgs), IdLoc, SourceRange(IdLoc, RParenLoc), - Member->getDeclName(), IK_Direct, + Member->getDeclName(), + InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc), ConstructorArgs); if (C) { @@ -1232,7 +1234,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, (void**)Args, NumArgs), BaseLoc, SourceRange(BaseLoc, RParenLoc), - Name, IK_Direct, + Name, + InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc), ConstructorArgs); if (C) { // Take over the constructor arguments as our own. @@ -3656,7 +3659,9 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, SourceRange(VDecl->getLocation(), RParenLoc), VDecl->getDeclName(), - IK_Direct, + InitializationKind::CreateDirect(VDecl->getLocation(), + LParenLoc, + RParenLoc), ConstructorArgs); if (!Constructor) RealDecl->setInvalidDecl(); @@ -3692,7 +3697,7 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, QualType ClassType, Expr **Args, unsigned NumArgs, - Sema::InitializationKind Kind, + InitializationKind Kind, OverloadCandidateSet &CandidateSet) { // C++ [dcl.init]p14: // If the initialization is direct-initialization, or if it is @@ -3727,10 +3732,12 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, else Constructor = cast<CXXConstructorDecl>(*Con); - if ((Kind == Sema::IK_Direct) || - (Kind == Sema::IK_Copy && + if ((Kind.getKind() == InitializationKind::IK_Direct) || + (Kind.getKind() == InitializationKind::IK_Value) || + (Kind.getKind() == InitializationKind::IK_Copy && Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || - (Kind == Sema::IK_Default && Constructor->isDefaultConstructor())) { + ((Kind.getKind() == InitializationKind::IK_Default) && + Constructor->isDefaultConstructor())) { if (ConstructorTmpl) SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, @@ -4002,7 +4009,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // real, update the initializer with the resulting function. if (!ICS) { if (DiagnoseUseOfDecl(Fn, DeclLoc)) - return true; + return true; Init = FixOverloadedFunctionReference(Init, Fn); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 16c5275d7de..5e0ce666ea2 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -225,7 +226,9 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, SourceRange(TypeRange.getBegin(), RParenLoc), DeclarationName(), - IK_Direct, + InitializationKind::CreateDirect(TypeRange.getBegin(), + LParenLoc, + RParenLoc), ConstructorArgs); if (!Constructor) @@ -449,12 +452,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, // Skip all the checks. } else if ((RT = AllocType->getAs<RecordType>()) && !AllocType->isAggregateType()) { + InitializationKind InitKind = InitializationKind::CreateDefault(TypeLoc); + if (NumConsArgs > 0) + InitKind = InitializationKind::CreateDirect(TypeLoc, + PlacementLParen, + PlacementRParen); Constructor = PerformInitializationByConstructor( AllocType, move(ConstructorArgs), TypeLoc, SourceRange(TypeLoc, ConstructorRParen), RT->getDecl()->getDeclName(), - NumConsArgs != 0 ? IK_Direct : IK_Default, + InitKind, ConvertedConstructorArgs); if (!Constructor) return ExprError(); @@ -1584,7 +1592,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, OverloadCandidateSet::iterator Best; switch (Self.BestViableFunction(CandidateSet, Loc, Best)) { - case Sema::OR_Success: + case OR_Success: // We found a match. Perform the conversions on the arguments and move on. if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], Best->Conversions[0], "converting") || @@ -1593,13 +1601,13 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, break; return false; - case Sema::OR_No_Viable_Function: + case OR_No_Viable_Function: Self.Diag(Loc, diag::err_typecheck_cond_incompatible_operands) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); return true; - case Sema::OR_Ambiguous: + case OR_Ambiguous: Self.Diag(Loc, diag::err_conditional_ambiguous_ovl) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); @@ -1607,7 +1615,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, // the viable candidates. break; - case Sema::OR_Deleted: + case OR_Deleted: assert(false && "Conditional operator has only built-in overloads"); break; } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 4b0fc84b301..d2ae906eff3 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -15,11 +15,13 @@ // //===----------------------------------------------------------------------===// +#include "SemaInit.h" #include "Sema.h" #include "clang/Parse/Designator.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "llvm/Support/ErrorHandling.h" #include <map> using namespace clang; @@ -76,7 +78,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, OverloadCandidateSet CandidateSet; if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined, CandidateSet, - true, false, false) != S.OR_Ambiguous) + true, false, false) != OR_Ambiguous) return S.Diag(Init->getSourceRange().getBegin(), diag::err_typecheck_convert_incompatible) << DeclType << Init->getType() << "initializing" @@ -230,13 +232,20 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + // FIXME: Poor location information + InitializationKind InitKind + = InitializationKind::CreateCopy(Init->getLocStart(), + SourceLocation()); + if (DirectInit) + InitKind = InitializationKind::CreateDirect(Init->getLocStart(), + SourceLocation(), + SourceLocation()); CXXConstructorDecl *Constructor = PerformInitializationByConstructor(DeclType, MultiExprArg(*this, (void **)&Init, 1), InitLoc, Init->getSourceRange(), - InitEntity, - DirectInit? IK_Direct : IK_Copy, + InitEntity, InitKind, ConstructorArgs); if (!Constructor) return true; @@ -1875,12 +1884,13 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { if (ClassDecl->hasUserDeclaredConstructor()) { ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + // FIXME: Poor location information CXXConstructorDecl *Constructor = PerformInitializationByConstructor(Type, MultiExprArg(*this, 0, 0), Loc, SourceRange(Loc), DeclarationName(), - IK_Direct, + InitializationKind::CreateValue(Loc, Loc, Loc), ConstructorArgs); if (!Constructor) return true; @@ -1908,3 +1918,955 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { return false; } + +//===----------------------------------------------------------------------===// +// Initialization entity +//===----------------------------------------------------------------------===// + +void InitializedEntity::InitDeclLoc() { + assert((Kind == EK_Variable || Kind == EK_Parameter || Kind == EK_Member) && + "InitDeclLoc cannot be used with non-declaration entities."); + + if (TypeSourceInfo *DI = VariableOrMember->getTypeSourceInfo()) { + TL = DI->getTypeLoc(); + return; + } + + // FIXME: Once we've gone through the effort to create the fake + // TypeSourceInfo, should we cache it in the declaration? + // (If not, we "leak" it). + TypeSourceInfo *DI = VariableOrMember->getASTContext() + .CreateTypeSourceInfo(VariableOrMember->getType()); + DI->getTypeLoc().initialize(VariableOrMember->getLocation()); + TL = DI->getTypeLoc(); +} + +InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, + CXXBaseSpecifier *Base) +{ + InitializedEntity Result; + Result.Kind = EK_Base; + Result.Base = Base; + // FIXME: CXXBaseSpecifier should store a TypeLoc. + TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Base->getType()); + DI->getTypeLoc().initialize(Base->getSourceRange().getBegin()); + Result.TL = DI->getTypeLoc(); + return Result; +} + +//===----------------------------------------------------------------------===// +// Initialization sequence +//===----------------------------------------------------------------------===// + +void InitializationSequence::Step::Destroy() { + switch (Kind) { + case SK_ResolveAddressOfOverloadedFunction: + case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseLValue: + case SK_BindReference: + case SK_BindReferenceToTemporary: + case SK_UserConversion: + case SK_QualificationConversionRValue: + case SK_QualificationConversionLValue: + break; + + case SK_ConversionSequence: + delete ICS; + } +} + +void InitializationSequence::AddAddressOverloadResolutionStep( + FunctionDecl *Function) { + Step S; + S.Kind = SK_ResolveAddressOfOverloadedFunction; + S.Type = Function->getType(); + S.Function = Function; + Steps.push_back(S); +} + +void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType, + bool IsLValue) { + Step S; + S.Kind = IsLValue? SK_CastDerivedToBaseLValue : SK_CastDerivedToBaseRValue; + S.Type = BaseType; + Steps.push_back(S); +} + +void InitializationSequence::AddReferenceBindingStep(QualType T, + bool BindingTemporary) { + Step S; + S.Kind = BindingTemporary? SK_BindReferenceToTemporary : SK_BindReference; + S.Type = T; + Steps.push_back(S); +} + +void InitializationSequence::AddUserConversionStep(FunctionDecl *Function) { + Step S; + S.Kind = SK_UserConversion; + S.Type = Function->getResultType().getNonReferenceType(); + S.Function = Function; + Steps.push_back(S); +} + +void InitializationSequence::AddQualificationConversionStep(QualType Ty, + bool IsLValue) { + Step S; + S.Kind = IsLValue? SK_QualificationConversionLValue + : SK_QualificationConversionRValue; + S.Type = Ty; + Steps.push_back(S); +} + +void InitializationSequence::AddConversionSequenceStep( + const ImplicitConversionSequence &ICS, + QualType T) { + Step S; + S.Kind = SK_ConversionSequence; + S.Type = T; + S.ICS = new ImplicitConversionSequence(ICS); + Steps.push_back(S); +} + +void InitializationSequence::SetOverloadFailure(FailureKind Failure, + OverloadingResult Result) { + SequenceKind = FailedSequence; + this->Failure = Failure; + this->FailedOverloadResult = Result; +} + +//===----------------------------------------------------------------------===// +// Attempt initialization +//===----------------------------------------------------------------------===// + +/// \brief Attempt list initialization (C++0x [dcl.init.list]) +static bool TryListInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitListExpr *InitList, + InitializationSequence &Sequence) { + // FIXME: For now, it is safe to assume that list initialization always + // works. When we actually perform list initialization, we'll do all of the + // necessary checking. + // C++0x initializer lists will force us to perform more checking here. + return true; +} + +/// \brief Try a reference initialization that involves calling a conversion +/// function. +/// +/// FIXME: look intos DRs 656, 896 +static OverloadingResult TryRefInitWithConversionFunction(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + bool AllowRValues, + InitializationSequence &Sequence) { + QualType DestType = Entity.getType().getType(); + QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); + QualType T1 = cv1T1.getUnqualifiedType(); + QualType cv2T2 = Initializer->getType(); + QualType T2 = cv2T2.getUnqualifiedType(); + + bool DerivedToBase; + assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), + T1, T2, DerivedToBase) && + "Must have incompatible references when binding via conversion"); + + // Build the candidate set directly in the initialization sequence + // structure, so that it will persist if we fail. + OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); + CandidateSet.clear(); + + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; + + const RecordType *T1RecordType = 0; + if (AllowRValues && (T1RecordType = T1->getAs<RecordType>())) { + // The type we're converting to is a class type. Enumerate its constructors + // to see if there is a suitable conversion. + CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl()); + + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(T1).getUnqualifiedType()); + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = T1RecordDecl->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl + = dyn_cast<FunctionTemplateDecl>(*Con); + if (ConstructorTmpl) + Constructor = cast<CXXConstructorDecl>( + ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast<CXXConstructorDecl>(*Con); + + if (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + &Initializer, 1, CandidateSet); + else + S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet); + } + } + } + + if (const RecordType *T2RecordType = T2->getAs<RecordType>()) { + // The type we're converting from is a class type, enumerate its conversion + // functions. + CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl()); + + // Determine the type we are converting to. If we are allowed to + // convert to an rvalue, take the type that the destination type + // refers to. + QualType ToType = AllowRValues? cv1T1 : DestType; + + const UnresolvedSet *Conversions + = T2RecordDecl->getVisibleConversionFunctions(); + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); + I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + else + Conv = cast<CXXConversionDecl>(*I); + + // If the conversion function doesn't return a reference type, + // it can't be considered for this conversion unless we're allowed to + // consider rvalues. + // FIXME: Do we need to make sure that we only consider conversion + // candidates with reference-compatible results? That might be needed to + // break recursion. + if ((AllowExplicit || !Conv->isExplicit()) && + (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){ + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer, + ToType, CandidateSet); + else + S.AddConversionCandidate(Conv, ActingDC, Initializer, cv1T1, + CandidateSet); + } + } + } + + SourceLocation DeclLoc = Initializer->getLocStart(); + + // Perform overload resolution. If it fails, return the failed result. + OverloadCandidateSet::iterator Best; + if (OverloadingResult Result + = S.BestViableFunction(CandidateSet, DeclLoc, Best)) + return Result; + + // Add the user-defined conversion step. + FunctionDecl *Function = Best->Function; + Sequence.AddUserConversionStep(Function); + + // Determine whether we need to perform derived-to-base or + // cv-qualification adjustments. + if (isa<CXXConversionDecl>(Function)) + T2 = Function->getResultType(); + else + T2 = cv1T1; + + bool NewDerivedToBase = false; + Sema::ReferenceCompareResult NewRefRelationship + = S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonReferenceType(), + NewDerivedToBase); + assert(NewRefRelationship != Sema::Ref_Incompatible && + "Overload resolution picked a bad conversion function"); + (void)NewRefRelationship; + if (NewDerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, + T2.getNonReferenceType().getQualifiers()), + /*isLValue=*/true); + + if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, T2->isReferenceType()); + + Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType()); + return OR_Success; +} + +/// \brief Attempt reference initialization (C++0x [dcl.init.list]) +static void TryReferenceInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + Sequence.setSequenceKind(InitializationSequence::ReferenceBinding); + + QualType DestType = Entity.getType().getType(); + QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); + QualType T1 = cv1T1.getUnqualifiedType(); + QualType cv2T2 = Initializer->getType(); + QualType T2 = cv2T2.getUnqualifiedType(); + SourceLocation DeclLoc = Initializer->getLocStart(); + + // If the initializer is the address of an overloaded function, try + // to resolve the overloaded function. If all goes well, T2 is the + // type of the resulting function. + if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { + FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, + T1, + false); + if (!Fn) { + Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); + return; + } + + Sequence.AddAddressOverloadResolutionStep(Fn); + cv2T2 = Fn->getType(); + T2 = cv2T2.getUnqualifiedType(); + } + + // FIXME: Rvalue references + bool ForceRValue = false; + + // Compute some basic properties of the types and the initializer. + bool isLValueRef = DestType->isLValueReferenceType(); + bool isRValueRef = !isLValueRef; + bool DerivedToBase = false; + Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : + Initializer->isLvalue(S.Context); + Sema::ReferenceCompareResult RefRelationship + = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase); + + // C++0x [dcl.init.ref]p5: + // A reference to type "cv1 T1" is initialized by an expression of type + // "cv2 T2" as follows: + // + // - If the reference is an lvalue reference and the initializer + // expression + OverloadingResult ConvOvlResult = OR_Success; + if (isLValueRef) { + if (InitLvalue == Expr::LV_Valid && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // - is an lvalue (but is not a bit-field), and "cv1 T1" is + // reference-compatible with "cv2 T2," or + // + // Per C++ [over.best.ics]p2, we ignore whether the lvalue is a + // bit-field when we're determining whether the reference initialization + // can occur. This property will be checked by PerformInitialization. + if (DerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + /*isLValue=*/true); + if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false); + return; + } + + // - has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to an + // lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible + // with "cv3 T3" (this conversion is selected by enumerating the + // applicable conversion functions (13.3.1.6) and choosing the best + // one through overload resolution (13.3)), + if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType()) { + ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, + Initializer, + /*AllowRValues=*/false, + Sequence); + if (ConvOvlResult == OR_Success) + return; + } + } + + // - Otherwise, the reference shall be an lvalue reference to a + // non-volatile const type (i.e., cv1 shall be const), or the reference + // shall be an rvalue reference and the initializer expression shall + // be an rvalue. + if (!((isLValueRef && cv1T1.getCVRQualifiers() == Qualifiers::Const) || + (isRValueRef && InitLvalue != Expr::LV_Valid))) { + if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + else if (isLValueRef) + Sequence.SetFailed(InitLvalue == Expr::LV_Valid + ? (RefRelationship == Sema::Ref_Related + ? InitializationSequence::FK_ReferenceInitDropsQualifiers + : InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated) + : InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary); + else + Sequence.SetFailed( + InitializationSequence::FK_RValueReferenceBindingToLValue); + + return; + } + + // - If T1 and T2 are class types and + if (T1->isRecordType() && T2->isRecordType()) { + // - the initializer expression is an rvalue and "cv1 T1" is + // reference-compatible with "cv2 T2", or + if (InitLvalue != Expr::LV_Valid && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + if (DerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + /*isLValue=*/false); + if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/false); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); + return; + } + + // - T1 is not reference-related to T2 and the initializer expression + // can be implicitly converted to an rvalue of type "cv3 T3" (this + // conversion is selected by enumerating the applicable conversion + // functions (13.3.1.6) and choosing the best one through overload + // resolution (13.3)), + if (RefRelationship == Sema::Ref_Incompatible) { + ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, + Kind, Initializer, + /*AllowRValues=*/true, + Sequence); + if (ConvOvlResult) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + + return; + } + + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); + return; + } + + // - If the initializer expression is an rvalue, with T2 an array type, + // and "cv1 T1" is reference-compatible with "cv2 T2," the reference + // is bound to the object represented by the rvalue (see 3.10). + // FIXME: How can an array type be reference-compatible with anything? + // Don't we mean the element types of T1 and T2? + + // - Otherwise, a temporary of type “cv1 T1” is created and initialized + // from the initializer expression using the rules for a non-reference + // copy initialization (8.5). The reference is then bound to the + // temporary. [...] + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct); + ImplicitConversionSequence ICS + = S.TryImplicitConversion(Initializer, cv1T1, + /*SuppressUserConversions=*/false, AllowExplicit, + /*ForceRValue=*/false, + /*FIXME:InOverloadResolution=*/false, + /*UserCast=*/Kind.isExplicitCast()); + + if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + // FIXME: Use the conversion function set stored in ICS to turn + // 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); + return; + } + + // [...] If T1 is reference-related to T2, cv1 must be the + // same cv-qualification as, or greater cv-qualification + // than, cv2; otherwise, the program is ill-formed. + if (RefRelationship == Sema::Ref_Related && + !cv1T1.isAtLeastAsQualifiedAs(cv2T2)) { + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); + return; + } + + // Perform the actual conversion. + Sequence.AddConversionSequenceStep(ICS, cv1T1); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); + return; +} + +/// \brief Attempt character array initialization from a string literal +/// (C++ [dcl.init.string], C99 6.7.8). +static void TryStringLiteralInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + // FIXME: Implement! +} + +/// \brief Attempt value initialization (C++ [dcl.init]p7). +static void TryValueInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitializationSequence &Sequence) { + // FIXME: Implement! +} + +/// \brief Attempt initialization by constructor (C++ [dcl.init]), which +/// enumerates the constructors of the initialized entity and performs overload +/// resolution to select the best. +static void TryConstructorInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs, + InitializationSequence &Sequence) { + // FIXME: Implement! +} + +/// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]), +/// which enumerates all conversion functions and performs overload resolution +/// to select the best. +static void TryUserDefinedConversion(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + // FIXME: Implement! +} + +/// \brief Attempt an implicit conversion (C++ [conv]) converting from one +/// non-class type to another. +static void TryImplicitConversion(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + ImplicitConversionSequence ICS + = S.TryImplicitConversion(Initializer, Entity.getType().getType(), + /*SuppressUserConversions=*/true, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*FIXME:InOverloadResolution=*/false, + /*UserCast=*/Kind.isExplicitCast()); + + if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); + return; + } + + Sequence.AddConversionSequenceStep(ICS, Entity.getType().getType()); +} + +InitializationSequence::InitializationSequence(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, + unsigned NumArgs) { + ASTContext &Context = S.Context; + + // C++0x [dcl.init]p16: + // The semantics of initializers are as follows. The destination type is + // the type of the object or reference being initialized and the source + // type is the type of the initializer expression. The source type is not + // defined when the initializer is a braced-init-list or when it is a + // parenthesized list of expressions. + QualType DestType = Entity.getType().getType(); + + if (DestType->isDependentType() || + Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { + SequenceKind = DependentSequence; + return; + } + + QualType SourceType; + Expr *Initializer = 0; + if (Kind.getKind() == InitializationKind::IK_Copy) { + Initializer = Args[0]; + if (!isa<InitListExpr>(Initializer)) + SourceType = Initializer->getType(); + } + + // - If the initializer is a braced-init-list, the object is + // list-initialized (8.5.4). + if (InitListExpr *InitList = dyn_cast_or_null<InitListExpr>(Initializer)) { + TryListInitialization(S, Entity, Kind, InitList, *this); + } + + // - If the destination type is a reference type, see 8.5.3. + if (DestType->isReferenceType()) { + // C++0x [dcl.init.ref]p1: + // A variable declared to be a T& or T&&, that is, "reference to type T" + // (8.3.2), shall be initialized by an object, or function, of type T or + // by an object that can be converted into a T. + // (Therefore, multiple arguments are not permitted.) + if (NumArgs != 1) + SetFailed(FK_TooManyInitsForReference); + else + TryReferenceInitialization(S, Entity, Kind, Args[0], *this); + return; + } + + // - If the destination type is an array of characters, an array of + // char16_t, an array of char32_t, or an array of wchar_t, and the + // initializer is a string literal, see 8.5.2. + if (Initializer && IsStringInit(Initializer, DestType, Context)) { + TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); + return; + } + + // - If the initializer is (), the object is value-initialized. + if (Kind.getKind() == InitializationKind::IK_Value) { + TryValueInitialization(S, Entity, Kind, *this); + return; + } + + // - Otherwise, if the destination type is an array, the program is + // ill-formed. + if (const ArrayType *AT = Context.getAsArrayType(DestType)) { + if (AT->getElementType()->isAnyCharacterType()) + SetFailed(FK_ArrayNeedsInitListOrStringLiteral); + else + SetFailed(FK_ArrayNeedsInitList); + + return; + } + + // - If the destination type is a (possibly cv-qualified) class type: + if (DestType->isRecordType()) { + // - 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 + // class of the destination, constructors are considered. [...] + if (Kind.getKind() == InitializationKind::IK_Direct || + (Kind.getKind() == InitializationKind::IK_Copy && + (Context.hasSameUnqualifiedType(SourceType, DestType) || + S.IsDerivedFrom(SourceType, DestType)))) + TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, *this); + // - Otherwise (i.e., for the remaining copy-initialization cases), + // user-defined conversion sequences that can convert from the source + // type to the destination type or (when a conversion function is + // used) to a derived class thereof are enumerated as described in + // 13.3.1.4, and the best one is chosen through overload resolution + // (13.3). + else + TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); + return; + } + + // - Otherwise, if the source type is a (possibly cv-qualified) class + // type, conversion functions are considered. + if (SourceType->isRecordType()) { + TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); + return; + } + + // - Otherwise, the initial value of the object being initialized is the + // (possibly converted) value of the ini- tializer expression. Standard + // conversions (Clause 4) will be used, if necessary, to convert the + // initializer expression to the cv-unqualified version of the + // destination type; no user-defined conversions are considered. + TryImplicitConversion(S, Entity, Kind, Initializer, *this); +} + +InitializationSequence::~InitializationSequence() { + for (llvm::SmallVectorImpl<Step>::iterator Step = Steps.begin(), + StepEnd = Steps.end(); + Step != StepEnd; ++Step) + Step->Destroy(); +} + +//===----------------------------------------------------------------------===// +// Perform initialization +//===----------------------------------------------------------------------===// + +Action::OwningExprResult +InitializationSequence::Perform(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Action::MultiExprArg Args) { + if (SequenceKind == FailedSequence) { + unsigned NumArgs = Args.size(); + Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs); + return S.ExprError(); + } + + if (SequenceKind == DependentSequence) { + if (Kind.getKind() == InitializationKind::IK_Copy) + return Sema::OwningExprResult(S, Args.release()[0]); + + unsigned NumArgs = Args.size(); + return S.Owned(new (S.Context) ParenListExpr(S.Context, + SourceLocation(), + (Expr **)Args.release(), + NumArgs, + SourceLocation())); + } + + QualType DestType = Entity.getType().getType().getNonReferenceType(); + + Sema::OwningExprResult CurInit(S); + // For copy initialization and any other initialization forms that + // only have a single initializer, we start with the (only) + // initializer we have. + // FIXME: DPG is not happy about this. There's confusion regarding whether + // we're supposed to start the conversion from the solitary initializer or + // from the set of arguments. + if (Kind.getKind() == InitializationKind::IK_Copy || + SequenceKind == ReferenceBinding) { + assert(Args.size() == 1); + CurInit = Sema::OwningExprResult(S, Args.release()[0]); + if (CurInit.isInvalid()) + return S.ExprError(); + } + + // Walk through the computed steps for the initialization sequence, + // performing the specified conversions along the way. + for (step_iterator Step = step_begin(), StepEnd = step_end(); + Step != StepEnd; ++Step) { + if (CurInit.isInvalid()) + return S.ExprError(); + + Expr *CurInitExpr = (Expr *)CurInit.get(); + QualType SourceType = CurInitExpr->getType(); + + switch (Step->Kind) { + case SK_ResolveAddressOfOverloadedFunction: + // Overload resolution determined which function invoke; update the + // initializer to reflect that choice. + CurInit = S.FixOverloadedFunctionReference(move(CurInit), Step->Function); + break; + + case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseLValue: { + // We have a derived-to-base cast that produces either an rvalue or an + // lvalue. Perform that cast. + + // Casts to inaccessible base classes are allowed with C-style casts. + bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); + if (S.CheckDerivedToBaseConversion(SourceType, Step->Type, + CurInitExpr->getLocStart(), + CurInitExpr->getSourceRange(), + IgnoreBaseAccess)) + return S.ExprError(); + + CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type, + CastExpr::CK_DerivedToBase, + (Expr*)CurInit.release(), + Step->Kind == SK_CastDerivedToBaseLValue)); + break; + } + + case SK_BindReference: + if (FieldDecl *BitField = CurInitExpr->getBitField()) { + // References cannot bind to bit fields (C++ [dcl.init.ref]p5). + S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield) + << Entity.getType().getType().isVolatileQualified() + << BitField->getDeclName() + << CurInitExpr->getSourceRange(); + S.Diag(BitField->getLocation(), diag::note_bitfield_decl); + return S.ExprError(); + } + + // Reference binding does not have any corresponding ASTs. + + // Check exception specifications + if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) + return S.ExprError(); + break; + + case SK_BindReferenceToTemporary: + // Check exception specifications + if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) + return S.ExprError(); + + // FIXME: At present, we have no AST to describe when we need to make a + // temporary to bind a reference to. We should. + break; + + case SK_UserConversion: { + // We have a user-defined conversion that invokes either a constructor + // or a conversion function. + CastExpr::CastKind CastKind = CastExpr::CK_Unknown; + if (CXXConstructorDecl *Constructor + = dyn_cast<CXXConstructorDecl>(Step->Function)) { + // Build a call to the selected constructor. + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + SourceLocation Loc = CurInitExpr->getLocStart(); + CurInit.release(); // Ownership transferred into MultiExprArg, below. + + // Determine the arguments required to actually perform the constructor + // call. + if (S.CompleteConstructorCall(Constructor, + Sema::MultiExprArg(S, + (void **)&CurInitExpr, + 1), + Loc, ConstructorArgs)) + return S.ExprError(); + + // Build the an expression that constructs a temporary. + CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, + move_arg(ConstructorArgs)); + if (CurInit.isInvalid()) + return S.ExprError(); + + CastKind = CastExpr::CK_ConstructorConversion; + } 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. + if (S.PerformObjectArgumentInitialization(CurInitExpr, Conversion)) + return S.ExprError(); + + // Do a little dance to make sure that CurInit has the proper + // pointer. + CurInit.release(); + + // Build the actual call to the conversion function. + CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, Conversion)); + if (CurInit.isInvalid() || !CurInit.get()) + return S.ExprError(); + + CastKind = CastExpr::CK_UserDefinedConversion; + } + + CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + CurInitExpr = CurInit.takeAs<Expr>(); + CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), + CastKind, + CurInitExpr, + false)); + break; + } + + case SK_QualificationConversionLValue: + case SK_QualificationConversionRValue: + // Perform a qualification conversion; these can never go wrong. + S.ImpCastExprToType(CurInitExpr, Step->Type, + CastExpr::CK_NoOp, + Step->Kind == SK_QualificationConversionLValue); + CurInit.release(); + CurInit = S.Owned(CurInitExpr); + break; + + case SK_ConversionSequence: + if (S.PerformImplicitConversion(CurInitExpr, Step->Type, "converting", + false, false, *Step->ICS)) + return S.ExprError(); + + CurInit.release(); + CurInit = S.Owned(CurInitExpr); + break; + } + } + + return move(CurInit); +} + +//===----------------------------------------------------------------------===// +// Diagnose initialization failures +//===----------------------------------------------------------------------===// +bool InitializationSequence::Diagnose(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs) { + if (SequenceKind != FailedSequence) + return false; + + QualType DestType = Entity.getType().getType(); + switch (Failure) { + case FK_TooManyInitsForReference: + S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits) + << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); + break; + + case FK_ArrayNeedsInitList: + case FK_ArrayNeedsInitListOrStringLiteral: + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) + << (Failure == FK_ArrayNeedsInitListOrStringLiteral); + break; + + case FK_AddressOfOverloadFailed: + S.ResolveAddressOfOverloadedFunction(Args[0], + DestType.getNonReferenceType(), + true); + break; + + case FK_ReferenceInitOverloadFailed: + switch (FailedOverloadResult) { + case OR_Ambiguous: + S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition) + << Args[0]->getType() << DestType.getNonReferenceType() + << Args[0]->getSourceRange(); + S.PrintOverloadCandidates(FailedCandidateSet, true); + break; + + case OR_No_Viable_Function: + S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) + << Args[0]->getType() << DestType.getNonReferenceType() + << Args[0]->getSourceRange(); + S.PrintOverloadCandidates(FailedCandidateSet, false); + break; + + case OR_Deleted: { + S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function) + << Args[0]->getType() << DestType.getNonReferenceType() + << Args[0]->getSourceRange(); + OverloadCandidateSet::iterator Best; + OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet, + Kind.getLocation(), + Best); + if (Ovl == OR_Deleted) { + S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) + << Best->Function->isDeleted(); + } else { + llvm::llvm_unreachable("Inconsistent overload resolution?"); + } + break; + } + + case OR_Success: + llvm::llvm_unreachable("Conversion did not fail!"); + break; + } + break; + + case FK_NonConstLValueReferenceBindingToTemporary: + case FK_NonConstLValueReferenceBindingToUnrelated: + S.Diag(Kind.getLocation(), + Failure == FK_NonConstLValueReferenceBindingToTemporary + ? diag::err_lvalue_reference_bind_to_temporary + : diag::err_lvalue_reference_bind_to_unrelated) + << DestType.getNonReferenceType() + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_RValueReferenceBindingToLValue: + S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref) + << Args[0]->getSourceRange(); + break; + + case FK_ReferenceInitDropsQualifiers: + S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) + << DestType.getNonReferenceType() + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_ReferenceInitFailed: + S.Diag(Kind.getLocation(), diag::err_reference_bind_failed) + << DestType.getNonReferenceType() + << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_ConversionFailed: + S.Diag(Kind.getLocation(), diag::err_cannot_initialize_decl_noname) + << DestType + << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + } + + return true; +} diff --git a/clang/lib/Sema/SemaInit.h b/clang/lib/Sema/SemaInit.h index e69de29bb2d..85aa421db67 100644 --- a/clang/lib/Sema/SemaInit.h +++ b/clang/lib/Sema/SemaInit.h @@ -0,0 +1,530 @@ +//===--- SemaInit.h - Semantic Analysis for Initializers ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides supporting data types for initialization of objects. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_INIT_H +#define LLVM_CLANG_SEMA_INIT_H + +#include "SemaOverload.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Parse/Action.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> + +namespace clang { + +class CXXBaseSpecifier; +class DeclaratorDecl; +class DeclaratorInfo; +class FieldDecl; +class FunctionDecl; +class ParmVarDecl; +class Sema; +class TypeLoc; +class VarDecl; + +/// \brief Describes an entity that is being initialized. +class InitializedEntity { +public: + /// \brief Specifies the kind of entity being initialized. + enum EntityKind { + /// \brief The entity being initialized is a variable. + EK_Variable, + /// \brief The entity being initialized is a function parameter. + EK_Parameter, + /// \brief The entity being initialized is the result of a function call. + EK_Result, + /// \brief The entity being initialized is an exception object that + /// is being thrown. + EK_Exception, + /// \brief The entity being initialized is a temporary object. + EK_Temporary, + /// \brief The entity being initialized is a base member subobject. + EK_Base, + /// \brief The entity being initialized is a non-static data member + /// subobject. + EK_Member + }; + +private: + /// \brief The kind of entity being initialized. + EntityKind Kind; + + /// \brief The type of the object or reference being initialized along with + /// its location information. + TypeLoc TL; + + union { + /// \brief When Kind == EK_Variable, EK_Parameter, or EK_Member, + /// 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. + unsigned Location; + + /// \brief When Kind == EK_Base, the base specifier that provides the + /// base class. + CXXBaseSpecifier *Base; + }; + + InitializedEntity() { } + + /// \brief Create the initialization entity for a variable. + InitializedEntity(VarDecl *Var) + : Kind(EK_Variable), + VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Var)) + { + InitDeclLoc(); + } + + /// \brief Create the initialization entity for a parameter. + InitializedEntity(ParmVarDecl *Parm) + : Kind(EK_Parameter), + VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Parm)) + { + InitDeclLoc(); + } + + /// \brief Create the initialization entity for the result of a function, + /// throwing an object, or performing an explicit cast. + InitializedEntity(EntityKind Kind, SourceLocation Loc, TypeLoc TL) + : Kind(Kind), TL(TL), Location(Loc.getRawEncoding()) { } + + /// \brief Create the initialization entity for a member subobject. + InitializedEntity(FieldDecl *Member) + : Kind(EK_Member), + VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Member)) + { + InitDeclLoc(); + } + + /// \brief Initialize type-location information from a declaration. + void InitDeclLoc(); + +public: + /// \brief Create the initialization entity for a variable. + static InitializedEntity InitializeVariable(VarDecl *Var) { + return InitializedEntity(Var); + } + + /// \brief Create the initialization entity for a parameter. + static InitializedEntity InitializeParameter(ParmVarDecl *Parm) { + return InitializedEntity(Parm); + } + + /// \brief Create the initialization entity for the result of a function. + static InitializedEntity InitializeResult(SourceLocation ReturnLoc, + TypeLoc TL) { + return InitializedEntity(EK_Result, ReturnLoc, TL); + } + + /// \brief Create the initialization entity for an exception object. + static InitializedEntity InitializeException(SourceLocation ThrowLoc, + TypeLoc TL) { + return InitializedEntity(EK_Exception, ThrowLoc, TL); + } + + /// \brief Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(EntityKind Kind, TypeLoc TL) { + return InitializedEntity(Kind, SourceLocation(), TL); + } + + /// \brief Create the initialization entity for a base class subobject. + static InitializedEntity InitializeBase(ASTContext &Context, + CXXBaseSpecifier *Base); + + /// \brief Create the initialize entity for a member subobject. + static InitializedEntity InitializeMember(FieldDecl *Member) { + return InitializedEntity(Member); + } + + /// \brief Determine the kind of initialization. + EntityKind getKind() const { return Kind; } + + /// \brief Retrieve type being initialized. + TypeLoc getType() const { return TL; } + + /// \brief Determine the location of the 'return' keyword when initializing + /// the result of a function call. + SourceLocation getReturnLoc() const { + assert(getKind() == EK_Result && "No 'return' location!"); + return SourceLocation::getFromRawEncoding(Location); + } + + /// \brief Determine the location of the 'throw' keyword when initializing + /// an exception object. + SourceLocation getThrowLoc() const { + assert(getKind() == EK_Exception && "No 'throw' location!"); + return SourceLocation::getFromRawEncoding(Location); + } +}; + +/// \brief Describes the kind of initialization being performed, along with +/// location information for tokens related to the initialization (equal sign, +/// parentheses). +class InitializationKind { +public: + /// \brief The kind of initialization being performed. + enum InitKind { + IK_Direct, ///< Direct initialization + IK_Copy, ///< Copy initialization + IK_Default, ///< Default initialization + IK_Value ///< Value initialization + }; + +private: + /// \brief The kind of initialization that we're storing. + enum StoredInitKind { + SIK_Direct = IK_Direct, ///< Direct initialization + SIK_Copy = IK_Copy, ///< Copy initialization + SIK_Default = IK_Default, ///< Default initialization + SIK_Value = IK_Value, ///< Value initialization + SIK_DirectCast, ///< Direct initialization due to a cast + /// \brief Direct initialization due to a C-style or functional cast. + SIK_DirectCStyleOrFunctionalCast + }; + + /// \brief The kind of initialization being performed. + StoredInitKind Kind; + + /// \brief The source locations involved in the initialization. + SourceLocation Locations[3]; + + InitializationKind(StoredInitKind Kind, SourceLocation Loc1, + SourceLocation Loc2, SourceLocation Loc3) + : Kind(Kind) + { + Locations[0] = Loc1; + Locations[1] = Loc2; + Locations[2] = Loc3; + } + +public: + /// \brief Create a direct initialization. + static InitializationKind CreateDirect(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return InitializationKind(SIK_Direct, InitLoc, LParenLoc, RParenLoc); + } + + /// \brief Create a direct initialization due to a cast. + static InitializationKind CreateCast(SourceRange TypeRange, + bool IsCStyleCast) { + return InitializationKind(IsCStyleCast? SIK_DirectCStyleOrFunctionalCast + : SIK_DirectCast, + TypeRange.getBegin(), TypeRange.getBegin(), + TypeRange.getEnd()); + } + + /// \brief Create a copy initialization. + static InitializationKind CreateCopy(SourceLocation InitLoc, + SourceLocation EqualLoc) { + return InitializationKind(SIK_Copy, InitLoc, EqualLoc, EqualLoc); + } + + /// \brief Create a default initialization. + static InitializationKind CreateDefault(SourceLocation InitLoc) { + return InitializationKind(SIK_Default, InitLoc, InitLoc, InitLoc); + } + + /// \brief Create a value initialization. + static InitializationKind CreateValue(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return InitializationKind(SIK_Value, InitLoc, LParenLoc, RParenLoc); + } + + /// \brief Determine the initialization kind. + InitKind getKind() const { + if (Kind > SIK_Value) + return IK_Direct; + + return (InitKind)Kind; + } + + /// \brief Determine whether this initialization is an explicit cast. + bool isExplicitCast() const { + return Kind == SIK_DirectCast || Kind == SIK_DirectCStyleOrFunctionalCast; + } + + /// \brief Determine whether this initialization is a C-style cast. + bool isCStyleOrFunctionalCast() const { + return Kind == SIK_DirectCStyleOrFunctionalCast; + } + + /// \brief Retrieve the location at which initialization is occurring. + SourceLocation getLocation() const { return Locations[0]; } + + /// \brief Retrieve the source range that covers the initialization. + SourceRange getRange() const { + return SourceRange(Locations[0], Locations[1]); + } + + /// \brief Retrieve the location of the equal sign for copy initialization + /// (if present). + SourceLocation getEqualLoc() const { + assert(Kind == SIK_Copy && "Only copy initialization has an '='"); + return Locations[1]; + } + + /// \brief Retrieve the source range containing the locations of the open + /// and closing parentheses for value and direct initializations. + SourceRange getParenRange() const { + assert((getKind() == IK_Direct || Kind == SIK_Value) && + "Only direct- and value-initialization have parentheses"); + return SourceRange(Locations[1], Locations[2]); + } +}; + +/// \brief Describes the sequence of initializations required to initialize +/// a given object or reference with a set of arguments. +class InitializationSequence { +public: + /// \brief Describes the kind of initialization sequence computed. + enum SequenceKind { + /// \brief A failed initialization sequence. The failure kind tells what + /// happened. + FailedSequence = 0, + + /// \brief A dependent initialization, which could not be + /// type-checked due to the presence of dependent types or + /// dependently-type expressions. + DependentSequence, + + /// \brief A reference binding. + ReferenceBinding + }; + + /// \brief Describes the kind of a particular step in an initialization + /// sequence. + enum StepKind { + /// \brief Resolve the address of an overloaded function to a specific + /// function declaration. + SK_ResolveAddressOfOverloadedFunction, + /// \brief Perform a derived-to-base cast, producing an rvalue. + SK_CastDerivedToBaseRValue, + /// \brief Perform a derived-to-base cast, producing an lvalue. + SK_CastDerivedToBaseLValue, + /// \brief Reference binding to an lvalue. + SK_BindReference, + /// \brief Reference binding to a temporary. + SK_BindReferenceToTemporary, + /// \brief Perform a user-defined conversion, either via a conversion + /// function or via a constructor. + SK_UserConversion, + /// \brief Perform a qualification conversion, producing an rvalue. + SK_QualificationConversionRValue, + /// \brief Perform a qualification conversion, producing an lvalue. + SK_QualificationConversionLValue, + /// \brief Perform an implicit conversion sequence. + SK_ConversionSequence + }; + + /// \brief A single step in the initialization sequence. + class Step { + public: + /// \brief The kind of conversion or initialization step we are taking. + StepKind Kind; + + // \brief The type that results from this initialization. + QualType Type; + + union { + /// \brief When Kind == SK_ResolvedOverloadedFunction or Kind == + /// SK_UserConversion, the function that the expression should be + /// resolved to or the conversion function to call, respectively. + FunctionDecl *Function; + + /// \brief When Kind = SK_ConversionSequence, the implicit conversion + /// sequence + ImplicitConversionSequence *ICS; + }; + + void Destroy(); + }; + +private: + /// \brief The kind of initialization sequence computed. + enum SequenceKind SequenceKind; + + /// \brief Steps taken by this initialization. + llvm::SmallVector<Step, 4> Steps; + +public: + /// \brief Describes why initialization failed. + enum FailureKind { + /// \brief Too many initializers provided for a reference. + FK_TooManyInitsForReference, + /// \brief Array must be initialized with an initializer list. + FK_ArrayNeedsInitList, + /// \brief Array must be initialized with an initializer list or a + /// string literal. + FK_ArrayNeedsInitListOrStringLiteral, + /// \brief Cannot resolve the address of an overloaded function. + FK_AddressOfOverloadFailed, + /// \brief Overloading due to reference initialization failed. + FK_ReferenceInitOverloadFailed, + /// \brief Non-const lvalue reference binding to a temporary. + FK_NonConstLValueReferenceBindingToTemporary, + /// \brief Non-const lvalue reference binding to an lvalue of unrelated + /// type. + FK_NonConstLValueReferenceBindingToUnrelated, + /// \brief Rvalue reference binding to an lvalue. + FK_RValueReferenceBindingToLValue, + /// \brief Reference binding drops qualifiers. + FK_ReferenceInitDropsQualifiers, + /// \brief Reference binding failed. + FK_ReferenceInitFailed, + /// \brief Implicit conversion failed. + FK_ConversionFailed + }; + +private: + /// \brief The reason why initialization failued. + FailureKind Failure; + + /// \brief The failed result of overload resolution. + OverloadingResult FailedOverloadResult; + + /// \brief The candidate set created when initialization failed. + OverloadCandidateSet FailedCandidateSet; + +public: + /// \brief Try to perform initialization of the given entity, creating a + /// record of the steps required to perform the initialization. + /// + /// The generated initialization sequence will either contain enough + /// information to diagnose + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization. + /// + /// \param NumArgs the number of arguments provided for initialization. + InitializationSequence(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, + unsigned NumArgs); + + ~InitializationSequence(); + + /// \brief Perform the actual initialization of the given entity based on + /// the computed initialization sequence. + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization, ownership of + /// which is transfered into the routine. + /// + /// \returns an expression that performs the actual object initialization, if + /// the initialization is well-formed. Otherwise, emits diagnostics + /// and returns an invalid expression. + Action::OwningExprResult Perform(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Action::MultiExprArg Args); + + /// \brief Diagnose an potentially-invalid initialization sequence. + /// + /// \returns true if the initialization sequence was ill-formed, + /// false otherwise. + bool Diagnose(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs); + + /// \brief Determine the kind of initialization sequence computed. + enum SequenceKind getKind() const { return SequenceKind; } + + /// \brief Set the kind of sequence computed. + void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; } + + /// \brief Determine whether the initialization sequence is valid. + operator bool() const { return SequenceKind != FailedSequence; } + + typedef llvm::SmallVector<Step, 4>::const_iterator step_iterator; + step_iterator step_begin() const { return Steps.begin(); } + step_iterator step_end() const { return Steps.end(); } + + /// \brief Add a new step in the initialization that resolves the address + /// of an overloaded function to a specific function declaration. + /// + /// \param Function the function to which the overloaded function reference + /// resolves. + void AddAddressOverloadResolutionStep(FunctionDecl *Function); + + /// \brief Add a new step in the initialization that performs a derived-to- + /// base cast. + /// + /// \param BaseType the base type to which we will be casting. + /// + /// \param IsLValue true if the result of this cast will be treated as + /// an lvalue. + void AddDerivedToBaseCastStep(QualType BaseType, bool IsLValue); + + /// \brief Add a new step binding a reference to an object. + /// + /// \param BindingTemporary true if we are binding a reference to a temporary + /// object (thereby extending its lifetime); false if we are binding to an + /// lvalue or an lvalue treated as an rvalue. + void AddReferenceBindingStep(QualType T, bool BindingTemporary); + + /// \brief Add a new step invoking a conversion function, which is either + /// a constructor or a conversion function. + void AddUserConversionStep(FunctionDecl *Function); + + /// \brief Add a new step that performs a qualification conversion to the + /// given type. + void AddQualificationConversionStep(QualType Ty, bool IsLValue); + + /// \brief Add a new step that applies an implicit conversion sequence. + void AddConversionSequenceStep(const ImplicitConversionSequence &ICS, + QualType T); + + /// \brief Note that this initialization sequence failed. + void SetFailed(FailureKind Failure) { + SequenceKind = FailedSequence; + this->Failure = Failure; + } + + /// \brief Note that this initialization sequence failed due to failed + /// overload resolution. + void SetOverloadFailure(FailureKind Failure, OverloadingResult Result); + + /// \brief Retrieve a reference to the candidate set when overload + /// resolution fails. + OverloadCandidateSet &getFailedCandidateSet() { + return FailedCandidateSet; + } + + /// \brief Determine why initialization failed. + FailureKind getFailureKind() const { + assert(getKind() == FailedSequence && "Not an initialization failure!"); + return Failure; + } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_INIT_H diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 4443de05380..9ca8d767835 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1399,13 +1399,13 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { /// for overload resolution. /// \param UserCast true if looking for user defined conversion for a static /// cast. -Sema::OverloadingResult Sema::IsUserDefinedConversion( - Expr *From, QualType ToType, - UserDefinedConversionSequence& User, - OverloadCandidateSet& CandidateSet, - bool AllowConversionFunctions, - bool AllowExplicit, bool ForceRValue, - bool UserCast) { +OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, + UserDefinedConversionSequence& User, + OverloadCandidateSet& CandidateSet, + bool AllowConversionFunctions, + bool AllowExplicit, + bool ForceRValue, + bool UserCast) { if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) { if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) { // We're not going to find any constructors. @@ -4167,10 +4167,9 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, /// function, Best points to the candidate function found. /// /// \returns The result of overload resolution. -Sema::OverloadingResult -Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, - SourceLocation Loc, - OverloadCandidateSet::iterator& Best) { +OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, + SourceLocation Loc, + OverloadCandidateSet::iterator& Best) { // Find the best viable function. Best = CandidateSet.end(); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); @@ -5769,4 +5768,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { return E->Retain(); } +Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E, + FunctionDecl *Fn) { + return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Fn)); +} + } // end namespace clang diff --git a/clang/lib/Sema/SemaOverload.h b/clang/lib/Sema/SemaOverload.h index 5eef3cebe41..3613d608834 100644 --- a/clang/lib/Sema/SemaOverload.h +++ b/clang/lib/Sema/SemaOverload.h @@ -15,12 +15,26 @@ #ifndef LLVM_CLANG_SEMA_OVERLOAD_H #define LLVM_CLANG_SEMA_OVERLOAD_H +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" namespace clang { + class ASTContext; class CXXConstructorDecl; + class CXXConversionDecl; class FunctionDecl; + /// OverloadingResult - Capture the result of performing overload + /// resolution. + enum OverloadingResult { + OR_Success, ///< Overload resolution succeeded. + OR_No_Viable_Function, ///< No viable function found. + OR_Ambiguous, ///< Ambiguous candidates found. + OR_Deleted ///< Overload resoltuion refers to a deleted function. + }; + /// ImplicitConversionKind - The kind of implicit conversion used to /// convert an argument to a parameter's type. The enumerator values /// match with Table 9 of (C++ 13.3.3.1.1) and are listed such that @@ -271,6 +285,7 @@ namespace clang { /// OverloadCandidateSet - A set of overload candidates, used in C++ /// overload resolution (C++ 13.3). class OverloadCandidateSet : public llvm::SmallVector<OverloadCandidate, 16> { + typedef llvm::SmallVector<OverloadCandidate, 16> inherited; llvm::SmallPtrSet<Decl *, 16> Functions; public: @@ -279,6 +294,12 @@ namespace clang { bool isNewCandidate(Decl *F) { return Functions.insert(F->getCanonicalDecl()); } + + /// \brief Clear out all of the candidates. + void clear() { + inherited::clear(); + Functions.clear(); + } }; } // end namespace clang diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp new file mode 100644 index 00000000000..66fa2d13984 --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s +int g(int); +void f() { + int i; + int& r = i; + r = 1; + int* p = &r; + int &rr=r; + int (&rg)(int) = g; + rg(i); + int a[3]; + int (&ra)[3] = a; + ra[1] = i; +} diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p3.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p3.cpp new file mode 100644 index 00000000000..54840f52663 --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p3.cpp @@ -0,0 +1,3 @@ +// RUN: clang-cc -fsyntax-only -verify %s +int& r1; // expected-error{{declaration of reference variable 'r1' requires an initializer}} +extern int& r2; diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp new file mode 100644 index 00000000000..5d34345c49f --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp @@ -0,0 +1,53 @@ +// RUN: clang-cc -ast-dump %s 2>&1 | FileCheck %s + +// CHECK: example0 +void example0() { + double d = 2.0; + // CHECK: double &rd = + // CHECK-NEXT: DeclRefExpr + double &rd = d; + // CHECK: double const &rcd = + // CHECK-NEXT: ImplicitCastExpr{{.*}}'double const' <NoOp> + const double &rcd = d; +} + +struct A { }; +struct B : A { } b; + +// CHECK: example1 +void example1() { + // CHECK: struct A &ra = + // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase> lvalue + A &ra = b; + // CHECK: struct A const &rca = + // CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp> + // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase> + const A& rca = b; +} + +extern B f(); + +struct X { + operator B(); +} x; + +// CHECK: example2 +void example2() { + // CHECK: struct A const &rca = + // CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp> + // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase> + // CHECK: CallExpr{{.*}}struct B + const A &rca = f(); + // CHECK: struct A const &r = + // CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp> + // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase> + // CHECK: CXXMemberCallExpr{{.*}}'struct B' + const A& r = x; +} + +// CHECK: example3 +void example3() { + // CHECK: double const &rcd2 = + // CHECK: ImplicitCastExpr{{.*}}<IntegralToFloating> + const double& rcd2 = 2; +} diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp new file mode 100644 index 00000000000..5fa1fff8c86 --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp @@ -0,0 +1,129 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct Base { }; // expected-note{{candidate function}} +struct Derived : Base { }; // expected-note{{candidate function}} +struct Unrelated { }; +struct Derived2 : Base { }; +struct Diamond : Derived, Derived2 { }; + +struct ConvertibleToBaseRef { + operator Base&() const; +}; + +struct ConvertibleToDerivedRef { + operator Derived&() const; +}; + +struct ConvertibleToBothDerivedRef { + operator Derived&(); // expected-note{{candidate function}} + operator Derived2&(); // expected-note{{candidate function}} +}; + +struct ConvertibleToIntRef { + operator int&(); +}; + +struct ConvertibleToBase { + operator Base() const; +}; + +struct ConvertibleToDerived { + operator Derived() const; +}; + +struct ConvertibleToBothDerived { + operator Derived(); // expected-note{{candidate function}} + operator Derived2(); // expected-note{{candidate function}} +}; + +struct ConvertibleToInt { + operator int(); +}; + +template<typename T> T create(); + +// First bullet: lvalue references binding to lvalues (the simple cases). +void bind_lvalue_to_lvalue(Base b, Derived d, + const Base bc, const Derived dc, + Diamond diamond, + int i) { + // Reference-compatible + Base &br1 = b; + Base &br2 = d; + Derived &dr1 = d; + Derived &dr2 = b; // expected-error{{non-const lvalue reference to type 'struct Derived' cannot bind to a value of unrelated type 'struct Base'}} + Base &br3 = bc; // expected-error{{drops qualifiers}} + Base &br4 = dc; // expected-error{{drops qualifiers}} + Base &br5 = diamond; // expected-error{{ambiguous conversion from derived class 'struct Diamond' to base class 'struct Base'}} + int &ir = i; + long &lr = i; // expected-error{{non-const lvalue reference to type 'long' cannot bind to a value of unrelated type 'int'}} +} + +void bind_lvalue_quals(volatile Base b, volatile Derived d, + volatile const Base bvc, volatile const Derived dvc, + volatile const int ivc) { + volatile Base &bvr1 = b; + volatile Base &bvr2 = d; + volatile Base &bvr3 = bvc; // expected-error{{binding of reference to type 'struct Base volatile' to a value of type 'struct Base const volatile' drops qualifiers}} + volatile Base &bvr4 = dvc; // expected-error{{binding of reference to type 'struct Base volatile' to a value of type 'struct Derived const volatile' drops qualifiers}} + + volatile int &ir = ivc; // expected-error{{binding of reference to type 'int volatile' to a value of type 'int const volatile' drops qualifiers}} +} + +void bind_lvalue_to_rvalue() { + Base &br1 = Base(); // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a temporary of type 'struct Base'}} + Base &br2 = Derived(); // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a temporary of type 'struct Derived'}} + + int &ir = 17; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} +} + +void bind_lvalue_to_unrelated(Unrelated ur) { + Base &br1 = ur; // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a value of unrelated type 'struct Unrelated'}} +} + +void bind_lvalue_to_conv_lvalue() { + // Not reference-related, but convertible + Base &nbr1 = ConvertibleToBaseRef(); + Base &nbr2 = ConvertibleToDerivedRef(); + Derived &ndr1 = ConvertibleToDerivedRef(); + int &ir = ConvertibleToIntRef(); +} + +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}} +} + +struct IntBitfield { + int i : 17; // expected-note{{bit-field is declared here}} +}; + +void test_bitfield(IntBitfield ib) { + int & ir1 = (ib.i); // expected-error{{non-const reference cannot bind to bit-field 'i'}} +} + +// Second bullet: const lvalue reference binding to an rvalue with +// similar type (both of which are class types). +void bind_const_lvalue_to_rvalue() { + const Base &br1 = create<Base>(); + const Base &br2 = create<Derived>(); + const Derived &dr1 = create<Base>(); // expected-error{{no viable conversion}} + + const Base &br3 = create<const Base>(); + const Base &br4 = create<const Derived>(); + + const Base &br5 = create<const volatile Base>(); // expected-error{{binding of reference to type 'struct Base const' to a value of type 'struct Base const volatile' drops qualifiers}} + const Base &br6 = create<const volatile Derived>(); // expected-error{{binding of reference to type 'struct Base const' to a value of type 'struct Derived const volatile' drops qualifiers}} + + const int &ir = create<int>(); +} + +// Second bullet: const lvalue reference binds to the result of a conversion. +void bind_const_lvalue_to_class_conv_temporary() { + const Base &br1 = ConvertibleToBase(); + const Base &br2 = ConvertibleToDerived(); +} +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}} +} diff --git a/clang/test/CodeGenCXX/references.cpp b/clang/test/CodeGenCXX/references.cpp index eaaf346d7cc..74dc0ea6d7b 100644 --- a/clang/test/CodeGenCXX/references.cpp +++ b/clang/test/CodeGenCXX/references.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -verify -emit-llvm -o - %s | FileCheck %s - void t1() { extern int& a; int b = a; @@ -19,7 +18,6 @@ void t3() { // Test reference binding. struct C { int a; }; - void f(const bool&); void f(const int&); void f(const _Complex int&); diff --git a/clang/test/SemaCXX/convert-to-bool.cpp b/clang/test/SemaCXX/convert-to-bool.cpp index 937b2729d1c..277bfc6c688 100644 --- a/clang/test/SemaCXX/convert-to-bool.cpp +++ b/clang/test/SemaCXX/convert-to-bool.cpp @@ -49,7 +49,7 @@ void test_explicit_bool(ExplicitConvToBool ecb) { } void test_explicit_conv_to_ref(ExplicitConvToRef ecr) { - int& i1 = ecr; // expected-error{{non-const lvalue reference to type 'int' cannot be initialized with a value of type 'struct ExplicitConvToRef'}} + int& i1 = ecr; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'struct ExplicitConvToRef'}} int& i2(ecr); // okay } @@ -57,11 +57,11 @@ struct A { }; struct B { }; struct C { explicit operator A&(); // expected-warning{{explicit conversion functions are a C++0x extension}} - operator B&(); + operator B&(); // expected-note{{candidate}} }; void test_copy_init_conversions(C c) { - A &a = c; // expected-error{{non-const lvalue reference to type 'struct A' cannot be initialized with a value of type 'struct C'}} + A &a = c; // expected-error{{no viable conversion from 'struct C' to 'struct A'}} B &b = b; // okay } diff --git a/clang/test/SemaCXX/decl-init-ref.cpp b/clang/test/SemaCXX/decl-init-ref.cpp index d7db647cd11..20eb91a608c 100644 --- a/clang/test/SemaCXX/decl-init-ref.cpp +++ b/clang/test/SemaCXX/decl-init-ref.cpp @@ -1,6 +1,6 @@ // RUN: clang-cc -fsyntax-only -verify -std=c++0x %s -struct A {}; +struct A {}; // expected-note {{candidate function}} struct BASE { operator A(); // expected-note {{candidate function}} @@ -21,6 +21,6 @@ extern B f(); const int& ri = (void)0; // expected-error {{invalid initialization of reference of type 'int const &' from expression of type 'void'}} int main() { - const A& rca = f(); // expected-error {{rvalue reference cannot bind to lvalue due to multiple conversion functions}} - A& ra = f(); // expected-error {{non-const lvalue reference to type 'struct A' cannot be initialized with a temporary of type 'class B'}} + const A& rca = f(); // expected-error {{conversion from 'class B' to 'struct A const' 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/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp index 16d37040f14..672b8b4fc26 100644 --- a/clang/test/SemaCXX/overloaded-operator.cpp +++ b/clang/test/SemaCXX/overloaded-operator.cpp @@ -67,7 +67,7 @@ void enum_test(Enum1 enum1, Enum2 enum2, E1 e1, E2 e2) { float &f1 = (e1 == e2); float &f2 = (enum1 == e2); float &f3 = (e1 == enum2); - float &f4 = (enum1 == enum2); // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a temporary of type 'bool'}} + float &f4 = (enum1 == enum2); // expected-error{{non-const lvalue reference to type 'float' cannot bind to a temporary of type 'bool'}} } // PR5244 - Argument-dependent lookup would include the two operators below, diff --git a/clang/test/SemaCXX/ref-init-ambiguous.cpp b/clang/test/SemaCXX/ref-init-ambiguous.cpp index dda1ead7b62..60620993b43 100644 --- a/clang/test/SemaCXX/ref-init-ambiguous.cpp +++ b/clang/test/SemaCXX/ref-init-ambiguous.cpp @@ -3,18 +3,19 @@ enum E2 { }; struct A { - operator E2&(); // expected-note 3 {{candidate function}} + operator E2&(); // expected-note 2 {{candidate function}} }; struct B { - operator E2&(); // expected-note 3 {{candidate function}} + operator E2&(); // expected-note 2 {{candidate function}} }; struct C : B, A { }; void test(C c) { - const E2 &e2 = c; // expected-error {{reference initialization of type 'enum E2 const &' with initializer of type 'struct C' is ambiguous}} + // 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'}} } void foo(const E2 &); diff --git a/clang/test/SemaCXX/references.cpp b/clang/test/SemaCXX/references.cpp index e03abf4300a..45d3923ff0a 100644 --- a/clang/test/SemaCXX/references.cpp +++ b/clang/test/SemaCXX/references.cpp @@ -44,17 +44,17 @@ B fB(); // C++ [dcl.init.ref]p5b2 void test4() { - double& rd2 = 2.0; // expected-error{{non-const lvalue reference to type 'double' cannot be initialized with a temporary of type 'double'}} + double& rd2 = 2.0; // expected-error{{non-const lvalue reference to type 'double' cannot bind to a temporary of type 'double'}} int i = 2; - double& rd3 = i; // expected-error{{non-const lvalue reference to type 'double' cannot be initialized with a value of type 'int'}} + double& rd3 = i; // expected-error{{non-const lvalue reference to type 'double' cannot bind to a value of unrelated type 'int'}} const A& rca = fB(); } void test5() { - const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0 + // const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0 const volatile int cvi = 1; - const int& r = cvi; // expected-error{{initialization of reference to type 'int const' with a value of type 'int const volatile' drops qualifiers}} + const int& r = cvi; // expected-error{{binding of reference to type 'int const' to a value of type 'int const volatile' drops qualifiers}} } // C++ [dcl.init.ref]p3 diff --git a/clang/test/SemaCXX/rval-references.cpp b/clang/test/SemaCXX/rval-references.cpp index 5132c2a69be..7a71607707c 100644 --- a/clang/test/SemaCXX/rval-references.cpp +++ b/clang/test/SemaCXX/rval-references.cpp @@ -44,7 +44,7 @@ void f() { conv_to_not_int_rvalue cnir; not_int &&ni4 = cnir; // expected-error {{rvalue reference cannot bind to lvalue}} - not_int &ni5 = cnir; // expected-error{{non-const lvalue reference to type 'struct not_int' cannot be initialized with a value of type 'struct conv_to_not_int_rvalue'}} + not_int &ni5 = cnir; // expected-error{{non-const lvalue reference to type 'struct not_int' cannot bind to a value of unrelated type 'struct conv_to_not_int_rvalue'}} not_int &&ni6 = conv_to_not_int_rvalue(); diff --git a/clang/test/SemaTemplate/instantiate-expr-4.cpp b/clang/test/SemaTemplate/instantiate-expr-4.cpp index cd74a21d6db..150faec3f2a 100644 --- a/clang/test/SemaTemplate/instantiate-expr-4.cpp +++ b/clang/test/SemaTemplate/instantiate-expr-4.cpp @@ -185,7 +185,7 @@ template struct InitList2<APair, int*, double*>; // expected-note{{instantiation template<typename T, typename Result> struct DotMemRef0 { void f(T t) { - Result result = t.m; // expected-error{{cannot be initialized}} + Result result = t.m; // expected-error{{non-const lvalue reference to type}} } }; @@ -207,7 +207,7 @@ template struct DotMemRef0<MemInt, float&>; // expected-note{{instantiation}} template<typename T, typename Result> struct ArrowMemRef0 { void f(T t) { - Result result = t->m; // expected-error 2{{cannot be initialized}} + Result result = t->m; // expected-error 2{{non-const lvalue reference}} } }; @@ -269,7 +269,7 @@ template struct ThisMemberFuncCall0<int&>; template<typename T> struct NonDepMemberCall0 { void foo(HasMemFunc0<int&> x) { - T result = x.f(); // expected-error{{initialized}} + T result = x.f(); // expected-error{{non-const lvalue reference}} } }; |