diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp | 1736 |
1 files changed, 1294 insertions, 442 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index 5720d93..f9c2c9a 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -31,7 +32,7 @@ using namespace clang; using namespace sema; ParsedType Sema::getDestructorName(SourceLocation TildeLoc, - IdentifierInfo &II, + IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectTypePtr, @@ -71,26 +72,26 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (SS.isSet()) { NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); - + bool AlreadySearched = false; bool LookAtPrefix = true; // C++ [basic.lookup.qual]p6: - // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, + // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, // the type-names are looked up as types in the scope designated by the // nested-name-specifier. In a qualified-id of the form: - // - // ::[opt] nested-name-specifier ̃ class-name + // + // ::[opt] nested-name-specifier ~ class-name // // where the nested-name-specifier designates a namespace scope, and in // a qualified-id of the form: // - // ::opt nested-name-specifier class-name :: ̃ class-name + // ::opt nested-name-specifier class-name :: ~ class-name // - // the class-names are looked up as types in the scope designated by + // the class-names are looked up as types in the scope designated by // the nested-name-specifier. // // Here, we check the first case (completely) and determine whether the - // code below is permitted to look at the prefix of the + // code below is permitted to look at the prefix of the // nested-name-specifier. DeclContext *DC = computeDeclContext(SS, EnteringContext); if (DC && DC->isFileContext()) { @@ -99,7 +100,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, isDependent = false; } else if (DC && isa<CXXRecordDecl>(DC)) LookAtPrefix = false; - + // The second case from the C++03 rules quoted further above. NestedNameSpecifier *Prefix = 0; if (AlreadySearched) { @@ -116,7 +117,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = LookupCtx && LookupCtx->isDependentContext(); } - + LookInScope = false; } else if (ObjectTypePtr) { // C++ [basic.lookup.classref]p3: @@ -128,7 +129,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // cv-qualified) T. LookupCtx = computeDeclContext(SearchType); isDependent = SearchType->isDependentType(); - assert((isDependent || !SearchType->isIncompleteType()) && + assert((isDependent || !SearchType->isIncompleteType()) && "Caller should have completed object type"); LookInScope = true; @@ -170,7 +171,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // nested-name-specifier (if present) or the object type, then // this is the destructor for that class. // FIXME: This is a workaround until we get real drafting for core - // issue 399, for which there isn't even an obvious direction. + // issue 399, for which there isn't even an obvious direction. if (ClassTemplateDecl *Template = Found.getAsSingle<ClassTemplateDecl>()) { QualType MemberOfType; if (SS.isSet()) { @@ -182,7 +183,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, } if (MemberOfType.isNull()) MemberOfType = SearchType; - + if (MemberOfType.isNull()) continue; @@ -199,7 +200,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, continue; } - + // We're referring to an unresolved class template // specialization. Determine whether we class template we found // is the same as the template being specialized or, if we don't @@ -220,7 +221,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // The class template we found has the same name as the // (dependent) template name being specialized. - if (DependentTemplateName *DepTemplate + if (DependentTemplateName *DepTemplate = SpecName.getAsDependentTemplateName()) { if (DepTemplate->isIdentifier() && DepTemplate->getIdentifier() == Template->getIdentifier()) @@ -253,7 +254,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (ObjectTypePtr) Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) - << &II; + << &II; else Diag(NameLoc, diag::err_destructor_class_name); @@ -262,13 +263,13 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, /// \brief Build a C++ typeid expression with a type operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, - SourceLocation TypeidLoc, - TypeSourceInfo *Operand, - SourceLocation RParenLoc) { + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { // C++ [expr.typeid]p4: - // The top-level cv-qualifiers of the lvalue expression or the type-id + // The top-level cv-qualifiers of the lvalue expression or the type-id // that is the operand of typeid are always ignored. - // If the type of the type-id is a class type or a reference to a class + // If the type of the type-id is a class type or a reference to a class // type, the class shall be completely-defined. Qualifiers Quals; QualType T @@ -277,7 +278,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, if (T->getAs<RecordType>() && RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); - + return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand, SourceRange(TypeidLoc, RParenLoc))); @@ -285,9 +286,9 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, /// \brief Build a C++ typeid expression with an expression operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, - SourceLocation TypeidLoc, - Expr *E, - SourceLocation RParenLoc) { + SourceLocation TypeidLoc, + Expr *E, + SourceLocation RParenLoc) { bool isUnevaluatedOperand = true; if (E && !E->isTypeDependent()) { QualType T = E->getType(); @@ -298,7 +299,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, // shall be completely-defined. if (RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); - + // C++ [expr.typeid]p3: // When typeid is applied to an expression other than an glvalue of a // polymorphic class type [...] [the] expression is an unevaluated @@ -310,11 +311,11 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, MarkVTableUsed(TypeidLoc, RecordD); } } - + // C++ [expr.typeid]p4: // [...] If the type of the type-id is a reference to a possibly - // cv-qualified type, the result of the typeid expression refers to a - // std::type_info object representing the cv-unqualified referenced + // cv-qualified type, the result of the typeid expression refers to a + // std::type_info object representing the cv-unqualified referenced // type. Qualifiers Quals; QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); @@ -323,16 +324,16 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E)); } } - + // If this is an unevaluated operand, clear out the set of // declaration references we have been computing and eliminate any // temporaries introduced in its computation. if (isUnevaluatedOperand) ExprEvalContexts.back().Context = Unevaluated; - + return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), E, - SourceRange(TypeidLoc, RParenLoc))); + SourceRange(TypeidLoc, RParenLoc))); } /// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression); @@ -343,15 +344,17 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, if (!StdNamespace) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); - LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); - LookupQualifiedName(R, getStdNamespace()); - RecordDecl *TypeInfoRecordDecl = R.getAsSingle<RecordDecl>(); - if (!TypeInfoRecordDecl) - return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - - QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl); - + if (!CXXTypeInfoDecl) { + IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); + LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); + LookupQualifiedName(R, getStdNamespace()); + CXXTypeInfoDecl = R.getAsSingle<RecordDecl>(); + if (!CXXTypeInfoDecl) + return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); + } + + QualType TypeInfoType = Context.getTypeDeclType(CXXTypeInfoDecl); + if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = 0; @@ -359,17 +362,102 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, &TInfo); if (T.isNull()) return ExprError(); - + if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc); } - // The operand is an expression. + // The operand is an expression. return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } +/// Retrieve the UuidAttr associated with QT. +static UuidAttr *GetUuidAttrOfType(QualType QT) { + // Optionally remove one level of pointer, reference or array indirection. + const Type *Ty = QT.getTypePtr();; + if (QT->isPointerType() || QT->isReferenceType()) + Ty = QT->getPointeeType().getTypePtr(); + else if (QT->isArrayType()) + Ty = cast<ArrayType>(QT)->getElementType().getTypePtr(); + + // Loop all class definition and declaration looking for an uuid attribute. + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + while (RD) { + if (UuidAttr *Uuid = RD->getAttr<UuidAttr>()) + return Uuid; + RD = RD->getPreviousDeclaration(); + } + return 0; +} + +/// \brief Build a Microsoft __uuidof expression with a type operand. +ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { + if (!Operand->getType()->isDependentType()) { + if (!GetUuidAttrOfType(Operand->getType())) + return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); + } + + // FIXME: add __uuidof semantic analysis for type operand. + return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(), + Operand, + SourceRange(TypeidLoc, RParenLoc))); +} + +/// \brief Build a Microsoft __uuidof expression with an expression operand. +ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *E, + SourceLocation RParenLoc) { + if (!E->getType()->isDependentType()) { + if (!GetUuidAttrOfType(E->getType()) && + !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) + return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); + } + // FIXME: add __uuidof semantic analysis for type operand. + return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(), + E, + SourceRange(TypeidLoc, RParenLoc))); +} + +/// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression); +ExprResult +Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, + bool isType, void *TyOrExpr, SourceLocation RParenLoc) { + // If MSVCGuidDecl has not been cached, do the lookup. + if (!MSVCGuidDecl) { + IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID"); + LookupResult R(*this, GuidII, SourceLocation(), LookupTagName); + LookupQualifiedName(R, Context.getTranslationUnitDecl()); + MSVCGuidDecl = R.getAsSingle<RecordDecl>(); + if (!MSVCGuidDecl) + return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof)); + } + + QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl); + + if (isType) { + // The operand is a type; handle it as such. + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr), + &TInfo); + if (T.isNull()) + return ExprError(); + + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); + + return BuildCXXUuidof(GuidType, OpLoc, TInfo, RParenLoc); + } + + // The operand is an expression. + return BuildCXXUuidof(GuidType, OpLoc, (Expr*)TyOrExpr, RParenLoc); +} + /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { @@ -388,6 +476,9 @@ Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { /// ActOnCXXThrow - Parse throw expressions. ExprResult Sema::ActOnCXXThrow(SourceLocation OpLoc, Expr *Ex) { + if (!getLangOptions().Exceptions) + Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; + if (Ex && !Ex->isTypeDependent() && CheckCXXThrowOperand(OpLoc, Ex)) return ExprError(); return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc)); @@ -399,12 +490,12 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // A throw-expression initializes a temporary object, called the exception // object, the type of which is determined by removing any top-level // cv-qualifiers from the static type of the operand of throw and adjusting - // the type from "array of T" or "function returning T" to "pointer to T" + // the type from "array of T" or "function returning T" to "pointer to T" // or "pointer to function returning T", [...] if (E->getType().hasQualifiers()) ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, CastCategory(E)); - + DefaultFunctionArrayConversion(E); // If the type of the exception would be an incomplete type or a pointer @@ -430,13 +521,14 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // Initialize the exception result. This implicitly weeds out // abstract types or types with inaccessible copy constructors. - // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p34. + const VarDecl *NRVOVariable = getCopyElisionCandidate(QualType(), E, false); + + // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p32. InitializedEntity Entity = - InitializedEntity::InitializeException(ThrowLoc, E->getType(), - /*NRVO=*/false); - ExprResult Res = PerformCopyInitialization(Entity, - SourceLocation(), - Owned(E)); + InitializedEntity::InitializeException(ThrowLoc, E->getType(), + /*NRVO=*/false); + ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable, + QualType(), E); if (Res.isInvalid()) return true; E = Res.takeAs<Expr>(); @@ -451,11 +543,15 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // exception handling will make use of the vtable. MarkVTableUsed(ThrowLoc, RD); + // If a pointer is thrown, the referenced object will not be destroyed. + if (isPointer) + return false; + // If the class has a non-trivial destructor, we must be able to call it. if (RD->hasTrivialDestructor()) return false; - CXXDestructorDecl *Destructor + CXXDestructorDecl *Destructor = const_cast<CXXDestructorDecl*>(LookupDestructor(RD)); if (!Destructor) return false; @@ -466,30 +562,48 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { return false; } -ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { +CXXMethodDecl *Sema::tryCaptureCXXThis() { + // Ignore block scopes: we can capture through them. + // Ignore nested enum scopes: we'll diagnose non-constant expressions + // where they're invalid, and other uses are legitimate. + // Don't ignore nested class scopes: you can't use 'this' in a local class. + DeclContext *DC = CurContext; + while (true) { + if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext(); + else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext(); + else break; + } + + // If we're not in an instance method, error out. + CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC); + if (!method || !method->isInstance()) + return 0; + + // Mark that we're closing on 'this' in all the block scopes, if applicable. + for (unsigned idx = FunctionScopes.size() - 1; + isa<BlockScopeInfo>(FunctionScopes[idx]); + --idx) + cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true; + + return method; +} + +ExprResult Sema::ActOnCXXThis(SourceLocation loc) { /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. - DeclContext *DC = getFunctionLevelDeclContext(); - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) - if (MD->isInstance()) - return Owned(new (Context) CXXThisExpr(ThisLoc, - MD->getThisType(Context), - /*isImplicit=*/false)); + CXXMethodDecl *method = tryCaptureCXXThis(); + if (!method) return Diag(loc, diag::err_invalid_this_use); - return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); + return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context), + /*isImplicit=*/false)); } -/// ActOnCXXTypeConstructExpr - Parse construction of a specified type. -/// Can be interpreted either as function-style casting ("int(x)") -/// or class type construction ("ClassType(x,y,z)") -/// or creation of a value-initialized type ("int()"). ExprResult -Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, +Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenLoc, MultiExprArg exprs, - SourceLocation *CommaLocs, SourceLocation RParenLoc) { if (!TypeRep) return ExprError(); @@ -498,17 +612,30 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, QualType Ty = GetTypeFromParser(TypeRep, &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); + + return BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc); +} + +/// ActOnCXXTypeConstructExpr - Parse construction of a specified type. +/// Can be interpreted either as function-style casting ("int(x)") +/// or class type construction ("ClassType(x,y,z)") +/// or creation of a value-initialized type ("int()"). +ExprResult +Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, + SourceLocation LParenLoc, + MultiExprArg exprs, + SourceLocation RParenLoc) { + QualType Ty = TInfo->getType(); unsigned NumExprs = exprs.size(); Expr **Exprs = (Expr**)exprs.get(); - SourceLocation TyBeginLoc = TypeRange.getBegin(); + SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); SourceRange FullRange = SourceRange(TyBeginLoc, RParenLoc); if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) { exprs.release(); - return Owned(CXXUnresolvedConstructExpr::Create(Context, - TypeRange.getBegin(), Ty, + return Owned(CXXUnresolvedConstructExpr::Create(Context, TInfo, LParenLoc, Exprs, NumExprs, RParenLoc)); @@ -522,7 +649,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, PDiag(diag::err_invalid_incomplete_type_use) << FullRange)) return ExprError(); - + if (RequireNonAbstractType(TyBeginLoc, Ty, diag::err_allocation_of_abstract_type)) return ExprError(); @@ -534,55 +661,91 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, // corresponding cast expression. // if (NumExprs == 1) { - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Invalid; + ExprValueKind VK = VK_RValue; CXXCastPath BasePath; - if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, BasePath, + if (CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0], + Kind, VK, BasePath, /*FunctionalStyle=*/true)) return ExprError(); exprs.release(); return Owned(CXXFunctionalCastExpr::Create(Context, - Ty.getNonLValueExprType(Context), - TInfo, TyBeginLoc, Kind, + Ty.getNonLValueExprType(Context), + VK, TInfo, TyBeginLoc, Kind, Exprs[0], &BasePath, RParenLoc)); } - if (Ty->isRecordType()) { - InitializedEntity Entity = InitializedEntity::InitializeTemporary(Ty); - InitializationKind Kind - = NumExprs ? InitializationKind::CreateDirect(TypeRange.getBegin(), - LParenLoc, RParenLoc) - : InitializationKind::CreateValue(TypeRange.getBegin(), - LParenLoc, RParenLoc); - InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - move(exprs)); + InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); + InitializationKind Kind + = NumExprs ? InitializationKind::CreateDirect(TyBeginLoc, + LParenLoc, RParenLoc) + : InitializationKind::CreateValue(TyBeginLoc, + LParenLoc, RParenLoc); + InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs)); + + // FIXME: Improve AST representation? + return move(Result); +} + +/// doesUsualArrayDeleteWantSize - Answers whether the usual +/// operator delete[] for the given type has a size_t parameter. +static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, + QualType allocType) { + const RecordType *record = + allocType->getBaseElementTypeUnsafe()->getAs<RecordType>(); + if (!record) return false; + + // Try to find an operator delete[] in class scope. + + DeclarationName deleteName = + S.Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete); + LookupResult ops(S, deleteName, loc, Sema::LookupOrdinaryName); + S.LookupQualifiedName(ops, record->getDecl()); + + // We're just doing this for information. + ops.suppressDiagnostics(); + + // Very likely: there's no operator delete[]. + if (ops.empty()) return false; + + // If it's ambiguous, it should be illegal to call operator delete[] + // on this thing, so it doesn't matter if we allocate extra space or not. + if (ops.isAmbiguous()) return false; + + LookupResult::Filter filter = ops.makeFilter(); + while (filter.hasNext()) { + NamedDecl *del = filter.next()->getUnderlyingDecl(); - // FIXME: Improve AST representation? - return move(Result); + // C++0x [basic.stc.dynamic.deallocation]p2: + // A template instance is never a usual deallocation function, + // regardless of its signature. + if (isa<FunctionTemplateDecl>(del)) { + filter.erase(); + continue; + } + + // C++0x [basic.stc.dynamic.deallocation]p2: + // If class T does not declare [an operator delete[] with one + // parameter] but does declare a member deallocation function + // named operator delete[] with exactly two parameters, the + // second of which has type std::size_t, then this function + // is a usual deallocation function. + if (!cast<CXXMethodDecl>(del)->isUsualDeallocationFunction()) { + filter.erase(); + continue; + } } + filter.done(); - // C++ [expr.type.conv]p1: - // If the expression list specifies more than a single value, the type shall - // be a class with a suitably declared constructor. - // - if (NumExprs > 1) - return ExprError(Diag(CommaLocs[0], - diag::err_builtin_func_cast_more_than_one_arg) - << FullRange); - - assert(NumExprs == 0 && "Expected 0 expressions"); - // C++ [expr.type.conv]p2: - // The expression T(), where T is a simple-type-specifier for a non-array - // complete object type or the (possibly cv-qualified) void type, creates an - // rvalue of the specified type, which is value-initialized. - // - exprs.release(); - return Owned(new (Context) CXXScalarValueInitExpr(Ty, TyBeginLoc, RParenLoc)); -} + if (!ops.isSingleResult()) return false; + const FunctionDecl *del = cast<FunctionDecl>(ops.getFoundDecl()); + return (del->getNumParams() == 2); +} /// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.: /// @code new (memory) int[size][4] @endcode @@ -592,15 +755,20 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, ExprResult Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, - SourceLocation PlacementRParen, SourceRange TypeIdParens, + SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, SourceLocation ConstructorRParen) { + bool TypeContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + Expr *ArraySize = 0; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { DeclaratorChunk &Chunk = D.getTypeObject(0); + if (TypeContainsAuto) + return ExprError(Diag(Chunk.Loc, diag::err_new_array_of_auto) + << D.getSourceRange()); if (Chunk.Arr.hasStatic) return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new) << D.getSourceRange()); @@ -630,25 +798,24 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - //FIXME: Store TypeSourceInfo in CXXNew expression. - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0, /*OwnedDecl=*/0, + /*AllowAuto=*/true); QualType AllocType = TInfo->getType(); if (D.isInvalidType()) return ExprError(); - - SourceRange R = TInfo->getTypeLoc().getSourceRange(); + return BuildCXXNew(StartLoc, UseGlobal, PlacementLParen, move(PlacementArgs), PlacementRParen, TypeIdParens, AllocType, - D.getSourceRange().getBegin(), - R, + TInfo, ArraySize, ConstructorLParen, move(ConstructorArgs), - ConstructorRParen); + ConstructorRParen, + TypeContainsAuto); } ExprResult @@ -658,15 +825,37 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, - SourceLocation TypeLoc, - SourceRange TypeRange, + TypeSourceInfo *AllocTypeInfo, Expr *ArraySize, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, - SourceLocation ConstructorRParen) { - if (CheckAllocatedType(AllocType, TypeLoc, TypeRange)) - return ExprError(); + SourceLocation ConstructorRParen, + bool TypeMayContainAuto) { + SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange(); + + // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. + if (TypeMayContainAuto && AllocType->getContainedAutoType()) { + if (ConstructorArgs.size() == 0) + return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) + << AllocType << TypeRange); + if (ConstructorArgs.size() != 1) { + Expr *FirstBad = ConstructorArgs.get()[1]; + return ExprError(Diag(FirstBad->getSourceRange().getBegin(), + diag::err_auto_new_ctor_multiple_expressions) + << AllocType << TypeRange); + } + QualType DeducedType; + if (!DeduceAutoType(AllocType, ConstructorArgs.get()[0], DeducedType)) + return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) + << AllocType + << ConstructorArgs.get()[0]->getType() + << TypeRange + << ConstructorArgs.get()[0]->getSourceRange()); + AllocType = DeducedType; + AllocTypeInfo = Context.getTrivialTypeSourceInfo(AllocType, StartLoc); + } + // Per C++0x [expr.new]p5, the type being constructed may be a // typedef of an array type. if (!ArraySize) { @@ -679,14 +868,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } + if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange)) + return ExprError(); + QualType ResultType = Context.getPointerType(AllocType); // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral // or enumeration type with a non-negative value." if (ArraySize && !ArraySize->isTypeDependent()) { - + QualType SizeType = ArraySize->getType(); - + ExprResult ConvertedSize = ConvertToIntegralOrEnumerationType(StartLoc, ArraySize, PDiag(diag::err_array_size_not_integral), @@ -696,16 +888,16 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, PDiag(diag::note_array_size_conversion), PDiag(diag::err_array_size_ambiguous_conversion), PDiag(diag::note_array_size_conversion), - PDiag(getLangOptions().CPlusPlus0x? 0 + PDiag(getLangOptions().CPlusPlus0x? 0 : diag::ext_array_size_conversion)); if (ConvertedSize.isInvalid()) return ExprError(); - + ArraySize = ConvertedSize.take(); SizeType = ArraySize->getType(); - if (!SizeType->isIntegralOrEnumerationType()) + if (!SizeType->isIntegralOrUnscopedEnumerationType()) return ExprError(); - + // Let's see if this is a constant < 0. If so, we reject it out of hand. // We don't care about special rules, so we tell the machinery it's not // evaluated - it gives us a result in more cases. @@ -713,17 +905,17 @@ 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()), + llvm::APInt::getNullValue(Value.getBitWidth()), Value.isUnsigned())) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); - + if (!AllocType->isDependentType()) { unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { - Diag(ArraySize->getSourceRange().getBegin(), + Diag(ArraySize->getSourceRange().getBegin(), diag::err_array_too_large) << Value.toString(10) << ArraySize->getSourceRange(); @@ -736,11 +928,11 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, << ArraySize->getSourceRange() << FixItHint::CreateRemoval(TypeIdParens.getBegin()) << FixItHint::CreateRemoval(TypeIdParens.getEnd()); - + TypeIdParens = SourceRange(); } } - + ImpCastExprToType(ArraySize, Context.getSizeType(), CK_IntegralCast); } @@ -749,7 +941,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, FunctionDecl *OperatorDelete = 0; Expr **PlaceArgs = (Expr**)PlacementArgs.get(); unsigned NumPlaceArgs = PlacementArgs.size(); - + if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) && FindAllocationFunctions(StartLoc, @@ -757,24 +949,32 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, UseGlobal, AllocType, ArraySize, PlaceArgs, NumPlaceArgs, OperatorNew, OperatorDelete)) return ExprError(); + + // If this is an array allocation, compute whether the usual array + // deallocation function for the type has a size_t parameter. + bool UsualArrayDeleteWantsSize = false; + if (ArraySize && !AllocType->isDependentType()) + UsualArrayDeleteWantsSize + = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); + llvm::SmallVector<Expr *, 8> AllPlaceArgs; if (OperatorNew) { // Add default arguments, if any. - const FunctionProtoType *Proto = + const FunctionProtoType *Proto = OperatorNew->getType()->getAs<FunctionProtoType>(); - VariadicCallType CallType = + VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; - + if (GatherArgumentsForCall(PlacementLParen, OperatorNew, - Proto, 1, PlaceArgs, NumPlaceArgs, + Proto, 1, PlaceArgs, NumPlaceArgs, AllPlaceArgs, CallType)) return ExprError(); - + NumPlaceArgs = AllPlaceArgs.size(); if (NumPlaceArgs > 0) PlaceArgs = &AllPlaceArgs[0]; } - + bool Init = ConstructorLParen.isValid(); // --- Choosing a constructor --- CXXConstructorDecl *Constructor = 0; @@ -786,7 +986,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, if (NumConsArgs && (ResultType->isArrayType() || ArraySize)) { SourceRange InitRange(ConsArgs[0]->getLocStart(), ConsArgs[NumConsArgs - 1]->getLocEnd()); - + Diag(StartLoc, diag::err_new_array_init_args) << InitRange; return ExprError(); } @@ -800,22 +1000,22 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, // - If the new-initializer is omitted, the object is default- // initialized (8.5); if no initialization is performed, // the object has indeterminate value - = !Init? InitializationKind::CreateDefault(TypeLoc) - // - Otherwise, the new-initializer is interpreted according to the + = !Init? InitializationKind::CreateDefault(TypeRange.getBegin()) + // - Otherwise, the new-initializer is interpreted according to the // initialization rules of 8.5 for direct-initialization. - : InitializationKind::CreateDirect(TypeLoc, - ConstructorLParen, + : InitializationKind::CreateDirect(TypeRange.getBegin(), + ConstructorLParen, ConstructorRParen); - + InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType); InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs); - ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, + ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, move(ConstructorArgs)); if (FullInit.isInvalid()) return ExprError(); - - // FullInit is our initializer; walk through it to determine if it's a + + // FullInit is our initializer; walk through it to determine if it's a // constructor call, which CXXNewExpr handles directly. if (Expr *FullInitExpr = (Expr *)FullInit.get()) { if (CXXBindTemporaryExpr *Binder @@ -827,7 +1027,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, for (CXXConstructExpr::arg_iterator A = Construct->arg_begin(), AEnd = Construct->arg_end(); A != AEnd; ++A) - ConvertedConstructorArgs.push_back(A->Retain()); + ConvertedConstructorArgs.push_back(*A); } else { // Take the converted initializer. ConvertedConstructorArgs.push_back(FullInit.release()); @@ -835,12 +1035,12 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } else { // No initialization required. } - + // Take the converted arguments and use them for the new expression. NumConsArgs = ConvertedConstructorArgs.size(); ConsArgs = (Expr **)ConvertedConstructorArgs.take(); } - + // Mark the new and delete operators as referenced. if (OperatorNew) MarkDeclarationReferenced(StartLoc, OperatorNew); @@ -848,18 +1048,20 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, MarkDeclarationReferenced(StartLoc, OperatorDelete); // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) - + PlacementArgs.release(); ConstructorArgs.release(); - - // FIXME: The TypeSourceInfo should also be included in CXXNewExpr. + return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, TypeIdParens, ArraySize, Constructor, Init, ConsArgs, NumConsArgs, OperatorDelete, - ResultType, StartLoc, + UsualArrayDeleteWantsSize, + ResultType, AllocTypeInfo, + StartLoc, Init ? ConstructorRParen : - TypeRange.getEnd())); + TypeRange.getEnd(), + ConstructorLParen, ConstructorRParen)); } /// CheckAllocatedType - Checks that a type is suitable as the allocated type @@ -883,6 +1085,9 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, else if (RequireNonAbstractType(Loc, AllocType, diag::err_allocation_of_abstract_type)) return true; + else if (AllocType->isVariablyModifiedType()) + return Diag(Loc, diag::err_variably_modified_new_type) + << AllocType; return false; } @@ -931,10 +1136,10 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // C++ [expr.new]p8: // If the allocated type is a non-array type, the allocation - // function’s name is operator new and the deallocation function’s + // function's name is operator new and the deallocation function's // name is operator delete. If the allocated type is an array - // type, the allocation function’s name is operator new[] and the - // deallocation function’s name is operator delete[]. + // type, the allocation function's name is operator new[] and the + // deallocation function's name is operator delete[]. DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( @@ -975,12 +1180,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // C++ [expr.new]p19: // // If the new-expression begins with a unary :: operator, the - // deallocation function’s name is looked up in the global + // deallocation function's name is looked up in the global // scope. Otherwise, if the allocated type is a class type T or an - // array thereof, the deallocation function’s name is looked up in + // array thereof, the deallocation function's name is looked up in // the scope of T. If this lookup fails to find the name, or if // the allocated type is not a class type or array thereof, the - // deallocation function’s name is looked up in the global scope. + // deallocation function's name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && !UseGlobal) { CXXRecordDecl *RD @@ -999,39 +1204,49 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, llvm::SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches; - if (NumPlaceArgs > 0) { + // Whether we're looking for a placement operator delete is dictated + // by whether we selected a placement operator new, not by whether + // we had explicit placement arguments. This matters for things like + // struct A { void *operator new(size_t, int = 0); ... }; + // A *a = new A() + bool isPlacementNew = (NumPlaceArgs > 0 || OperatorNew->param_size() != 1); + + if (isPlacementNew) { // C++ [expr.new]p20: // A declaration of a placement deallocation function matches the // declaration of a placement allocation function if it has the // same number of parameters and, after parameter transformations // (8.3.5), all parameter types except the first are // identical. [...] - // + // // To perform this comparison, we compute the function type that // the deallocation function should have, and use that type both // for template argument deduction and for comparison purposes. + // + // FIXME: this comparison should ignore CC and the like. QualType ExpectedFunctionType; { const FunctionProtoType *Proto = OperatorNew->getType()->getAs<FunctionProtoType>(); + llvm::SmallVector<QualType, 4> ArgTypes; - ArgTypes.push_back(Context.VoidPtrTy); + ArgTypes.push_back(Context.VoidPtrTy); for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I) ArgTypes.push_back(Proto->getArgType(I)); + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = Proto->isVariadic(); + ExpectedFunctionType = Context.getFunctionType(Context.VoidTy, ArgTypes.data(), - ArgTypes.size(), - Proto->isVariadic(), - 0, false, false, 0, 0, - FunctionType::ExtInfo()); + ArgTypes.size(), EPI); } - for (LookupResult::iterator D = FoundDelete.begin(), + for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { FunctionDecl *Fn = 0; - if (FunctionTemplateDecl *FnTmpl + if (FunctionTemplateDecl *FnTmpl = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { // Perform template argument deduction to try to match the // expected function type. @@ -1048,7 +1263,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // C++ [expr.new]p20: // [...] Any non-placement deallocation function matches a // non-placement allocation function. [...] - for (LookupResult::iterator D = FoundDelete.begin(), + for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl())) @@ -1073,7 +1288,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, if (NumPlaceArgs && getLangOptions().CPlusPlus0x && isNonPlacementDeallocationFunction(OperatorDelete)) { Diag(StartLoc, diag::err_placement_new_non_placement_delete) - << SourceRange(PlaceArgs[0]->getLocStart(), + << SourceRange(PlaceArgs[0]->getLocStart(), PlaceArgs[NumPlaceArgs - 1]->getLocEnd()); Diag(OperatorDelete->getLocation(), diag::note_previous_decl) << DeleteName; @@ -1107,7 +1322,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, R.suppressDiagnostics(); OverloadCandidateSet Candidates(StartLoc); - for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); + 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. @@ -1140,12 +1355,13 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { ExprResult Result = PerformCopyInitialization(InitializedEntity::InitializeParameter( + Context, FnDecl->getParamDecl(i)), SourceLocation(), - Owned(Args[i]->Retain())); + Owned(Args[i])); if (Result.isInvalid()) return true; - + Args[i] = Result.takeAs<Expr>(); } Operator = FnDecl; @@ -1190,18 +1406,18 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, 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 + // [...] 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 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 + // 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 @@ -1211,14 +1427,14 @@ void Sema::DeclareGlobalNewDelete() { if (!StdBadAlloc) { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. - StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, - getOrCreateStdNamespace(), - SourceLocation(), - &PP.getIdentifierTable().get("bad_alloc"), + StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, + getOrCreateStdNamespace(), + SourceLocation(), + &PP.getIdentifierTable().get("bad_alloc"), SourceLocation(), 0); getStdBadAlloc()->setImplicit(true); } - + GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); @@ -1268,28 +1484,31 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, } QualType BadAllocType; - bool HasBadAllocExceptionSpec + bool HasBadAllocExceptionSpec = (Name.getCXXOverloadedOperator() == OO_New || Name.getCXXOverloadedOperator() == OO_Array_New); if (HasBadAllocExceptionSpec) { assert(StdBadAlloc && "Must have std::bad_alloc declared"); BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); } - - QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0, - true, false, - HasBadAllocExceptionSpec? 1 : 0, - &BadAllocType, - FunctionType::ExtInfo()); + + FunctionProtoType::ExtProtoInfo EPI; + EPI.HasExceptionSpec = true; + if (HasBadAllocExceptionSpec) { + EPI.NumExceptions = 1; + EPI.Exceptions = &BadAllocType; + } + + QualType FnType = Context.getFunctionType(Return, &Argument, 1, EPI); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, FnType, /*TInfo=*/0, SC_None, SC_None, false, true); Alloc->setImplicit(); - + if (AddMallocAttr) Alloc->addAttr(::new (Context) MallocAttr(SourceLocation(), Context)); - + ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), 0, Argument, /*TInfo=*/0, SC_None, @@ -1308,7 +1527,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); - + if (Found.isAmbiguous()) return true; @@ -1352,7 +1571,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, if (!Found.empty()) { Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) << Name << RD; - + for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) Diag((*F)->getUnderlyingDecl()->getLocation(), @@ -1364,7 +1583,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, // Look for a global declaration. DeclareGlobalNewDelete(); DeclContext *TUDecl = Context.getTranslationUnitDecl(); - + CXXNullPtrLiteralExpr Null(Context.VoidPtrTy, SourceLocation()); Expr* DeallocArgs[1]; DeallocArgs[0] = &Null; @@ -1391,19 +1610,21 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // DR599 amends "pointer type" to "pointer to object type" in both cases. FunctionDecl *OperatorDelete = 0; + bool ArrayFormAsWritten = ArrayForm; + bool UsualArrayDeleteWantsSize = false; if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); if (const RecordType *Record = Type->getAs<RecordType>()) { - if (RequireCompleteType(StartLoc, Type, + if (RequireCompleteType(StartLoc, Type, PDiag(diag::err_delete_incomplete_class_type))) return ExprError(); - + llvm::SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions; CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); - const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); + const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = I.getDecl(); @@ -1413,9 +1634,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // Skip over templated conversion functions; they aren't considered. if (isa<FunctionTemplateDecl>(D)) continue; - + CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); - + QualType ConvType = Conv->getConversionType().getNonReferenceType(); if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType()) @@ -1446,7 +1667,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); if (Pointee->isVoidType() && !isSFINAEContext()) { - // The C++ standard bans deleting a pointer to a non-object type, which + // The C++ standard bans deleting a pointer to a non-object type, which // effectively bans deletion of "void*". However, most compilers support // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) @@ -1461,13 +1682,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, return ExprError(); // 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 + // [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), + ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy), CK_NoOp); - + + if (Pointee->isArrayType() && !ArrayForm) { + Diag(StartLoc, diag::warn_delete_array_type) + << Type << Ex->getSourceRange() + << FixItHint::CreateInsertion(PP.getLocForEndOfToken(StartLoc), "[]"); + ArrayForm = true; + } + DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( ArrayForm ? OO_Array_Delete : OO_Delete); @@ -1475,16 +1703,33 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (const RecordType *RT = PointeeElem->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (!UseGlobal && + if (!UseGlobal && FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete)) return ExprError(); - + + // If we're allocating an array of records, check whether the + // usual operator delete[] has a size_t parameter. + if (ArrayForm) { + // If the user specifically asked to use the global allocator, + // we'll need to do the lookup into the class. + if (UseGlobal) + UsualArrayDeleteWantsSize = + doesUsualArrayDeleteWantSize(*this, StartLoc, PointeeElem); + + // Otherwise, the usual operator delete[] should be the + // function we just found. + else if (isa<CXXMethodDecl>(OperatorDelete)) + UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2); + } + if (!RD->hasTrivialDestructor()) - if (const CXXDestructorDecl *Dtor = LookupDestructor(RD)) + if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { MarkDeclarationReferenced(StartLoc, const_cast<CXXDestructorDecl*>(Dtor)); + DiagnoseUseOfDecl(Dtor, StartLoc); + } } - + if (!OperatorDelete) { // Look for a global declaration. DeclareGlobalNewDelete(); @@ -1496,38 +1741,49 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, } MarkDeclarationReferenced(StartLoc, OperatorDelete); + + // Check access and ambiguity of operator delete and destructor. + if (const RecordType *RT = PointeeElem->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { + CheckDestructorAccess(Ex->getExprLoc(), Dtor, + PDiag(diag::err_access_dtor) << PointeeElem); + } + } - // FIXME: Check access and ambiguity of operator delete and destructor. } return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, + ArrayFormAsWritten, + UsualArrayDeleteWantsSize, OperatorDelete, Ex, StartLoc)); } /// \brief Check the use of the given variable as a C++ condition in an if, /// while, do-while, or switch statement. ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, - SourceLocation StmtLoc, - bool ConvertToBoolean) { + SourceLocation StmtLoc, + bool ConvertToBoolean) { QualType T = ConditionVar->getType(); - + // C++ [stmt.select]p2: // The declarator shall not specify a function or an array. if (T->isFunctionType()) - return ExprError(Diag(ConditionVar->getLocation(), + return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_function_type) << ConditionVar->getSourceRange()); else if (T->isArrayType()) - return ExprError(Diag(ConditionVar->getLocation(), + return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_array_type) << ConditionVar->getSourceRange()); Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, - ConditionVar->getLocation(), - ConditionVar->getType().getNonReferenceType()); + ConditionVar->getLocation(), + ConditionVar->getType().getNonReferenceType(), + VK_LValue); if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) return ExprError(); - + return Owned(Condition); } @@ -1575,42 +1831,46 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { return false; } -static ExprResult BuildCXXCastArgument(Sema &S, +static ExprResult BuildCXXCastArgument(Sema &S, SourceLocation CastLoc, QualType Ty, CastKind Kind, CXXMethodDecl *Method, + NamedDecl *FoundDecl, Expr *From) { switch (Kind) { default: assert(0 && "Unhandled cast kind!"); case CK_ConstructorConversion: { ASTOwningVector<Expr*> ConstructorArgs(S); - + if (S.CompleteConstructorCall(cast<CXXConstructorDecl>(Method), MultiExprArg(&From, 1), CastLoc, ConstructorArgs)) return ExprError(); - - ExprResult Result = - S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), + + ExprResult Result = + S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), move_arg(ConstructorArgs), - /*ZeroInit*/ false, CXXConstructExpr::CK_Complete); + /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, + SourceRange()); if (Result.isInvalid()) return ExprError(); - + return S.MaybeBindToTemporary(Result.takeAs<Expr>()); } - + case CK_UserDefinedConversion: { assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); - + // Create an implicit call expr that calls it. - // FIXME: pass the FoundDecl for the user-defined conversion here - CXXMemberCallExpr *CE = S.BuildCXXMemberCallExpr(From, Method, Method); - return S.MaybeBindToTemporary(CE); + ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Method); + if (Result.isInvalid()) + return ExprError(); + + return S.MaybeBindToTemporary(Result.get()); } } -} +} /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit @@ -1621,52 +1881,51 @@ static ExprResult BuildCXXCastArgument(Sema &S, bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence &ICS, - AssignmentAction Action, bool IgnoreBaseAccess) { + AssignmentAction Action, bool CStyle) { switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: if (PerformImplicitConversion(From, ToType, ICS.Standard, Action, - IgnoreBaseAccess)) + CStyle)) return true; break; case ImplicitConversionSequence::UserDefinedConversion: { - + FunctionDecl *FD = ICS.UserDefined.ConversionFunction; - CastKind CastKind = CK_Unknown; + CastKind CastKind; QualType BeforeToType; if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(FD)) { CastKind = 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)) { + } else { + const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(FD); CastKind = CK_ConstructorConversion; // Do no conversion if dealing with ... for the first conversion. if (!ICS.UserDefined.EllipsisConversion) { - // If the user-defined conversion is specified by a constructor, the + // 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().getNonReferenceType(); } - } - else - assert(0 && "Unknown conversion function kind!"); - // Whatch out for elipsis conversion. + } + // Watch out for elipsis conversion. if (!ICS.UserDefined.EllipsisConversion) { - if (PerformImplicitConversion(From, BeforeToType, + if (PerformImplicitConversion(From, BeforeToType, ICS.UserDefined.Before, AA_Converting, - IgnoreBaseAccess)) + CStyle)) return true; } - - ExprResult CastArg + + ExprResult CastArg = BuildCXXCastArgument(*this, From->getLocStart(), ToType.getNonReferenceType(), - CastKind, cast<CXXMethodDecl>(FD), + CastKind, cast<CXXMethodDecl>(FD), + ICS.UserDefined.FoundConversionFunction, From); if (CastArg.isInvalid()) @@ -1675,7 +1934,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, From = CastArg.takeAs<Expr>(); return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, - AA_Converting, IgnoreBaseAccess); + AA_Converting, CStyle); } case ImplicitConversionSequence::AmbiguousConversion: @@ -1683,7 +1942,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); return true; - + case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); return false; @@ -1705,7 +1964,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, - AssignmentAction Action, bool IgnoreBaseAccess) { + AssignmentAction Action, bool CStyle) { // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, @@ -1719,7 +1978,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ASTOwningVector<Expr*> ConstructorArgs(*this); if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor), MultiExprArg(*this, &From, 1), - /*FIXME:ConstructLoc*/SourceLocation(), + /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) return true; ExprResult FromResult = @@ -1727,7 +1986,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ToType, SCS.CopyConstructor, move_arg(ConstructorArgs), /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete); + CXXConstructExpr::CK_Complete, + SourceRange()); if (FromResult.isInvalid()) return true; From = FromResult.takeAs<Expr>(); @@ -1738,7 +1998,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ToType, SCS.CopyConstructor, MultiExprArg(*this, &From, 1), /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete); + CXXConstructExpr::CK_Complete, + SourceRange()); if (FromResult.isInvalid()) return true; @@ -1765,10 +2026,25 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Perform the first implicit conversion. switch (SCS.First) { case ICK_Identity: - case ICK_Lvalue_To_Rvalue: // Nothing to do. break; + case ICK_Lvalue_To_Rvalue: + // Should this get its own ICK? + if (From->getObjectKind() == OK_ObjCProperty) { + ConvertPropertyForRValue(From); + if (!From->isGLValue()) break; + } + + // Check for trivial buffer overflows. + if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(From)) + CheckArrayAccess(AE); + + FromType = FromType.getUnqualifiedType(); + From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue, + From, 0, VK_RValue); + break; + case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay); @@ -1798,12 +2074,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // If both sides are functions (or pointers/references to them), there could // be incompatible exception declarations. if (CheckExceptionSpecCompatibility(From, ToType)) - return true; - - ImpCastExprToType(From, Context.getNoReturnType(From->getType(), false), - CK_NoOp); + return true; + + ImpCastExprToType(From, ToType, CK_NoOp); break; - + case ICK_Integral_Promotion: case ICK_Integral_Conversion: ImpCastExprToType(From, ToType, CK_IntegralCast); @@ -1815,9 +2090,23 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; case ICK_Complex_Promotion: - case ICK_Complex_Conversion: - ImpCastExprToType(From, ToType, CK_Unknown); + case ICK_Complex_Conversion: { + QualType FromEl = From->getType()->getAs<ComplexType>()->getElementType(); + QualType ToEl = ToType->getAs<ComplexType>()->getElementType(); + CastKind CK; + if (FromEl->isRealFloatingType()) { + if (ToEl->isRealFloatingType()) + CK = CK_FloatingComplexCast; + else + CK = CK_FloatingComplexToIntegralComplex; + } else if (ToEl->isRealFloatingType()) { + CK = CK_IntegralComplexToFloatingComplex; + } else { + CK = CK_IntegralComplexCast; + } + ImpCastExprToType(From, ToType, CK); break; + } case ICK_Floating_Integral: if (ToType->isRealFloatingType()) @@ -1831,7 +2120,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; case ICK_Pointer_Conversion: { - if (SCS.IncompatibleObjC) { + if (SCS.IncompatibleObjC && Action != AA_Casting) { // Diagnose incompatible Objective-C conversions Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) @@ -1839,20 +2128,18 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, << From->getSourceRange(); } - - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Invalid; CXXCastPath BasePath; - if (CheckPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess)) + if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return true; ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath); break; } - + case ICK_Pointer_Member: { - CastKind Kind = CK_Unknown; + CastKind Kind = CK_Invalid; CXXCastPath BasePath; - if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, - IgnoreBaseAccess)) + if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle)) return true; if (CheckExceptionSpecCompatibility(From, ToType)) return true; @@ -1860,22 +2147,29 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; } case ICK_Boolean_Conversion: { - CastKind Kind = CK_Unknown; - if (FromType->isMemberPointerType()) - Kind = CK_MemberPointerToBoolean; - + CastKind Kind = CK_Invalid; + switch (FromType->getScalarTypeKind()) { + case Type::STK_Pointer: Kind = CK_PointerToBoolean; break; + case Type::STK_MemberPointer: Kind = CK_MemberPointerToBoolean; break; + case Type::STK_Bool: llvm_unreachable("bool -> bool conversion?"); + case Type::STK_Integral: Kind = CK_IntegralToBoolean; break; + case Type::STK_Floating: Kind = CK_FloatingToBoolean; break; + case Type::STK_IntegralComplex: Kind = CK_IntegralComplexToBoolean; break; + case Type::STK_FloatingComplex: Kind = CK_FloatingComplexToBoolean; break; + } + ImpCastExprToType(From, Context.BoolTy, Kind); break; } case ICK_Derived_To_Base: { CXXCastPath BasePath; - if (CheckDerivedToBaseConversion(From->getType(), + if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), - From->getSourceRange(), + From->getSourceRange(), &BasePath, - IgnoreBaseAccess)) + CStyle)) return true; ImpCastExprToType(From, ToType.getNonReferenceType(), @@ -1891,10 +2185,60 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Vector_Splat: ImpCastExprToType(From, ToType, CK_VectorSplat); break; - + case ICK_Complex_Real: - ImpCastExprToType(From, ToType, CK_Unknown); + // Case 1. x -> _Complex y + if (const ComplexType *ToComplex = ToType->getAs<ComplexType>()) { + QualType ElType = ToComplex->getElementType(); + bool isFloatingComplex = ElType->isRealFloatingType(); + + // x -> y + if (Context.hasSameUnqualifiedType(ElType, From->getType())) { + // do nothing + } else if (From->getType()->isRealFloatingType()) { + ImpCastExprToType(From, ElType, + isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral); + } else { + assert(From->getType()->isIntegerType()); + ImpCastExprToType(From, ElType, + isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast); + } + // y -> _Complex y + ImpCastExprToType(From, ToType, + isFloatingComplex ? CK_FloatingRealToComplex + : CK_IntegralRealToComplex); + + // Case 2. _Complex x -> y + } else { + const ComplexType *FromComplex = From->getType()->getAs<ComplexType>(); + assert(FromComplex); + + QualType ElType = FromComplex->getElementType(); + bool isFloatingComplex = ElType->isRealFloatingType(); + + // _Complex x -> x + ImpCastExprToType(From, ElType, + isFloatingComplex ? CK_FloatingComplexToReal + : CK_IntegralComplexToReal); + + // x -> y + if (Context.hasSameUnqualifiedType(ElType, ToType)) { + // do nothing + } else if (ToType->isRealFloatingType()) { + ImpCastExprToType(From, ToType, + isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating); + } else { + assert(ToType->isIntegerType()); + ImpCastExprToType(From, ToType, + isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast); + } + } break; + + case ICK_Block_Pointer_Conversion: { + ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, VK_RValue); + break; + } case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: @@ -1933,31 +2277,409 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return false; } -ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT, - SourceLocation KWLoc, - SourceLocation LParen, - ParsedType Ty, - SourceLocation RParen) { - QualType T = GetTypeFromParser(Ty); +ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait UTT, + SourceLocation KWLoc, + ParsedType Ty, + SourceLocation RParen) { + TypeSourceInfo *TSInfo; + QualType T = GetTypeFromParser(Ty, &TSInfo); + + if (!TSInfo) + TSInfo = Context.getTrivialTypeSourceInfo(T); + return BuildUnaryTypeTrait(UTT, KWLoc, TSInfo, RParen); +} + +static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T, + SourceLocation KeyLoc) { + // FIXME: For many of these traits, we need a complete type before we can + // check these properties. + assert(!T->isDependentType() && + "Cannot evaluate traits for dependent types."); + ASTContext &C = Self.Context; + switch(UTT) { + default: assert(false && "Unknown type trait or not implemented"); + case UTT_IsPOD: return T->isPODType(); + case UTT_IsLiteral: return T->isLiteralType(); + case UTT_IsClass: // Fallthrough + case UTT_IsUnion: + if (const RecordType *Record = T->getAs<RecordType>()) { + bool Union = Record->getDecl()->isUnion(); + return UTT == UTT_IsUnion ? Union : !Union; + } + return false; + case UTT_IsEnum: return T->isEnumeralType(); + case UTT_IsPolymorphic: + if (const RecordType *Record = T->getAs<RecordType>()) { + // Type traits are only parsed in C++, so we've got CXXRecords. + return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic(); + } + return false; + case UTT_IsAbstract: + if (const RecordType *RT = T->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->isAbstract(); + return false; + case UTT_IsEmpty: + if (const RecordType *Record = T->getAs<RecordType>()) { + return !Record->getDecl()->isUnion() + && cast<CXXRecordDecl>(Record->getDecl())->isEmpty(); + } + return false; + case UTT_HasTrivialConstructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true then the trait is true, else if type is + // a cv class or union type (or array thereof) with a trivial default + // constructor ([class.ctor]) then the trait is true, else it is false. + if (T->isPODType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(T)->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor(); + return false; + case UTT_HasTrivialCopy: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true or type is a reference type then + // the trait is true, else if type is a cv class or union type + // with a trivial copy constructor ([class.copy]) then the trait + // is true, else it is false. + if (T->isPODType() || T->isReferenceType()) + return true; + if (const RecordType *RT = T->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor(); + return false; + case UTT_HasTrivialAssign: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is const qualified or is a reference type then the + // trait is false. Otherwise if __is_pod (type) is true then the + // trait is true, else if type is a cv class or union type with + // a trivial copy assignment ([class.copy]) then the trait is + // true, else it is false. + // Note: the const and reference restrictions are interesting, + // given that const and reference members don't prevent a class + // from having a trivial copy assignment operator (but do cause + // errors if the copy assignment operator is actually used, q.v. + // [class.copy]p12). + + if (C.getBaseElementType(T).isConstQualified()) + return false; + if (T->isPODType()) + return true; + if (const RecordType *RT = T->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment(); + return false; + case UTT_HasTrivialDestructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true or type is a reference type + // then the trait is true, else if type is a cv class or union + // type (or array thereof) with a trivial destructor + // ([class.dtor]) then the trait is true, else it is + // false. + if (T->isPODType() || T->isReferenceType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(T)->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor(); + return false; + // TODO: Propagate nothrowness for implicitly declared special members. + case UTT_HasNothrowAssign: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is const qualified or is a reference type then the + // trait is false. Otherwise if __has_trivial_assign (type) + // is true then the trait is true, else if type is a cv class + // or union type with copy assignment operators that are known + // not to throw an exception then the trait is true, else it is + // false. + if (C.getBaseElementType(T).isConstQualified()) + return false; + if (T->isReferenceType()) + return false; + if (T->isPODType()) + return true; + if (const RecordType *RT = T->getAs<RecordType>()) { + CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialCopyAssignment()) + return true; + + bool FoundAssign = false; + bool AllNoThrow = true; + DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal); + LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc), + Sema::LookupOrdinaryName); + if (Self.LookupQualifiedName(Res, RD)) { + for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end(); + Op != OpEnd; ++Op) { + CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op); + if (Operator->isCopyAssignmentOperator()) { + FoundAssign = true; + const FunctionProtoType *CPT + = Operator->getType()->getAs<FunctionProtoType>(); + if (!CPT->hasEmptyExceptionSpec()) { + AllNoThrow = false; + break; + } + } + } + } + + return FoundAssign && AllNoThrow; + } + return false; + case UTT_HasNothrowCopy: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __has_trivial_copy (type) is true then the trait is true, else + // if type is a cv class or union type with copy constructors that are + // known not to throw an exception then the trait is true, else it is + // false. + if (T->isPODType() || T->isReferenceType()) + return true; + if (const RecordType *RT = T->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialCopyConstructor()) + return true; + + bool FoundConstructor = false; + bool AllNoThrow = true; + unsigned FoundTQs; + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD); + Con != ConEnd; ++Con) { + // A template constructor is never a copy constructor. + // FIXME: However, it may actually be selected at the actual overload + // resolution point. + if (isa<FunctionTemplateDecl>(*Con)) + continue; + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isCopyConstructor(FoundTQs)) { + FoundConstructor = true; + const FunctionProtoType *CPT + = Constructor->getType()->getAs<FunctionProtoType>(); + // TODO: check whether evaluating default arguments can throw. + // For now, we'll be conservative and assume that they can throw. + if (!CPT->hasEmptyExceptionSpec() || CPT->getNumArgs() > 1) { + AllNoThrow = false; + break; + } + } + } + + return FoundConstructor && AllNoThrow; + } + return false; + case UTT_HasNothrowConstructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __has_trivial_constructor (type) is true then the trait is + // true, else if type is a cv class or union type (or array + // thereof) with a default constructor that is known not to + // throw an exception then the trait is true, else it is false. + if (T->isPODType()) + return true; + if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialConstructor()) + return true; + + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD); + Con != ConEnd; ++Con) { + // FIXME: In C++0x, a constructor template can be a default constructor. + if (isa<FunctionTemplateDecl>(*Con)) + continue; + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isDefaultConstructor()) { + const FunctionProtoType *CPT + = Constructor->getType()->getAs<FunctionProtoType>(); + // TODO: check whether evaluating default arguments can throw. + // For now, we'll be conservative and assume that they can throw. + return CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0; + } + } + } + return false; + case UTT_HasVirtualDestructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is a class type with a virtual destructor ([class.dtor]) + // then the trait is true, else it is false. + if (const RecordType *Record = T->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); + if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD)) + return Destructor->isVirtual(); + } + return false; + } +} + +ExprResult Sema::BuildUnaryTypeTrait(UnaryTypeTrait UTT, + SourceLocation KWLoc, + TypeSourceInfo *TSInfo, + SourceLocation RParen) { + QualType T = TSInfo->getType(); // 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, + // to be complete, an array of unknown bound, or void. + if (UTT != UTT_IsClass && UTT != UTT_IsEnum && UTT != UTT_IsUnion) { + QualType E = T; + if (T->isIncompleteArrayType()) + E = Context.getAsArrayType(T)->getElementType(); + if (!T->isVoidType() && + RequireCompleteType(KWLoc, E, 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, T, + bool Value = false; + if (!T->isDependentType()) + Value = EvaluateUnaryTypeTrait(*this, UTT, T, KWLoc); + + return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, UTT, TSInfo, Value, RParen, Context.BoolTy)); } -QualType Sema::CheckPointerToMemberOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) { +ExprResult Sema::ActOnBinaryTypeTrait(BinaryTypeTrait BTT, + SourceLocation KWLoc, + ParsedType LhsTy, + ParsedType RhsTy, + SourceLocation RParen) { + TypeSourceInfo *LhsTSInfo; + QualType LhsT = GetTypeFromParser(LhsTy, &LhsTSInfo); + if (!LhsTSInfo) + LhsTSInfo = Context.getTrivialTypeSourceInfo(LhsT); + + TypeSourceInfo *RhsTSInfo; + QualType RhsT = GetTypeFromParser(RhsTy, &RhsTSInfo); + if (!RhsTSInfo) + RhsTSInfo = Context.getTrivialTypeSourceInfo(RhsT); + + return BuildBinaryTypeTrait(BTT, KWLoc, LhsTSInfo, RhsTSInfo, RParen); +} + +static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, + QualType LhsT, QualType RhsT, + SourceLocation KeyLoc) { + assert((!LhsT->isDependentType() || RhsT->isDependentType()) && + "Cannot evaluate traits for dependent types."); + + switch(BTT) { + case BTT_IsBaseOf: { + // C++0x [meta.rel]p2 + // Base is a base class of Derived without regard to cv-qualifiers or + // Base and Derived are not unions and name the same class type without + // regard to cv-qualifiers. + + const RecordType *lhsRecord = LhsT->getAs<RecordType>(); + if (!lhsRecord) return false; + + const RecordType *rhsRecord = RhsT->getAs<RecordType>(); + if (!rhsRecord) return false; + + assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT) + == (lhsRecord == rhsRecord)); + + if (lhsRecord == rhsRecord) + return !lhsRecord->getDecl()->isUnion(); + + // C++0x [meta.rel]p2: + // If Base and Derived are class types and are different types + // (ignoring possible cv-qualifiers) then Derived shall be a + // complete type. + if (Self.RequireCompleteType(KeyLoc, RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) + return false; + + return cast<CXXRecordDecl>(rhsRecord->getDecl()) + ->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl())); + } + + case BTT_TypeCompatible: + return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(), + RhsT.getUnqualifiedType()); + + case BTT_IsConvertibleTo: { + // C++0x [meta.rel]p4: + // Given the following function prototype: + // + // template <class T> + // typename add_rvalue_reference<T>::type create(); + // + // the predicate condition for a template specialization + // is_convertible<From, To> shall be satisfied if and only if + // the return expression in the following code would be + // well-formed, including any implicit conversions to the return + // type of the function: + // + // To test() { + // return create<From>(); + // } + // + // Access checking is performed as if in a context unrelated to To and + // From. Only the validity of the immediate context of the expression + // of the return-statement (including conversions to the return type) + // is considered. + // + // We model the initialization as a copy-initialization of a temporary + // of the appropriate type, which for this expression is identical to the + // return statement (since NRVO doesn't apply). + if (LhsT->isObjectType() || LhsT->isFunctionType()) + LhsT = Self.Context.getRValueReferenceType(LhsT); + + InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT)); + OpaqueValueExpr From(KeyLoc, LhsT.getNonLValueExprType(Self.Context), + Expr::getValueKindForType(LhsT)); + Expr *FromPtr = &From; + InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, + SourceLocation())); + + // Perform the initialization within a SFINAE trap at translation unit + // scope. + Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); + InitializationSequence Init(Self, To, Kind, &FromPtr, 1); + if (Init.getKind() == InitializationSequence::FailedSequence) + return false; + + ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1)); + return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); + } + } + llvm_unreachable("Unknown type trait or not implemented"); +} + +ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT, + SourceLocation KWLoc, + TypeSourceInfo *LhsTSInfo, + TypeSourceInfo *RhsTSInfo, + SourceLocation RParen) { + QualType LhsT = LhsTSInfo->getType(); + QualType RhsT = RhsTSInfo->getType(); + + if (BTT == BTT_TypeCompatible) { + if (getLangOptions().CPlusPlus) { + Diag(KWLoc, diag::err_types_compatible_p_in_cplusplus) + << SourceRange(KWLoc, RParen); + return ExprError(); + } + } + + bool Value = false; + if (!LhsT->isDependentType() && !RhsT->isDependentType()) + Value = EvaluateBinaryTypeTrait(*this, BTT, LhsT, RhsT, KWLoc); + + // Select trait result type. + QualType ResultType; + switch (BTT) { + case BTT_IsBaseOf: ResultType = Context.BoolTy; break; + case BTT_TypeCompatible: ResultType = Context.IntTy; break; + case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break; + } + + return Owned(new (Context) BinaryTypeTraitExpr(KWLoc, BTT, LhsTSInfo, + RhsTSInfo, Value, RParen, + ResultType)); +} + +QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex, + ExprValueKind &VK, + SourceLocation Loc, + bool isIndirect) { const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall @@ -1973,8 +2695,11 @@ QualType Sema::CheckPointerToMemberOperands( QualType Class(MemPtr->getClass(), 0); - if (RequireCompleteType(Loc, Class, diag::err_memptr_rhs_to_incomplete)) - return QualType(); + // Note: C++ [expr.mptr.oper]p2-3 says that the class type into which the + // member pointer points must be completely-defined. However, there is no + // reason for this semantic distinction, and the rule is not enforced by + // other compilers. Therefore, we do not check this property, as it is + // likely to be considered a defect. // C++ 5.5p2 // [...] to its first operand, which shall be of class T or of a class of @@ -1983,7 +2708,7 @@ QualType Sema::CheckPointerToMemberOperands( QualType LType = lex->getType(); if (isIndirect) { if (const PointerType *Ptr = LType->getAs<PointerType>()) - LType = Ptr->getPointeeType().getNonReferenceType(); + LType = Ptr->getPointeeType(); else { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << 1 << LType @@ -2024,6 +2749,7 @@ QualType Sema::CheckPointerToMemberOperands( Diag(Loc, diag::err_pointer_to_member_type) << isIndirect; return QualType(); } + // C++ 5.5p2 // The result is an object or a function of the type specified by the // second operand. @@ -2038,6 +2764,47 @@ QualType Sema::CheckPointerToMemberOperands( // We probably need a "MemberFunctionClosureType" or something like that. QualType Result = MemPtr->getPointeeType(); Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers()); + + // C++0x [expr.mptr.oper]p6: + // In a .* expression whose object expression is an rvalue, the program is + // ill-formed if the second operand is a pointer to member function with + // ref-qualifier &. In a ->* expression or in a .* expression whose object + // expression is an lvalue, the program is ill-formed if the second operand + // is a pointer to member function with ref-qualifier &&. + if (const FunctionProtoType *Proto = Result->getAs<FunctionProtoType>()) { + switch (Proto->getRefQualifier()) { + case RQ_None: + // Do nothing + break; + + case RQ_LValue: + if (!isIndirect && !lex->Classify(Context).isLValue()) + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RType << 1 << lex->getSourceRange(); + break; + + case RQ_RValue: + if (isIndirect || !lex->Classify(Context).isRValue()) + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RType << 0 << lex->getSourceRange(); + break; + } + } + + // C++ [expr.mptr.oper]p6: + // The result of a .* expression whose second operand is a pointer + // to a data member is of the same value category as its + // first operand. The result of a .* expression whose second + // operand is a pointer to a member function is a prvalue. The + // result of an ->* expression is an lvalue if its second operand + // is a pointer to data member and a prvalue otherwise. + if (Result->isFunctionType()) + VK = VK_RValue; + else if (isIndirect) + VK = VK_LValue; + else + VK = lex->getValueKind(); + return Result; } @@ -2054,29 +2821,29 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, QualType &ToType) { HaveConversion = false; ToType = To->getType(); - - InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), + + InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), SourceLocation()); // 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 // as follows: // -- If E2 is an lvalue: - bool ToIsLvalue = (To->isLvalue(Self.Context) == Expr::LV_Valid); + bool ToIsLvalue = To->isLValue(); if (ToIsLvalue) { // E1 can be converted to match E2 if E1 can be implicitly converted to // type "lvalue reference to T2", subject to the constraint that in the // conversion the reference must bind directly to E1. QualType T = Self.Context.getLValueReferenceType(ToType); InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); - + InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); if (InitSeq.isDirectReferenceBinding()) { ToType = T; HaveConversion = true; return false; } - + if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); } @@ -2088,9 +2855,9 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, QualType TTy = To->getType(); const RecordType *FRec = FTy->getAs<RecordType>(); const RecordType *TRec = TTy->getAs<RecordType>(); - bool FDerivedFromT = FRec && TRec && FRec != TRec && + bool FDerivedFromT = FRec && TRec && FRec != TRec && Self.IsDerivedFrom(FTy, TTy); - if (FRec && TRec && + if (FRec && TRec && (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) { // E1 can be converted to match E2 if the class of T2 is the // same type as, or a base class of, the class of T1, and @@ -2103,28 +2870,28 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, HaveConversion = true; return false; } - + if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); - } + } } - + return false; } - + // -- Otherwise: E1 can be converted to match E2 if E1 can be // implicitly converted to the type that expression E2 would have - // if E2 were converted to an rvalue (or the type it has, if E2 is + // if E2 were converted to an rvalue (or the type it has, if E2 is // an rvalue). // // This actually refers very narrowly to the lvalue-to-rvalue conversion, not // to the array-to-pointer or function-to-pointer conversions. if (!TTy->getAs<TagType>()) TTy = TTy.getUnqualifiedType(); - + InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); - HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence; + HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence; ToType = TTy; if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); @@ -2138,13 +2905,14 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, /// value operand is a class type, overload resolution is used to find a /// conversion to a common type. static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, - SourceLocation Loc) { + SourceLocation QuestionLoc) { Expr *Args[2] = { LHS, RHS }; - OverloadCandidateSet CandidateSet(Loc); - Self.AddBuiltinOperatorCandidates(OO_Conditional, Loc, Args, 2, CandidateSet); + OverloadCandidateSet CandidateSet(QuestionLoc); + Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, 2, + CandidateSet); OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(Self, Loc, Best)) { + switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) { case OR_Success: // We found a match. Perform the conversions on the arguments and move on. if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], @@ -2155,13 +2923,20 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, return false; case OR_No_Viable_Function: - Self.Diag(Loc, diag::err_typecheck_cond_incompatible_operands) + + // Emit a better diagnostic if one of the expressions is a null pointer + // constant and the other is a pointer type. In this case, the user most + // likely forgot to take the address of the other expression. + if (Self.DiagnoseConditionalForNull(LHS, RHS, QuestionLoc)) + return true; + + Self.Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); return true; case OR_Ambiguous: - Self.Diag(Loc, diag::err_conditional_ambiguous_ovl) + Self.Diag(QuestionLoc, diag::err_conditional_ambiguous_ovl) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); // FIXME: Print the possible common types by printing the return types of @@ -2185,7 +2960,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) { ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&E, 1)); if (Result.isInvalid()) return true; - + E = Result.takeAs<Expr>(); return false; } @@ -2195,6 +2970,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) { /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y /// extension. In this case, LHS == Cond. (But they're not aliases.) QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++ // interface pointers. @@ -2206,6 +2982,10 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return QualType(); } + // Assume r-value. + VK = VK_RValue; + OK = OK_Ordinary; + // Either of the arguments dependent? if (LHS->isTypeDependent() || RHS->isTypeDependent()) return Context.DependentTy; @@ -2252,7 +3032,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // Otherwise, if the second and third operand have different types, and // either has (cv) class type, and attempt is made to convert each of those // operands to the other. - if (!Context.hasSameType(LTy, RTy) && + if (!Context.hasSameType(LTy, RTy) && (LTy->isRecordType() || RTy->isRecordType())) { ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft; // These return true if a single direction is already ambiguous. @@ -2262,7 +3042,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return QualType(); if (TryClassUnification(*this, RHS, LHS, QuestionLoc, HaveR2L, R2LType)) return QualType(); - + // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) @@ -2285,12 +3065,24 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, } // C++0x 5.16p4 - // If the second and third operands are lvalues and have the same type, - // the result is of that type [...] + // If the second and third operands are glvalues of the same value + // category and have the same type, the result is of that type and + // value category and it is a bit-field if the second or the third + // operand is a bit-field, or if both are bit-fields. + // We only extend this to bitfields, not to the crazy other kinds of + // l-values. bool Same = Context.hasSameType(LTy, RTy); - if (Same && LHS->isLvalue(Context) == Expr::LV_Valid && - RHS->isLvalue(Context) == Expr::LV_Valid) + if (Same && + LHS->isGLValue() && + LHS->getValueKind() == RHS->getValueKind() && + LHS->isOrdinaryOrBitFieldObject() && + RHS->isOrdinaryOrBitFieldObject()) { + VK = LHS->getValueKind(); + if (LHS->getObjectKind() == OK_BitField || + RHS->getObjectKind() == OK_BitField) + OK = OK_BitField; return LTy; + } // C++0x 5.16p5 // Otherwise, the result is an rvalue. If the second and third operands @@ -2321,18 +3113,18 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); - ExprResult LHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), - Owned(LHS)); + ExprResult LHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(LHS)); if (LHSCopy.isInvalid()) return QualType(); - - ExprResult RHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), - Owned(RHS)); + + ExprResult RHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(RHS)); if (RHSCopy.isInvalid()) return QualType(); - + LHS = LHSCopy.takeAs<Expr>(); RHS = RHSCopy.takeAs<Expr>(); } @@ -2341,7 +3133,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, } // Extension: conditional operator involving vector types. - if (LTy->isVectorType() || RTy->isVectorType()) + if (LTy->isVectorType() || RTy->isVectorType()) return CheckVectorOperands(QuestionLoc, LHS, RHS); // -- The second and third operands have arithmetic or enumeration type; @@ -2367,19 +3159,23 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, isSFINAEContext()? 0 : &NonStandardCompositeType); if (!Composite.isNull()) { if (NonStandardCompositeType) - Diag(QuestionLoc, + Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands_nonstandard) << LTy << RTy << Composite << LHS->getSourceRange() << RHS->getSourceRange(); - + return Composite; } - + // Similarly, attempt to find composite type of two objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (!Composite.isNull()) return Composite; + // Check if we are using a null with a non-pointer type. + if (DiagnoseConditionalForNull(LHS, RHS, QuestionLoc)) + return QualType(); + Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); @@ -2400,12 +3196,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, /// a non-standard (but still sane) composite type to which both expressions /// can be converted. When such a type is chosen, \c *NonStandardCompositeType /// will be set true. -QualType Sema::FindCompositePointerType(SourceLocation Loc, +QualType Sema::FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool *NonStandardCompositeType) { if (NonStandardCompositeType) *NonStandardCompositeType = false; - + assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); @@ -2422,14 +3218,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, if (T2->isMemberPointerType()) ImpCastExprToType(E1, T2, CK_NullToMemberPointer); else - ImpCastExprToType(E1, T2, CK_IntegralToPointer); + ImpCastExprToType(E1, T2, CK_NullToPointer); return T2; } if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (T1->isMemberPointerType()) ImpCastExprToType(E2, T1, CK_NullToMemberPointer); else - ImpCastExprToType(E2, T1, CK_IntegralToPointer); + ImpCastExprToType(E2, T1, CK_NullToPointer); return T1; } @@ -2456,20 +3252,20 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, ContainingClassVector MemberOfClass; QualType Composite1 = Context.getCanonicalType(T1), Composite2 = Context.getCanonicalType(T2); - unsigned NeedConstBefore = 0; + unsigned NeedConstBefore = 0; do { const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs<PointerType>()) && (Ptr2 = Composite2->getAs<PointerType>())) { Composite1 = Ptr1->getPointeeType(); Composite2 = Ptr2->getPointeeType(); - + // If we're allowed to create a non-standard composite type, keep track - // of where we need to fill in additional 'const' qualifiers. + // of where we need to fill in additional 'const' qualifiers. if (NonStandardCompositeType && Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); - + QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0)); @@ -2481,13 +3277,13 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, (MemPtr2 = Composite2->getAs<MemberPointerType>())) { Composite1 = MemPtr1->getPointeeType(); Composite2 = MemPtr2->getPointeeType(); - + // If we're allowed to create a non-standard composite type, keep track - // of where we need to fill in additional 'const' qualifiers. + // of where we need to fill in additional 'const' qualifiers. if (NonStandardCompositeType && Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); - + QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), @@ -2503,7 +3299,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, if (NeedConstBefore && NonStandardCompositeType) { // Extension: Add 'const' to qualifiers that come before the first qualifier - // mismatch, so that our (non-standard!) composite type meets the + // mismatch, so that our (non-standard!) composite type meets the // requirements of C++ [conv.qual]p4 bullet 3. for (unsigned I = 0; I != NeedConstBefore; ++I) { if ((QualifierUnion[I] & Qualifiers::Const) == 0) { @@ -2512,7 +3308,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, } } } - + // Rewrap the composites as pointers or member pointers with the union CVRs. ContainingClassVector::reverse_iterator MOC = MemberOfClass.rbegin(); @@ -2575,7 +3371,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, if (E2Result.isInvalid()) return QualType(); E2 = E2Result.takeAs<Expr>(); - + return Composite1; } @@ -2586,25 +3382,28 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); if (!E1ToC2 || !E2ToC2) return QualType(); - + // Convert E1 to Composite2 ExprResult E1Result = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E1, 1)); if (E1Result.isInvalid()) return QualType(); E1 = E1Result.takeAs<Expr>(); - + // Convert E2 to Composite2 ExprResult E2Result = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E2, 1)); if (E2Result.isInvalid()) return QualType(); E2 = E2Result.takeAs<Expr>(); - + return Composite2; } ExprResult Sema::MaybeBindToTemporary(Expr *E) { + if (!E) + return ExprError(); + if (!Context.getLangOptions().CPlusPlus) return Owned(E); @@ -2614,17 +3413,9 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!RT) return Owned(E); - // If this is the result of a call or an Objective-C message send expression, - // our source might actually be a reference, in which case we shouldn't bind. - if (CallExpr *CE = dyn_cast<CallExpr>(E)) { - if (CE->getCallReturnType()->isReferenceType()) - return Owned(E); - } else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) { - if (const ObjCMethodDecl *MD = ME->getMethodDecl()) { - if (MD->getResultType()->isReferenceType()) - return Owned(E); - } - } + // If the result is a glvalue, we shouldn't bind it. + if (E->Classify(Context).isGLValue()) + return Owned(E); // That should be enough to guarantee that this type is complete. // If it has a trivial destructor, we can avoid the extra copy. @@ -2644,48 +3435,49 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E)); } -Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr) { +Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) { assert(SubExpr && "sub expression can't be null!"); - // Check any implicit conversions within the expression. - CheckImplicitConversions(SubExpr); - unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; assert(ExprTemporaries.size() >= FirstTemporary); if (ExprTemporaries.size() == FirstTemporary) return SubExpr; - Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr, - &ExprTemporaries[FirstTemporary], - ExprTemporaries.size() - FirstTemporary); + Expr *E = ExprWithCleanups::Create(Context, SubExpr, + &ExprTemporaries[FirstTemporary], + ExprTemporaries.size() - FirstTemporary); ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary, ExprTemporaries.end()); return E; } -ExprResult -Sema::MaybeCreateCXXExprWithTemporaries(ExprResult SubExpr) { +ExprResult +Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) { if (SubExpr.isInvalid()) return ExprError(); - - return Owned(MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs<Expr>())); + + return Owned(MaybeCreateExprWithCleanups(SubExpr.take())); } -FullExpr Sema::CreateFullExpr(Expr *SubExpr) { +Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { + assert(SubStmt && "sub statement can't be null!"); + unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; assert(ExprTemporaries.size() >= FirstTemporary); - - unsigned NumTemporaries = ExprTemporaries.size() - FirstTemporary; - CXXTemporary **Temporaries = - NumTemporaries == 0 ? 0 : &ExprTemporaries[FirstTemporary]; - - FullExpr E = FullExpr::Create(Context, SubExpr, Temporaries, NumTemporaries); - - ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary, - ExprTemporaries.end()); - - return E; + if (ExprTemporaries.size() == FirstTemporary) + return SubStmt; + + // FIXME: In order to attach the temporaries, wrap the statement into + // a StmtExpr; currently this is only used for asm statements. + // This is hacky, either create a new CXXStmtWithTemporaries statement or + // a new AsmStmtWithTemporaries. + CompoundStmt *CompStmt = new (Context) CompoundStmt(Context, &SubStmt, 1, + SourceLocation(), + SourceLocation()); + Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), + SourceLocation()); + return MaybeCreateExprWithCleanups(E); } ExprResult @@ -2706,7 +3498,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, if (OpKind == tok::arrow) if (const PointerType *Ptr = BaseType->getAs<PointerType>()) BaseType = Ptr->getPointeeType(); - + ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Owned(Base); @@ -2720,7 +3512,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, llvm::SmallPtrSet<CanQualType,8> CTypes; llvm::SmallVector<SourceLocation, 8> Locations; CTypes.insert(Context.getCanonicalType(BaseType)); - + while (BaseType->isRecordType()) { Result = BuildOverloadedArrowExpr(S, Base, OpLoc); if (Result.isInvalid()) @@ -2760,10 +3552,10 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, // The object type must be complete (or dependent). if (!BaseType->isDependentType() && - RequireCompleteType(OpLoc, BaseType, + RequireCompleteType(OpLoc, BaseType, PDiag(diag::err_incomplete_member_access))) return ExprError(); - + // 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 expression is of a class @@ -2779,12 +3571,11 @@ ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, Diag(MemExpr->getLocStart(), diag::err_dtor_expr_without_call) << isa<CXXPseudoDestructorExpr>(MemExpr) << FixItHint::CreateInsertion(ExpectedLParenLoc, "()"); - + return ActOnCallExpr(/*Scope*/ 0, MemExpr, /*LPLoc*/ ExpectedLParenLoc, MultiExprArg(), - /*CommaLocs*/ 0, /*RPLoc*/ ExpectedLParenLoc); } @@ -2798,11 +3589,11 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, PseudoDestructorTypeStorage Destructed, bool HasTrailingLParen) { TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo(); - + // C++ [expr.pseudo]p2: - // The left-hand side of the dot operator shall be of scalar type. The + // The left-hand side of the dot operator shall be of scalar type. The // left-hand side of the arrow operator shall be of pointer to scalar type. - // This scalar type is the object type. + // This scalar type is the object type. QualType ObjectType = Base->getType(); if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) { @@ -2814,11 +3605,11 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, << FixItHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); - + OpKind = tok::period; } } - + if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) { Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) << ObjectType << Base->getSourceRange(); @@ -2826,7 +3617,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, } // C++ [expr.pseudo]p2: - // [...] The cv-unqualified versions of the object type and of the type + // [...] The cv-unqualified versions of the object type and of the type // designated by the pseudo-destructor-name shall be the same type. if (DestructedTypeInfo) { QualType DestructedType = DestructedTypeInfo->getType(); @@ -2837,7 +3628,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); - + // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, @@ -2845,29 +3636,29 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } } - + // C++ [expr.pseudo]p2: // [...] Furthermore, the two type-names in a pseudo-destructor-name of the // form // - // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name + // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name // // shall designate the same scalar type. if (ScopeTypeInfo) { QualType ScopeType = ScopeTypeInfo->getType(); if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(ScopeType, ObjectType)) { - + Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(), diag::err_pseudo_dtor_type_mismatch) << ObjectType << ScopeType << Base->getSourceRange() << ScopeTypeInfo->getTypeLoc().getLocalSourceRange(); - + ScopeType = QualType(); ScopeTypeInfo = 0; } } - + Expr *Result = new (Context) CXXPseudoDestructorExpr(Context, Base, OpKind == tok::arrow, OpLoc, @@ -2876,10 +3667,10 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, CCLoc, TildeLoc, Destructed); - + if (HasTrailingLParen) return Owned(Result); - + return DiagnoseDtorReference(Destructed.getLocation(), Result); } @@ -2900,9 +3691,9 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, "Invalid second type name in pseudo-destructor"); // C++ [expr.pseudo]p2: - // The left-hand side of the dot operator shall be of scalar type. The + // The left-hand side of the dot operator shall be of scalar type. The // left-hand side of the arrow operator shall be of pointer to scalar type. - // This scalar type is the object type. + // This scalar type is the object type. QualType ObjectType = Base->getType(); if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) { @@ -2914,7 +3705,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, << FixItHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); - + OpKind = tok::period; } } @@ -2928,32 +3719,32 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, else if (ObjectType->isDependentType()) ObjectTypePtrForLookup = ParsedType::make(Context.DependentTy); } - - // Convert the name of the type being destructed (following the ~) into a + + // Convert the name of the type being destructed (following the ~) into a // type (with source-location information). QualType DestructedType; TypeSourceInfo *DestructedTypeInfo = 0; PseudoDestructorTypeStorage Destructed; if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { - ParsedType T = getTypeName(*SecondTypeName.Identifier, + ParsedType T = getTypeName(*SecondTypeName.Identifier, SecondTypeName.StartLocation, - S, &SS, true, ObjectTypePtrForLookup); - if (!T && + S, &SS, true, false, ObjectTypePtrForLookup); + if (!T && ((SS.isSet() && !computeDeclContext(SS, false)) || (!SS.isSet() && ObjectType->isDependentType()))) { - // The name of the type being destroyed is a dependent name, and we + // The name of the type being destroyed is a dependent name, and we // couldn't find anything useful in scope. Just store the identifier and // it's location, and we'll perform (qualified) name lookup again at // template instantiation time. Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier, SecondTypeName.StartLocation); } else if (!T) { - Diag(SecondTypeName.StartLocation, + Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << SecondTypeName.Identifier << ObjectType; if (isSFINAEContext()) return ExprError(); - + // Recover by assuming we had the right type all along. DestructedType = ObjectType; } else @@ -2975,8 +3766,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, } else DestructedType = GetTypeFromParser(T.get(), &DestructedTypeInfo); } - - // If we've performed some kind of recovery, (re-)build the type source + + // If we've performed some kind of recovery, (re-)build the type source // information. if (!DestructedType.isNull()) { if (!DestructedTypeInfo) @@ -2984,24 +3775,24 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SecondTypeName.StartLocation); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } - + // Convert the name of the scope type (the type prior to '::') into a type. TypeSourceInfo *ScopeTypeInfo = 0; QualType ScopeType; - if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || + if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || FirstTypeName.Identifier) { if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { - ParsedType T = getTypeName(*FirstTypeName.Identifier, + ParsedType T = getTypeName(*FirstTypeName.Identifier, FirstTypeName.StartLocation, - S, &SS, false, ObjectTypePtrForLookup); + S, &SS, false, false, ObjectTypePtrForLookup); if (!T) { - Diag(FirstTypeName.StartLocation, + Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << FirstTypeName.Identifier << ObjectType; - + if (isSFINAEContext()) return ExprError(); - + // Just drop this type. It's unnecessary anyway. ScopeType = QualType(); } else @@ -3021,39 +3812,100 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, // Recover by dropping this type. ScopeType = QualType(); } else - ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); + ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); } } - + if (!ScopeType.isNull() && !ScopeTypeInfo) ScopeTypeInfo = Context.getTrivialTypeSourceInfo(ScopeType, FirstTypeName.StartLocation); - + return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, SS, ScopeTypeInfo, CCLoc, TildeLoc, Destructed, HasTrailingLParen); } -CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, - NamedDecl *FoundDecl, - CXXMethodDecl *Method) { +ExprResult Sema::BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, + CXXMethodDecl *Method) { if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, FoundDecl, Method)) - assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?"); + return true; - MemberExpr *ME = + MemberExpr *ME = new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, - SourceLocation(), Method->getType()); - QualType ResultType = Method->getCallResultType(); + SourceLocation(), Method->getType(), + VK_RValue, OK_Ordinary); + QualType ResultType = Method->getResultType(); + ExprValueKind VK = Expr::getValueKindForType(ResultType); + ResultType = ResultType.getNonLValueExprType(Context); + MarkDeclarationReferenced(Exp->getLocStart(), Method); CXXMemberCallExpr *CE = - new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, + new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, VK, Exp->getLocEnd()); return CE; } +ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, + SourceLocation RParen) { + return Owned(new (Context) CXXNoexceptExpr(Context.BoolTy, Operand, + Operand->CanThrow(Context), + KeyLoc, RParen)); +} + +ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, + Expr *Operand, SourceLocation RParen) { + return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen); +} + +/// Perform the conversions required for an expression used in a +/// context that ignores the result. +void Sema::IgnoredValueConversions(Expr *&E) { + // C99 6.3.2.1: + // [Except in specific positions,] an lvalue that does not have + // array type is converted to the value stored in the + // designated object (and is no longer an lvalue). + if (E->isRValue()) return; + + // We always want to do this on ObjC property references. + if (E->getObjectKind() == OK_ObjCProperty) { + ConvertPropertyForRValue(E); + if (E->isRValue()) return; + } + + // Otherwise, this rule does not apply in C++, at least not for the moment. + if (getLangOptions().CPlusPlus) return; + + // GCC seems to also exclude expressions of incomplete enum type. + if (const EnumType *T = E->getType()->getAs<EnumType>()) { + if (!T->getDecl()->isComplete()) { + // FIXME: stupid workaround for a codegen bug! + ImpCastExprToType(E, Context.VoidTy, CK_ToVoid); + return; + } + } + + DefaultFunctionArrayLvalueConversion(E); + if (!E->getType()->isVoidType()) + RequireCompleteType(E->getExprLoc(), E->getType(), + diag::err_incomplete_type); +} + ExprResult Sema::ActOnFinishFullExpr(Expr *FullExpr) { - if (!FullExpr) return ExprError(); - return MaybeCreateCXXExprWithTemporaries(FullExpr); + if (!FullExpr) + return ExprError(); + + if (DiagnoseUnexpandedParameterPack(FullExpr)) + return ExprError(); + + IgnoredValueConversions(FullExpr); + CheckImplicitConversions(FullExpr); + return MaybeCreateExprWithCleanups(FullExpr); +} + +StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { + if (!FullStmt) return StmtError(); + + return MaybeCreateStmtWithCleanups(FullStmt); } |