diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
commit | 9092c3e0fa01f3139b016d05d267a89e3b07747a (patch) | |
tree | 137ebebcae16fb0ce7ab4af456992bbd8d22fced /lib/Sema/SemaExprCXX.cpp | |
parent | 4981926bf654fe5a2c3893f24ca44106b217e71e (diff) | |
download | FreeBSD-src-9092c3e0fa01f3139b016d05d267a89e3b07747a.zip FreeBSD-src-9092c3e0fa01f3139b016d05d267a89e3b07747a.tar.gz |
Update clang to r84119.
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 1129 |
1 files changed, 837 insertions, 292 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 7afa594..5f111c8 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -11,13 +11,14 @@ // //===----------------------------------------------------------------------===// -#include "SemaInherit.h" #include "Sema.h" -#include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Lex/Preprocessor.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/DeclSpec.h" #include "llvm/ADT/STLExtras.h" using namespace clang; @@ -31,9 +32,10 @@ Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc, TypeTy *Ty, bool HasTrailingLParen, const CXXScopeSpec &SS, bool isAddressOfOperand) { - QualType ConvType = QualType::getFromOpaquePtr(Ty); - QualType ConvTypeCanon = Context.getCanonicalType(ConvType); - DeclarationName ConvName + //FIXME: Preserve type source info. + QualType ConvType = GetTypeFromParser(Ty); + CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType); + DeclarationName ConvName = Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon); return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen, &SS, isAddressOfOperand); @@ -59,12 +61,17 @@ Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc, Action::OwningExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { - NamespaceDecl *StdNs = GetStdNamespace(); - if (!StdNs) + if (!StdNamespace) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - + + if (isType) + // FIXME: Preserve type source info. + TyOrExpr = GetTypeFromParser(TyOrExpr).getAsOpaquePtr(); + IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); - Decl *TypeInfoDecl = LookupQualifiedName(StdNs, TypeInfoII, LookupTagName); + LookupResult R; + LookupQualifiedName(R, StdNamespace, TypeInfoII, LookupTagName); + Decl *TypeInfoDecl = R.getAsSingleDecl(Context); RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl); if (!TypeInfoRecordDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); @@ -73,29 +80,29 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, if (!isType) { // C++0x [expr.typeid]p3: - // When typeid is applied to an expression other than an lvalue of a - // polymorphic class type [...] [the] expression is an unevaluated + // When typeid is applied to an expression other than an lvalue of a + // polymorphic class type [...] [the] expression is an unevaluated // operand. - + // FIXME: if the type of the expression is a class type, the class // shall be completely defined. bool isUnevaluatedOperand = true; Expr *E = static_cast<Expr *>(TyOrExpr); if (E && !E->isTypeDependent() && E->isLvalue(Context) == Expr::LV_Valid) { QualType T = E->getType(); - if (const RecordType *RecordT = T->getAsRecordType()) { + if (const RecordType *RecordT = T->getAs<RecordType>()) { CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); if (RecordD->isPolymorphic()) isUnevaluatedOperand = false; } } - + // If this is an unevaluated operand, clear out the set of declaration // references we have been computing. if (isUnevaluatedOperand) PotentiallyReferencedDeclStack.back().clear(); } - + return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr, TypeInfoType.withConst(), SourceRange(OpLoc, RParenLoc))); @@ -136,15 +143,15 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // to an incomplete type other than (cv) void the program is ill-formed. QualType Ty = E->getType(); int isPointer = 0; - if (const PointerType* Ptr = Ty->getAsPointerType()) { + if (const PointerType* Ptr = Ty->getAs<PointerType>()) { Ty = Ptr->getPointeeType(); isPointer = 1; } if (!isPointer || !Ty->isVoidType()) { if (RequireCompleteType(ThrowLoc, Ty, - isPointer ? diag::err_throw_incomplete_ptr - : diag::err_throw_incomplete, - E->getSourceRange(), SourceRange(), QualType())) + PDiag(isPointer ? diag::err_throw_incomplete_ptr + : diag::err_throw_incomplete) + << E->getSourceRange())) return true; } @@ -179,7 +186,8 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, SourceLocation *CommaLocs, SourceLocation RParenLoc) { assert(TypeRep && "Missing type!"); - QualType Ty = QualType::getFromOpaquePtr(TypeRep); + // FIXME: Preserve type source info. + QualType Ty = GetTypeFromParser(TypeRep); unsigned NumExprs = exprs.size(); Expr **Exprs = (Expr**)exprs.get(); SourceLocation TyBeginLoc = TypeRange.getBegin(); @@ -188,14 +196,27 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) { exprs.release(); - - return Owned(CXXUnresolvedConstructExpr::Create(Context, - TypeRange.getBegin(), Ty, + + return Owned(CXXUnresolvedConstructExpr::Create(Context, + TypeRange.getBegin(), Ty, LParenLoc, Exprs, NumExprs, RParenLoc)); } + if (Ty->isArrayType()) + return ExprError(Diag(TyBeginLoc, + diag::err_value_init_for_array_type) << FullRange); + if (!Ty->isVoidType() && + RequireCompleteType(TyBeginLoc, Ty, + PDiag(diag::err_invalid_incomplete_type_use) + << FullRange)) + return ExprError(); + + if (RequireNonAbstractType(TyBeginLoc, Ty, + diag::err_allocation_of_abstract_type)) + return ExprError(); + // C++ [expr.type.conv]p1: // If the expression list is a single expression, the type conversion @@ -203,36 +224,54 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, // corresponding cast expression. // if (NumExprs == 1) { - if (CheckCastTypes(TypeRange, Ty, Exprs[0])) + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + CXXMethodDecl *Method = 0; + if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, Method, + /*FunctionalStyle=*/true)) return ExprError(); + exprs.release(); + if (Method) { + OwningExprResult CastArg + = BuildCXXCastArgument(TypeRange.getBegin(), Ty.getNonReferenceType(), + Kind, Method, Owned(Exprs[0])); + if (CastArg.isInvalid()) + return ExprError(); + + Exprs[0] = CastArg.takeAs<Expr>(); + } + return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(), - Ty, TyBeginLoc, Exprs[0], - RParenLoc)); + Ty, TyBeginLoc, Kind, + Exprs[0], RParenLoc)); } - if (const RecordType *RT = Ty->getAsRecordType()) { + if (const RecordType *RT = Ty->getAs<RecordType>()) { CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl()); - // FIXME: We should always create a CXXTemporaryObjectExpr here unless - // both the ctor and dtor are trivial. - if (NumExprs > 1 || Record->hasUserDeclaredConstructor()) { + if (NumExprs > 1 || !Record->hasTrivialConstructor() || + !Record->hasTrivialDestructor()) { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + CXXConstructorDecl *Constructor - = PerformInitializationByConstructor(Ty, Exprs, NumExprs, + = PerformInitializationByConstructor(Ty, move(exprs), TypeRange.getBegin(), SourceRange(TypeRange.getBegin(), RParenLoc), DeclarationName(), - IK_Direct); + IK_Direct, + ConstructorArgs); if (!Constructor) return ExprError(); - exprs.release(); - Expr *E = new (Context) CXXTemporaryObjectExpr(Context, Constructor, - Ty, TyBeginLoc, Exprs, - NumExprs, RParenLoc); - return MaybeBindToTemporary(E); + OwningExprResult Result = + BuildCXXTemporaryObjectExpr(Constructor, Ty, TyBeginLoc, + move_arg(ConstructorArgs), RParenLoc); + if (Result.isInvalid()) + return ExprError(); + + return MaybeBindToTemporary(Result.takeAs<Expr>()); } // Fall through to value-initialize an object of class type that @@ -255,18 +294,6 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, // complete object type or the (possibly cv-qualified) void type, creates an // rvalue of the specified type, which is value-initialized. // - if (Ty->isArrayType()) - return ExprError(Diag(TyBeginLoc, - diag::err_value_init_for_array_type) << FullRange); - if (!Ty->isDependentType() && !Ty->isVoidType() && - RequireCompleteType(TyBeginLoc, Ty, - diag::err_invalid_incomplete_type_use, FullRange)) - return ExprError(); - - if (RequireNonAbstractType(TyBeginLoc, Ty, - diag::err_allocation_of_abstract_type)) - return ExprError(); - exprs.release(); return Owned(new (Context) CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc)); } @@ -283,8 +310,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementRParen, bool ParenTypeId, Declarator &D, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, - SourceLocation ConstructorRParen) -{ + SourceLocation ConstructorRParen) { Expr *ArraySize = 0; unsigned Skip = 0; // If the specified type is an array, unwrap it and save the expression. @@ -301,29 +327,37 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, Skip = 1; } - QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip); - if (D.isInvalidType()) - return ExprError(); - // Every dimension shall be of constant size. - unsigned i = 1; - QualType ElementType = AllocType; - while (const ArrayType *Array = Context.getAsArrayType(ElementType)) { - if (!Array->isConstantArrayType()) { - Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst) - << static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange(); - return ExprError(); + if (D.getNumTypeObjects() > 0 && + D.getTypeObject(0).Kind == DeclaratorChunk::Array) { + for (unsigned I = 1, N = D.getNumTypeObjects(); I < N; ++I) { + if (D.getTypeObject(I).Kind != DeclaratorChunk::Array) + break; + + DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr; + if (Expr *NumElts = (Expr *)Array.NumElts) { + if (!NumElts->isTypeDependent() && !NumElts->isValueDependent() && + !NumElts->isIntegerConstantExpr(Context)) { + Diag(D.getTypeObject(I).Loc, diag::err_new_array_nonconst) + << NumElts->getSourceRange(); + return ExprError(); + } + } } - ElementType = Array->getElementType(); - ++i; } + + //FIXME: Store DeclaratorInfo in CXXNew expression. + DeclaratorInfo *DInfo = 0; + QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo, Skip); + if (D.isInvalidType()) + return ExprError(); - return BuildCXXNew(StartLoc, UseGlobal, + return BuildCXXNew(StartLoc, UseGlobal, PlacementLParen, - move(PlacementArgs), + move(PlacementArgs), PlacementRParen, ParenTypeId, - AllocType, + AllocType, D.getSourceRange().getBegin(), D.getSourceRange(), Owned(ArraySize), @@ -332,12 +366,12 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, ConstructorRParen); } -Sema::OwningExprResult +Sema::OwningExprResult Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, - bool ParenTypeId, + bool ParenTypeId, QualType AllocType, SourceLocation TypeLoc, SourceRange TypeRange, @@ -369,12 +403,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, llvm::APSInt Value; if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) { if (Value < llvm::APSInt( - llvm::APInt::getNullValue(Value.getBitWidth()), false)) + llvm::APInt::getNullValue(Value.getBitWidth()), + Value.isUnsigned())) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); } } + + ImpCastExprToType(ArraySize, Context.getSizeType()); } FunctionDecl *OperatorNew = 0; @@ -413,17 +450,24 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, unsigned NumConsArgs = ConstructorArgs.size(); if (AllocType->isDependentType()) { // Skip all the checks. - } - else if ((RT = AllocType->getAsRecordType()) && - !AllocType->isAggregateType()) { + } else if ((RT = AllocType->getAs<RecordType>()) && + !AllocType->isAggregateType()) { + ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this); + Constructor = PerformInitializationByConstructor( - AllocType, ConsArgs, NumConsArgs, + AllocType, move(ConstructorArgs), TypeLoc, SourceRange(TypeLoc, ConstructorRParen), RT->getDecl()->getDeclName(), - NumConsArgs != 0 ? IK_Direct : IK_Default); + NumConsArgs != 0 ? IK_Direct : IK_Default, + ConvertedConstructorArgs); if (!Constructor) return ExprError(); + + // Take the converted constructor arguments and use them for the new + // expression. + NumConsArgs = ConvertedConstructorArgs.size(); + ConsArgs = (Expr **)ConvertedConstructorArgs.take(); } else { if (!Init) { // FIXME: Check that no subpart is const. @@ -454,15 +498,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init, ConsArgs, NumConsArgs, OperatorDelete, ResultType, - StartLoc, Init ? ConstructorRParen : SourceLocation())); + StartLoc, Init ? ConstructorRParen : SourceLocation())); } /// CheckAllocatedType - Checks that a type is suitable as the allocated type /// in a new-expression. /// dimension off and stores the size expression in ArraySize. bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, - SourceRange R) -{ + SourceRange R) { // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an // abstract class type or array thereof. if (AllocType->isFunctionType()) @@ -473,8 +516,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, << AllocType << 1 << R; else if (!AllocType->isDependentType() && RequireCompleteType(Loc, AllocType, - diag::err_new_incomplete_type, - R)) + PDiag(diag::err_new_incomplete_type) + << R)) return true; else if (RequireNonAbstractType(Loc, AllocType, diag::err_allocation_of_abstract_type)) @@ -490,8 +533,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool IsArray, Expr **PlaceArgs, unsigned NumPlaceArgs, FunctionDecl *&OperatorNew, - FunctionDecl *&OperatorDelete) -{ + FunctionDecl *&OperatorDelete) { // --- Choosing an allocation function --- // C++ 5.3.4p8 - 14 & 18 // 1) If UseGlobal is true, only look in the global scope. Else, also look @@ -506,17 +548,18 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // We don't care about the actual value of this argument. // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? - AllocArgs[0] = new (Context) IntegerLiteral(llvm::APInt::getNullValue( - Context.Target.getPointerWidth(0)), - Context.getSizeType(), - SourceLocation()); + IntegerLiteral Size(llvm::APInt::getNullValue( + Context.Target.getPointerWidth(0)), + Context.getSizeType(), + SourceLocation()); + AllocArgs[0] = &Size; std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1); DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); if (AllocType->isRecordType() && !UseGlobal) { - CXXRecordDecl *Record - = cast<CXXRecordDecl>(AllocType->getAsRecordType()->getDecl()); + CXXRecordDecl *Record + = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl()); // FIXME: We fail to find inherited overloads. if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0], AllocArgs.size(), Record, /*AllowMissing=*/true, @@ -537,10 +580,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // copy them back. if (NumPlaceArgs > 0) std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs); - - // FIXME: This is leaked on error. But so much is currently in Sema that it's - // easier to clean it in one go. - AllocArgs[0]->Destroy(Context); + return false; } @@ -549,24 +589,30 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, DeclarationName Name, Expr** Args, unsigned NumArgs, DeclContext *Ctx, - bool AllowMissing, FunctionDecl *&Operator) -{ - DeclContext::lookup_iterator Alloc, AllocEnd; - llvm::tie(Alloc, AllocEnd) = Ctx->lookup(Name); - if (Alloc == AllocEnd) { + bool AllowMissing, FunctionDecl *&Operator) { + LookupResult R; + LookupQualifiedName(R, Ctx, Name, LookupOrdinaryName); + if (R.empty()) { if (AllowMissing) return false; return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) << Name << Range; } + // FIXME: handle ambiguity + OverloadCandidateSet Candidates; - for (; Alloc != AllocEnd; ++Alloc) { + for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); + Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. - if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc)) + if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc)) { AddOverloadCandidate(Fn, Args, NumArgs, Candidates, /*SuppressUserConversions=*/false); + continue; + } + + // FIXME: Handle function templates } // Do the resolution. @@ -578,7 +624,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // The first argument is size_t, and the first parameter must be size_t, // too. This is checked on declaration and can be assumed. (It can't be // asserted on, though, since invalid decls are left in there.) - for (unsigned i = 1; i < NumArgs; ++i) { + for (unsigned i = 0; i < NumArgs; ++i) { // FIXME: Passing word to diagnostic. if (PerformCopyInitialization(Args[i], FnDecl->getParamDecl(i)->getType(), @@ -623,16 +669,52 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, /// @endcode /// Note that the placement and nothrow forms of new are *not* implicitly /// declared. Their use requires including \<new\>. -void Sema::DeclareGlobalNewDelete() -{ +void Sema::DeclareGlobalNewDelete() { if (GlobalNewDeleteDeclared) return; + + // C++ [basic.std.dynamic]p2: + // [...] The following allocation and deallocation functions (18.4) are + // implicitly declared in global scope in each translation unit of a + // program + // + // void* operator new(std::size_t) throw(std::bad_alloc); + // void* operator new[](std::size_t) throw(std::bad_alloc); + // void operator delete(void*) throw(); + // void operator delete[](void*) throw(); + // + // These implicit declarations introduce only the function names operator + // new, operator new[], operator delete, operator delete[]. + // + // Here, we need to refer to std::bad_alloc, so we will implicitly declare + // "std" or "bad_alloc" as necessary to form the exception specification. + // However, we do not make these implicit declarations visible to name + // lookup. + if (!StdNamespace) { + // The "std" namespace has not yet been defined, so build one implicitly. + StdNamespace = NamespaceDecl::Create(Context, + Context.getTranslationUnitDecl(), + SourceLocation(), + &PP.getIdentifierTable().get("std")); + StdNamespace->setImplicit(true); + } + + if (!StdBadAlloc) { + // The "std::bad_alloc" class has not yet been declared, so build it + // implicitly. + StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class, + StdNamespace, + SourceLocation(), + &PP.getIdentifierTable().get("bad_alloc"), + SourceLocation(), 0); + StdBadAlloc->setImplicit(true); + } + GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); QualType SizeT = Context.getSizeType(); - // FIXME: Exception specifications are not added. DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_New), VoidPtr, SizeT); @@ -650,8 +732,7 @@ void Sema::DeclareGlobalNewDelete() /// DeclareGlobalAllocationFunction - Declares a single implicit global /// allocation function if it doesn't already exist. void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, - QualType Return, QualType Argument) -{ + QualType Return, QualType Argument) { DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); // Check if this function is already declared. @@ -667,14 +748,26 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, } } - QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0); + QualType BadAllocType; + bool HasBadAllocExceptionSpec + = (Name.getCXXOverloadedOperator() == OO_New || + Name.getCXXOverloadedOperator() == OO_Array_New); + if (HasBadAllocExceptionSpec) { + assert(StdBadAlloc && "Must have std::bad_alloc declared"); + BadAllocType = Context.getTypeDeclType(StdBadAlloc); + } + + QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0, + true, false, + HasBadAllocExceptionSpec? 1 : 0, + &BadAllocType); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, - FnType, FunctionDecl::None, false, true, - SourceLocation()); + FnType, /*DInfo=*/0, FunctionDecl::None, false, true); Alloc->setImplicit(); ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), - 0, Argument, VarDecl::None, 0); + 0, Argument, /*DInfo=*/0, + VarDecl::None, 0); Alloc->setParams(Context, &Param, 1); // FIXME: Also add this declaration to the IdentifierResolver, but @@ -689,43 +782,131 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, /// @code delete [] ptr; @endcode Action::OwningExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, - bool ArrayForm, ExprArg Operand) -{ - // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type - // having a single conversion function to a pointer type. The result has - // type void." + bool ArrayForm, ExprArg Operand) { + // C++ [expr.delete]p1: + // The operand shall have a pointer type, or a class type having a single + // conversion function to a pointer type. The result has type void. + // // DR599 amends "pointer type" to "pointer to object type" in both cases. + FunctionDecl *OperatorDelete = 0; + Expr *Ex = (Expr *)Operand.get(); if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); - if (Type->isRecordType()) { - // FIXME: Find that one conversion function and amend the type. + if (const RecordType *Record = Type->getAs<RecordType>()) { + llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions; + CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); + OverloadedFunctionDecl *Conversions = + RD->getVisibleConversionFunctions(); + + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + // Skip over templated conversion functions; they aren't considered. + if (isa<FunctionTemplateDecl>(*Func)) + continue; + + CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); + + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + if (ConvPtrType->getPointeeType()->isObjectType()) + ObjectPtrConversions.push_back(Conv); + } + if (ObjectPtrConversions.size() == 1) { + // We have a single conversion to a pointer-to-object type. Perform + // that conversion. + Operand.release(); + if (!PerformImplicitConversion(Ex, + ObjectPtrConversions.front()->getConversionType(), + "converting")) { + Operand = Owned(Ex); + Type = Ex->getType(); + } + } + else if (ObjectPtrConversions.size() > 1) { + Diag(StartLoc, diag::err_ambiguous_delete_operand) + << Type << Ex->getSourceRange(); + for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) { + CXXConversionDecl *Conv = ObjectPtrConversions[i]; + Diag(Conv->getLocation(), diag::err_ovl_candidate); + } + return ExprError(); + } } if (!Type->isPointerType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); - QualType Pointee = Type->getAsPointerType()->getPointeeType(); + QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); if (Pointee->isFunctionType() || Pointee->isVoidType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); else if (!Pointee->isDependentType() && - RequireCompleteType(StartLoc, Pointee, - diag::warn_delete_incomplete, - Ex->getSourceRange())) + RequireCompleteType(StartLoc, Pointee, + PDiag(diag::warn_delete_incomplete) + << Ex->getSourceRange())) return ExprError(); - // FIXME: Look up the correct operator delete overload and pass a pointer - // along. + // C++ [expr.delete]p2: + // [Note: a pointer to a const type can be the operand of a + // delete-expression; it is not necessary to cast away the constness + // (5.2.11) of the pointer expression before it is used as the operand + // of the delete-expression. ] + ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy), + CastExpr::CK_NoOp); + + // Update the operand. + Operand.take(); + Operand = ExprArg(*this, Ex); + + DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( + ArrayForm ? OO_Array_Delete : OO_Delete); + + if (Pointee->isRecordType() && !UseGlobal) { + CXXRecordDecl *Record + = cast<CXXRecordDecl>(Pointee->getAs<RecordType>()->getDecl()); + + // Try to find operator delete/operator delete[] in class scope. + LookupResult Found; + LookupQualifiedName(Found, Record, DeleteName, LookupOrdinaryName); + // FIXME: Diagnose ambiguity properly + assert(!Found.isAmbiguous() && "Ambiguous delete/delete[] not handled"); + for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); + F != FEnd; ++F) { + if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F)) + if (Delete->isUsualDeallocationFunction()) { + OperatorDelete = Delete; + break; + } + } + + if (!Record->hasTrivialDestructor()) + if (const CXXDestructorDecl *Dtor = Record->getDestructor(Context)) + MarkDeclarationReferenced(StartLoc, + const_cast<CXXDestructorDecl*>(Dtor)); + } + + if (!OperatorDelete) { + // Didn't find a member overload. Look for a global one. + DeclareGlobalNewDelete(); + DeclContext *TUDecl = Context.getTranslationUnitDecl(); + if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName, + &Ex, 1, TUDecl, /*AllowMissing=*/false, + OperatorDelete)) + return ExprError(); + } + // FIXME: Check access and ambiguity of operator delete and destructor. } Operand.release(); return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, - 0, Ex, StartLoc)); + OperatorDelete, Ex, StartLoc)); } @@ -747,8 +928,11 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc, assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class of condition decl."); - QualType Ty = GetTypeForDeclarator(D, S); - + // FIXME: Store DeclaratorInfo in the expression. + DeclaratorInfo *DInfo = 0; + TagDecl *OwnedTag = 0; + QualType Ty = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag); + if (Ty->isFunctionType()) { // The declarator shall not specify a function... // We exit without creating a CXXConditionDeclExpr because a FunctionDecl // would be created and CXXConditionDeclExpr wants a VarDecl. @@ -757,18 +941,9 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc, } else if (Ty->isArrayType()) { // ...or an array. Diag(StartLoc, diag::err_invalid_use_of_array_type) << SourceRange(StartLoc, EqualLoc); - } else if (const RecordType *RT = Ty->getAsRecordType()) { - RecordDecl *RD = RT->getDecl(); - // The type-specifier-seq shall not declare a new class... - if (RD->isDefinition() && - (RD->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(RD)))) - Diag(RD->getLocation(), diag::err_type_defined_in_condition); - } else if (const EnumType *ET = Ty->getAsEnumType()) { - EnumDecl *ED = ET->getDecl(); - // ...or enumeration. - if (ED->isDefinition() && - (ED->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(ED)))) - Diag(ED->getLocation(), diag::err_type_defined_in_condition); + } else if (OwnedTag && OwnedTag->isDefinition()) { + // The type-specifier-seq shall not declare a new class or enumeration. + Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition); } DeclPtrTy Dcl = ActOnDeclarator(S, D); @@ -801,7 +976,7 @@ bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) { /// conversion from a string literal to a pointer to non-const char or /// non-const wchar_t (for narrow and wide string literals, /// respectively). -bool +bool Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { // Look inside the implicit cast, if it exists. if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(From)) @@ -812,12 +987,12 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { // string literal can be converted to an rvalue of type "pointer // to wchar_t" (C++ 4.2p2). if (StringLiteral *StrLit = dyn_cast<StringLiteral>(From)) - if (const PointerType *ToPtrType = ToType->getAsPointerType()) - if (const BuiltinType *ToPointeeType - = ToPtrType->getPointeeType()->getAsBuiltinType()) { + if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) + if (const BuiltinType *ToPointeeType + = ToPtrType->getPointeeType()->getAs<BuiltinType>()) { // This conversion is considered only when there is an // explicit appropriate pointer target type (C++ 4.2p2). - if (ToPtrType->getPointeeType().getCVRQualifiers() == 0 && + if (!ToPtrType->getPointeeType().hasQualifiers() && ((StrLit->isWide() && ToPointeeType->isWideCharType()) || (!StrLit->isWide() && (ToPointeeType->getKind() == BuiltinType::Char_U || @@ -839,16 +1014,31 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const char *Flavor, bool AllowExplicit, - bool Elidable) -{ + bool Elidable) { ImplicitConversionSequence ICS; + return PerformImplicitConversion(From, ToType, Flavor, AllowExplicit, + Elidable, ICS); +} + +bool +Sema::PerformImplicitConversion(Expr *&From, QualType ToType, + const char *Flavor, bool AllowExplicit, + bool Elidable, + ImplicitConversionSequence& ICS) { ICS.ConversionKind = ImplicitConversionSequence::BadConversion; if (Elidable && getLangOptions().CPlusPlus0x) { - ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions*/false, - AllowExplicit, /*ForceRValue*/true); + ICS = TryImplicitConversion(From, ToType, + /*SuppressUserConversions=*/false, + AllowExplicit, + /*ForceRValue=*/true, + /*InOverloadResolution=*/false); } if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { - ICS = TryImplicitConversion(From, ToType, false, AllowExplicit); + ICS = TryImplicitConversion(From, ToType, + /*SuppressUserConversions=*/false, + AllowExplicit, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); } return PerformImplicitConversion(From, ToType, ICS, Flavor); } @@ -869,13 +1059,48 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return true; break; - case ImplicitConversionSequence::UserDefinedConversion: - // FIXME: This is, of course, wrong. We'll need to actually call the - // constructor or conversion operator, and then cope with the standard - // conversions. - ImpCastExprToType(From, ToType.getNonReferenceType(), - ToType->isLValueReferenceType()); - return false; + case ImplicitConversionSequence::UserDefinedConversion: { + + FunctionDecl *FD = ICS.UserDefined.ConversionFunction; + CastExpr::CastKind CastKind = CastExpr::CK_Unknown; + QualType BeforeToType; + if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(FD)) { + CastKind = CastExpr::CK_UserDefinedConversion; + + // If the user-defined conversion is specified by a conversion function, + // the initial standard conversion sequence converts the source type to + // the implicit object parameter of the conversion function. + BeforeToType = Context.getTagDeclType(Conv->getParent()); + } else if (const CXXConstructorDecl *Ctor = + dyn_cast<CXXConstructorDecl>(FD)) { + CastKind = CastExpr::CK_ConstructorConversion; + + // If the user-defined conversion is specified by a constructor, the + // initial standard conversion sequence converts the source type to the + // type required by the argument of the constructor + BeforeToType = Ctor->getParamDecl(0)->getType(); + } + else + assert(0 && "Unknown conversion function kind!"); + + if (PerformImplicitConversion(From, BeforeToType, + ICS.UserDefined.Before, "converting")) + return true; + + OwningExprResult CastArg + = BuildCXXCastArgument(From->getLocStart(), + ToType.getNonReferenceType(), + CastKind, cast<CXXMethodDecl>(FD), + Owned(From)); + + if (CastArg.isInvalid()) + return true; + + From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(), + CastKind, CastArg.takeAs<Expr>(), + ToType->isLValueReferenceType()); + return false; + } case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); @@ -895,7 +1120,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, /// otherwise. The expression From is replaced with the converted /// expression. Flavor is the context in which we're performing this /// conversion, for use in error messages. -bool +bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, const char *Flavor) { @@ -908,10 +1133,31 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (SCS.CopyConstructor) { // FIXME: When can ToType be a reference type? assert(!ToType->isReferenceType()); - - // FIXME: Keep track of whether the copy constructor is elidable or not. - From = CXXConstructExpr::Create(Context, ToType, - SCS.CopyConstructor, false, &From, 1); + if (SCS.Second == ICK_Derived_To_Base) { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor), + MultiExprArg(*this, (void **)&From, 1), + /*FIXME:ConstructLoc*/SourceLocation(), + ConstructorArgs)) + return true; + OwningExprResult FromResult = + BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), + ToType, SCS.CopyConstructor, + move_arg(ConstructorArgs)); + if (FromResult.isInvalid()) + return true; + From = FromResult.takeAs<Expr>(); + return false; + } + OwningExprResult FromResult = + BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), + ToType, SCS.CopyConstructor, + MultiExprArg(*this, (void**)&From, 1)); + + if (FromResult.isInvalid()) + return true; + + From = FromResult.takeAs<Expr>(); return false; } @@ -924,7 +1170,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); - ImpCastExprToType(From, FromType); + ImpCastExprToType(From, FromType, CastExpr::CK_ArrayToPointerDecay); break; case ICK_Function_To_Pointer: @@ -940,7 +1186,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, FromType = From->getType(); } FromType = Context.getPointerType(FromType); - ImpCastExprToType(From, FromType); + ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay); break; default: @@ -951,7 +1197,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Perform the second implicit conversion switch (SCS.Second) { case ICK_Identity: - // Nothing to do. + // If both sides are functions (or pointers/references to them), there could + // be incompatible exception declarations. + if (CheckExceptionSpecCompatibility(From, ToType)) + return true; + // Nothing else to do. break; case ICK_Integral_Promotion: @@ -968,26 +1218,32 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ImpCastExprToType(From, FromType); break; - case ICK_Pointer_Conversion: + case ICK_Pointer_Conversion: { if (SCS.IncompatibleObjC) { // Diagnose incompatible Objective-C conversions - Diag(From->getSourceRange().getBegin(), + Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) << From->getType() << ToType << Flavor << From->getSourceRange(); } - if (CheckPointerConversion(From, ToType)) + + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (CheckPointerConversion(From, ToType, Kind)) return true; - ImpCastExprToType(From, ToType); + ImpCastExprToType(From, ToType, Kind); break; - - case ICK_Pointer_Member: - if (CheckMemberPointerConversion(From, ToType)) + } + + case ICK_Pointer_Member: { + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (CheckMemberPointerConversion(From, ToType, Kind)) return true; - ImpCastExprToType(From, ToType); + if (CheckExceptionSpecCompatibility(From, ToType)) + return true; + ImpCastExprToType(From, ToType, Kind); break; - + } case ICK_Boolean_Conversion: FromType = Context.BoolTy; ImpCastExprToType(From, FromType); @@ -1006,7 +1262,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Qualification: // FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue // references. - ImpCastExprToType(From, ToType.getNonReferenceType(), + ImpCastExprToType(From, ToType.getNonReferenceType(), + CastExpr::CK_Unknown, ToType->isLValueReferenceType()); break; @@ -1023,34 +1280,38 @@ Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT, SourceLocation LParen, TypeTy *Ty, SourceLocation RParen) { - // FIXME: Some of the type traits have requirements. Interestingly, only the - // __is_base_of requirement is explicitly stated to be diagnosed. Indeed, G++ - // accepts __is_pod(Incomplete) without complaints, and claims that the type - // is indeed a POD. + QualType T = GetTypeFromParser(Ty); + + // According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html + // all traits except __is_class, __is_enum and __is_union require a the type + // to be complete. + if (OTT != UTT_IsClass && OTT != UTT_IsEnum && OTT != UTT_IsUnion) { + if (RequireCompleteType(KWLoc, T, + diag::err_incomplete_type_used_in_type_trait_expr)) + return ExprError(); + } // There is no point in eagerly computing the value. The traits are designed // to be used from type trait templates, so Ty will be a template parameter // 99% of the time. - return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT, - QualType::getFromOpaquePtr(Ty), - RParen, Context.BoolTy)); + return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT, T, + RParen, Context.BoolTy)); } QualType Sema::CheckPointerToMemberOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) -{ + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) { const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall // be of type "pointer to member of T" (where T is a completely-defined // class type) [...] QualType RType = rex->getType(); - const MemberPointerType *MemPtr = RType->getAsMemberPointerType(); + const MemberPointerType *MemPtr = RType->getAs<MemberPointerType>(); if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) << OpSpelling << RType << rex->getSourceRange(); return QualType(); - } + } QualType Class(MemPtr->getClass(), 0); @@ -1060,7 +1321,7 @@ QualType Sema::CheckPointerToMemberOperands( // such a class] QualType LType = lex->getType(); if (isIndirect) { - if (const PointerType *Ptr = LType->getAsPointerType()) + if (const PointerType *Ptr = LType->getAs<PointerType>()) LType = Ptr->getPointeeType().getNonReferenceType(); else { Diag(Loc, diag::err_bad_memptr_lhs) @@ -1071,8 +1332,8 @@ QualType Sema::CheckPointerToMemberOperands( if (Context.getCanonicalType(Class).getUnqualifiedType() != Context.getCanonicalType(LType).getUnqualifiedType()) { - BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, - /*DetectVirtual=*/false); + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + /*DetectVirtual=*/false); // FIXME: Would it be useful to print full ambiguity paths, or is that // overkill? if (!IsDerivedFrom(LType, Class, Paths) || @@ -1096,10 +1357,7 @@ QualType Sema::CheckPointerToMemberOperands( // argument. // We probably need a "MemberFunctionClosureType" or something like that. QualType Result = MemPtr->getPointeeType(); - if (LType.isConstQualified()) - Result.addConst(); - if (LType.isVolatileQualified()) - Result.addVolatile(); + Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers()); return Result; } @@ -1124,8 +1382,7 @@ static QualType TargetType(const ImplicitConversionSequence &ICS) { /// conversion. static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, SourceLocation QuestionLoc, - ImplicitConversionSequence &ICS) -{ + ImplicitConversionSequence &ICS) { // C++0x 5.16p3 // The process for determining whether an operand expression E1 of type T1 // can be converted to match an operand expression E2 of type T2 is defined @@ -1137,7 +1394,11 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // conversion the reference must bind directly to E1. if (!Self.CheckReferenceInit(From, Self.Context.getLValueReferenceType(To->getType()), - &ICS)) + To->getLocStart(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + &ICS)) { assert((ICS.ConversionKind == ImplicitConversionSequence::StandardConversion || @@ -1157,8 +1418,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // the same or one is a base class of the other: QualType FTy = From->getType(); QualType TTy = To->getType(); - const RecordType *FRec = FTy->getAsRecordType(); - const RecordType *TRec = TTy->getAsRecordType(); + const RecordType *FRec = FTy->getAs<RecordType>(); + const RecordType *TRec = TTy->getAs<RecordType>(); bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy); if (FRec && TRec && (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) { @@ -1169,7 +1430,10 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // Could still fail if there's no copy constructor. // FIXME: Is this a hard error then, or just a conversion failure? The // standard doesn't say. - ICS = Self.TryCopyInitialization(From, TTy); + ICS = Self.TryCopyInitialization(From, TTy, + /*SuppressUserConversions=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); } } else { // -- Otherwise: E1 can be converted to match E2 if E1 can be @@ -1178,12 +1442,16 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // First find the decayed type. if (TTy->isFunctionType()) TTy = Self.Context.getPointerType(TTy); - else if(TTy->isArrayType()) + else if (TTy->isArrayType()) TTy = Self.Context.getArrayDecayedType(TTy); // Now try the implicit conversion. // FIXME: This doesn't detect ambiguities. - ICS = Self.TryImplicitConversion(From, TTy); + ICS = Self.TryImplicitConversion(From, TTy, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); } return false; } @@ -1239,8 +1507,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, /// second part of a standard conversion is ICK_DerivedToBase. This function /// handles the reference binding specially. static bool ConvertForConditional(Sema &Self, Expr *&E, - const ImplicitConversionSequence &ICS) -{ + const ImplicitConversionSequence &ICS) { if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion && ICS.Standard.ReferenceBinding) { assert(ICS.Standard.DirectBinding && @@ -1248,14 +1515,22 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, // FIXME: CheckReferenceInit should be able to reuse the ICS instead of // redoing all the work. return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( - TargetType(ICS))); + TargetType(ICS)), + /*FIXME:*/E->getLocStart(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false); } if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion && ICS.UserDefined.After.ReferenceBinding) { assert(ICS.UserDefined.After.DirectBinding && "TryClassUnification should never generate indirect ref bindings"); return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( - TargetType(ICS))); + TargetType(ICS)), + /*FIXME:*/E->getLocStart(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false); } if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting")) return true; @@ -1412,27 +1687,48 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // containing class, and second-level cv-ness. // cv-ness is not a union, but must match one of the two operands. (Which, // frankly, is stupid.) - const MemberPointerType *LMemPtr = LTy->getAsMemberPointerType(); - const MemberPointerType *RMemPtr = RTy->getAsMemberPointerType(); - if (LMemPtr && RHS->isNullPointerConstant(Context)) { + const MemberPointerType *LMemPtr = LTy->getAs<MemberPointerType>(); + const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>(); + if (LMemPtr && + RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(RHS, LTy); return LTy; } - if (RMemPtr && LHS->isNullPointerConstant(Context)) { + if (RMemPtr && + LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(LHS, RTy); return RTy; } if (LMemPtr && RMemPtr) { QualType LPointee = LMemPtr->getPointeeType(); QualType RPointee = RMemPtr->getPointeeType(); + + QualifierCollector LPQuals, RPQuals; + const Type *LPCan = LPQuals.strip(Context.getCanonicalType(LPointee)); + const Type *RPCan = RPQuals.strip(Context.getCanonicalType(RPointee)); + // First, we check that the unqualified pointee type is the same. If it's // not, there's no conversion that will unify the two pointers. - if (Context.getCanonicalType(LPointee).getUnqualifiedType() == - Context.getCanonicalType(RPointee).getUnqualifiedType()) { - // Second, we take the greater of the two cv qualifications. If neither + if (LPCan == RPCan) { + + // Second, we take the greater of the two qualifications. If neither // is greater than the other, the conversion is not possible. - unsigned Q = LPointee.getCVRQualifiers() | RPointee.getCVRQualifiers(); - if (Q == LPointee.getCVRQualifiers() || Q == RPointee.getCVRQualifiers()){ + + Qualifiers MergedQuals = LPQuals + RPQuals; + + bool CompatibleQuals = true; + if (MergedQuals.getCVRQualifiers() != LPQuals.getCVRQualifiers() && + MergedQuals.getCVRQualifiers() != RPQuals.getCVRQualifiers()) + CompatibleQuals = false; + else if (LPQuals.getAddressSpace() != RPQuals.getAddressSpace()) + // FIXME: + // C99 6.5.15 as modified by TR 18037: + // If the second and third operands are pointers into different + // address spaces, the address spaces must overlap. + CompatibleQuals = false; + // FIXME: GC qualifiers? + + if (CompatibleQuals) { // Third, we check if either of the container classes is derived from // the other. QualType LContainer(LMemPtr->getClass(), 0); @@ -1450,8 +1746,9 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // The type 'Q Pointee (MoreDerived::*)' is the common type. // We don't use ImpCastExprToType here because this could still fail // for ambiguous or inaccessible conversions. - QualType Common = Context.getMemberPointerType( - LPointee.getQualifiedType(Q), MoreDerived.getTypePtr()); + LPointee = Context.getQualifiedType(LPointee, MergedQuals); + QualType Common + = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr()); if (PerformImplicitConversion(LHS, Common, "converting")) return QualType(); if (PerformImplicitConversion(RHS, Common, "converting")) @@ -1470,30 +1767,37 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, /// \brief Find a merged pointer type and convert the two expressions to it. /// -/// This finds the composite pointer type for @p E1 and @p E2 according to -/// C++0x 5.9p2. It converts both expressions to this type and returns it. +/// This finds the composite pointer type (or member pointer type) for @p E1 +/// and @p E2 according to C++0x 5.9p2. It converts both expressions to this +/// type and returns it. /// It does not emit diagnostics. QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); - if(!T1->isPointerType() && !T2->isPointerType()) - return QualType(); + + if (!T1->isPointerType() && !T1->isMemberPointerType() && + !T2->isPointerType() && !T2->isMemberPointerType()) + return QualType(); + + // FIXME: Do we need to work on the canonical types? // C++0x 5.9p2 // Pointer conversions and qualification conversions are performed on // pointer operands to bring them to their composite pointer type. If // one operand is a null pointer constant, the composite pointer type is // the type of the other operand. - if (E1->isNullPointerConstant(Context)) { + if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(E1, T2); return T2; } - if (E2->isNullPointerConstant(Context)) { + if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(E2, T1); return T1; } - // Now both have to be pointers. - if(!T1->isPointerType() || !T2->isPointerType()) + + // Now both have to be pointers or member pointers. + if (!T1->isPointerType() && !T1->isMemberPointerType() && + !T2->isPointerType() && !T2->isMemberPointerType()) return QualType(); // Otherwise, of one of the operands has type "pointer to cv1 void," then @@ -1506,32 +1810,93 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { // What we do here is, we build the two possible composite types, and try the // conversions in both directions. If only one works, or if the two composite // types are the same, we have succeeded. + // FIXME: extended qualifiers? llvm::SmallVector<unsigned, 4> QualifierUnion; + llvm::SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass; QualType Composite1 = T1, Composite2 = T2; - const PointerType *Ptr1, *Ptr2; - while ((Ptr1 = Composite1->getAsPointerType()) && - (Ptr2 = Composite2->getAsPointerType())) { - Composite1 = Ptr1->getPointeeType(); - Composite2 = Ptr2->getPointeeType(); - QualifierUnion.push_back( - Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); - } - // Rewrap the composites as pointers with the union CVRs. - for (llvm::SmallVector<unsigned, 4>::iterator I = QualifierUnion.begin(), - E = QualifierUnion.end(); I != E; ++I) { - Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I)); - Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I)); + do { + const PointerType *Ptr1, *Ptr2; + if ((Ptr1 = Composite1->getAs<PointerType>()) && + (Ptr2 = Composite2->getAs<PointerType>())) { + Composite1 = Ptr1->getPointeeType(); + Composite2 = Ptr2->getPointeeType(); + QualifierUnion.push_back( + Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); + MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0)); + continue; + } + + const MemberPointerType *MemPtr1, *MemPtr2; + if ((MemPtr1 = Composite1->getAs<MemberPointerType>()) && + (MemPtr2 = Composite2->getAs<MemberPointerType>())) { + Composite1 = MemPtr1->getPointeeType(); + Composite2 = MemPtr2->getPointeeType(); + QualifierUnion.push_back( + Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); + MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), + MemPtr2->getClass())); + continue; + } + + // FIXME: block pointer types? + + // Cannot unwrap any more types. + break; + } while (true); + + // Rewrap the composites as pointers or member pointers with the union CVRs. + llvm::SmallVector<std::pair<const Type *, const Type *>, 4>::iterator MOC + = MemberOfClass.begin(); + for (llvm::SmallVector<unsigned, 4>::iterator + I = QualifierUnion.begin(), + E = QualifierUnion.end(); + I != E; (void)++I, ++MOC) { + Qualifiers Quals = Qualifiers::fromCVRMask(*I); + if (MOC->first && MOC->second) { + // Rebuild member pointer type + Composite1 = Context.getMemberPointerType( + Context.getQualifiedType(Composite1, Quals), + MOC->first); + Composite2 = Context.getMemberPointerType( + Context.getQualifiedType(Composite2, Quals), + MOC->second); + } else { + // Rebuild pointer type + Composite1 + = Context.getPointerType(Context.getQualifiedType(Composite1, Quals)); + Composite2 + = Context.getPointerType(Context.getQualifiedType(Composite2, Quals)); + } } - ImplicitConversionSequence E1ToC1 = TryImplicitConversion(E1, Composite1); - ImplicitConversionSequence E2ToC1 = TryImplicitConversion(E2, Composite1); + ImplicitConversionSequence E1ToC1 = + TryImplicitConversion(E1, Composite1, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + ImplicitConversionSequence E2ToC1 = + TryImplicitConversion(E2, Composite1, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + ImplicitConversionSequence E1ToC2, E2ToC2; E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; if (Context.getCanonicalType(Composite1) != Context.getCanonicalType(Composite2)) { - E1ToC2 = TryImplicitConversion(E1, Composite2); - E2ToC2 = TryImplicitConversion(E2, Composite2); + E1ToC2 = TryImplicitConversion(E1, Composite2, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + E2ToC2 = TryImplicitConversion(E2, Composite2, + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); } bool ToC1Viable = E1ToC1.ConversionKind != @@ -1556,84 +1921,264 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { } Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { - const RecordType *RT = E->getType()->getAsRecordType(); + if (!Context.getLangOptions().CPlusPlus) + return Owned(E); + + const RecordType *RT = E->getType()->getAs<RecordType>(); if (!RT) return Owned(E); - + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); if (RD->hasTrivialDestructor()) return Owned(E); - - CXXTemporary *Temp = CXXTemporary::Create(Context, + + if (CallExpr *CE = dyn_cast<CallExpr>(E)) { + QualType Ty = CE->getCallee()->getType(); + if (const PointerType *PT = Ty->getAs<PointerType>()) + Ty = PT->getPointeeType(); + + const FunctionType *FTy = Ty->getAs<FunctionType>(); + if (FTy->getResultType()->isReferenceType()) + return Owned(E); + } + CXXTemporary *Temp = CXXTemporary::Create(Context, RD->getDestructor(Context)); ExprTemporaries.push_back(Temp); - MarkDestructorReferenced(E->getExprLoc(), E->getType()); + if (CXXDestructorDecl *Destructor = + const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) + MarkDeclarationReferenced(E->getExprLoc(), Destructor); // FIXME: Add the temporary to the temporaries vector. return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E)); } -// FIXME: This doesn't handle casts yet. -Expr *Sema::RemoveOutermostTemporaryBinding(Expr *E) { - const RecordType *RT = E->getType()->getAsRecordType(); - if (!RT) - return E; - - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialDestructor()) - return E; - - /// The expr passed in must be a CXXExprWithTemporaries. - CXXExprWithTemporaries *TempExpr = dyn_cast<CXXExprWithTemporaries>(E); - if (!TempExpr) - return E; - - Expr *SubExpr = TempExpr->getSubExpr(); - if (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(SubExpr)) { - assert(BE->getTemporary() == - TempExpr->getTemporary(TempExpr->getNumTemporaries() - 1) && - "Found temporary is not last in list!"); - - Expr *BindSubExpr = BE->getSubExpr(); - BE->setSubExpr(0); - - if (TempExpr->getNumTemporaries() == 1) { - // There's just one temporary left, so we don't need the TempExpr node. - TempExpr->Destroy(Context); - return BindSubExpr; - } else { - TempExpr->removeLastTemporary(); - TempExpr->setSubExpr(BindSubExpr); - BE->Destroy(Context); - } - - return E; - } - - // FIXME: We might need to handle other expressions here. - return E; -} - -Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, +Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, bool ShouldDestroyTemps) { assert(SubExpr && "sub expression can't be null!"); - + if (ExprTemporaries.empty()) return SubExpr; - + Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr, - &ExprTemporaries[0], + &ExprTemporaries[0], ExprTemporaries.size(), ShouldDestroyTemps); ExprTemporaries.clear(); - + return E; } +Sema::OwningExprResult +Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, TypeTy *&ObjectType) { + // Since this might be a postfix expression, get rid of ParenListExprs. + Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); + + Expr *BaseExpr = (Expr*)Base.get(); + assert(BaseExpr && "no record expansion"); + + QualType BaseType = BaseExpr->getType(); + if (BaseType->isDependentType()) { + // FIXME: member of the current instantiation + ObjectType = BaseType.getAsOpaquePtr(); + return move(Base); + } + + // C++ [over.match.oper]p8: + // [...] When operator->returns, the operator-> is applied to the value + // returned, with the original second operand. + if (OpKind == tok::arrow) { + // The set of types we've considered so far. + llvm::SmallPtrSet<CanQualType,8> CTypes; + llvm::SmallVector<SourceLocation, 8> Locations; + CTypes.insert(Context.getCanonicalType(BaseType)); + + while (BaseType->isRecordType()) { + Base = BuildOverloadedArrowExpr(S, move(Base), OpLoc); + BaseExpr = (Expr*)Base.get(); + if (BaseExpr == NULL) + return ExprError(); + if (CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(BaseExpr)) + Locations.push_back(OpCall->getDirectCallee()->getLocation()); + BaseType = BaseExpr->getType(); + CanQualType CBaseType = Context.getCanonicalType(BaseType); + if (!CTypes.insert(CBaseType)) { + Diag(OpLoc, diag::err_operator_arrow_circular); + for (unsigned i = 0; i < Locations.size(); i++) + Diag(Locations[i], diag::note_declared_at); + return ExprError(); + } + } + } + + if (BaseType->isPointerType()) + BaseType = BaseType->getPointeeType(); + + // We could end up with various non-record types here, such as extended + // vector types or Objective-C interfaces. Just return early and let + // ActOnMemberReferenceExpr do the work. + if (!BaseType->isRecordType()) { + // C++ [basic.lookup.classref]p2: + // [...] If the type of the object expression is of pointer to scalar + // type, the unqualified-id is looked up in the context of the complete + // postfix-expression. + ObjectType = 0; + return move(Base); + } + + // C++ [basic.lookup.classref]p2: + // If the id-expression in a class member access (5.2.5) is an + // unqualified-id, and the type of the object expres- sion is of a class + // type C (or of pointer to a class type C), the unqualified-id is looked + // up in the scope of class C. [...] + ObjectType = BaseType.getAsOpaquePtr(); + return move(Base); +} + +Sema::OwningExprResult +Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + IdentifierInfo *ClassName, + const CXXScopeSpec &SS, + bool HasTrailingLParen) { + if (SS.isInvalid()) + return ExprError(); + + QualType BaseType; + if (isUnknownSpecialization(SS)) + BaseType = Context.getTypenameType((NestedNameSpecifier *)SS.getScopeRep(), + ClassName); + else { + TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS); + if (!BaseTy) { + Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) + << ClassName; + return ExprError(); + } + + BaseType = GetTypeFromParser(BaseTy); + } + + CanQualType CanBaseType = Context.getCanonicalType(BaseType); + DeclarationName DtorName = + Context.DeclarationNames.getCXXDestructorName(CanBaseType); + + OwningExprResult Result + = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, + DtorName, DeclPtrTy(), &SS); + if (Result.isInvalid() || HasTrailingLParen) + return move(Result); + + // The only way a reference to a destructor can be used is to + // immediately call them. Since the next token is not a '(', produce a + // diagnostic and build the call now. + Expr *E = (Expr *)Result.get(); + SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(E->getLocEnd()); + Diag(E->getLocStart(), diag::err_dtor_expr_without_call) + << isa<CXXPseudoDestructorExpr>(E) + << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + + return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, + MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); +} + +Sema::OwningExprResult +Sema::ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + OverloadedOperatorKind OverOpKind, + const CXXScopeSpec *SS) { + if (SS && SS->isInvalid()) + return ExprError(); + + DeclarationName Name = + Context.DeclarationNames.getCXXOperatorName(OverOpKind); + + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, + Name, DeclPtrTy(), SS); +} + +Sema::OwningExprResult +Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation ClassNameLoc, + TypeTy *Ty, + const CXXScopeSpec *SS) { + if (SS && SS->isInvalid()) + return ExprError(); + + //FIXME: Preserve type source info. + QualType ConvType = GetTypeFromParser(Ty); + CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType); + DeclarationName ConvName = + Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon); + + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, + ConvName, DeclPtrTy(), SS); +} + +CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, + CXXMethodDecl *Method) { + MemberExpr *ME = + new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, + SourceLocation(), Method->getType()); + QualType ResultType; + if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(Method)) + ResultType = Conv->getConversionType().getNonReferenceType(); + else + ResultType = Method->getResultType().getNonReferenceType(); + + CXXMemberCallExpr *CE = + new (Context) CXXMemberCallExpr(Context, ME, 0, 0, + ResultType, + SourceLocation()); + return CE; +} + +Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, + QualType Ty, + CastExpr::CastKind Kind, + CXXMethodDecl *Method, + ExprArg Arg) { + Expr *From = Arg.takeAs<Expr>(); + + switch (Kind) { + default: assert(0 && "Unhandled cast kind!"); + case CastExpr::CK_ConstructorConversion: { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + + if (CompleteConstructorCall(cast<CXXConstructorDecl>(Method), + MultiExprArg(*this, (void **)&From, 1), + CastLoc, ConstructorArgs)) + return ExprError(); + + return BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), + move_arg(ConstructorArgs)); + } + + case CastExpr::CK_UserDefinedConversion: { + assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); + + // Cast to base if needed. + if (PerformObjectArgumentInitialization(From, Method)) + return ExprError(); + + // Create an implicit call expr that calls it. + CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method); + return Owned(CE); + } + } +} + Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs<Expr>(); if (FullExpr) - FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr, + FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr, /*ShouldDestroyTemps=*/true); + return Owned(FullExpr); } |