| //===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// \brief Implements semantic analysis for C++ expressions. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/Sema/SemaInternal.h" |
| #include "TypeLocBuilder.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/CXXInheritance.h" |
| #include "clang/AST/CharUnits.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/EvaluatedExprVisitor.h" |
| #include "clang/AST/ExprCXX.h" |
| #include "clang/AST/ExprObjC.h" |
| #include "clang/AST/RecursiveASTVisitor.h" |
| #include "clang/AST/TypeLoc.h" |
| #include "clang/Basic/PartialDiagnostic.h" |
| #include "clang/Basic/TargetInfo.h" |
| #include "clang/Lex/Preprocessor.h" |
| #include "clang/Sema/DeclSpec.h" |
| #include "clang/Sema/Initialization.h" |
| #include "clang/Sema/Lookup.h" |
| #include "clang/Sema/ParsedTemplate.h" |
| #include "clang/Sema/Scope.h" |
| #include "clang/Sema/ScopeInfo.h" |
| #include "clang/Sema/SemaLambda.h" |
| #include "clang/Sema/TemplateDeduction.h" |
| #include "llvm/ADT/APInt.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/Support/ErrorHandling.h" |
| using namespace clang; |
| using namespace sema; |
| |
| /// \brief Handle the result of the special case name lookup for inheriting |
| /// constructor declarations. 'NS::X::X' and 'NS::X<...>::X' are treated as |
| /// constructor names in member using declarations, even if 'X' is not the |
| /// name of the corresponding type. |
| ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, |
| SourceLocation NameLoc, |
| IdentifierInfo &Name) { |
| NestedNameSpecifier *NNS = SS.getScopeRep(); |
| |
| // Convert the nested-name-specifier into a type. |
| QualType Type; |
| switch (NNS->getKind()) { |
| case NestedNameSpecifier::TypeSpec: |
| case NestedNameSpecifier::TypeSpecWithTemplate: |
| Type = QualType(NNS->getAsType(), 0); |
| break; |
| |
| case NestedNameSpecifier::Identifier: |
| // Strip off the last layer of the nested-name-specifier and build a |
| // typename type for it. |
| assert(NNS->getAsIdentifier() == &Name && "not a constructor name"); |
| Type = Context.getDependentNameType(ETK_None, NNS->getPrefix(), |
| NNS->getAsIdentifier()); |
| break; |
| |
| case NestedNameSpecifier::Global: |
| case NestedNameSpecifier::Namespace: |
| case NestedNameSpecifier::NamespaceAlias: |
| llvm_unreachable("Nested name specifier is not a type for inheriting ctor"); |
| } |
| |
| // This reference to the type is located entirely at the location of the |
| // final identifier in the qualified-id. |
| return CreateParsedType(Type, |
| Context.getTrivialTypeSourceInfo(Type, NameLoc)); |
| } |
| |
| ParsedType Sema::getDestructorName(SourceLocation TildeLoc, |
| IdentifierInfo &II, |
| SourceLocation NameLoc, |
| Scope *S, CXXScopeSpec &SS, |
| ParsedType ObjectTypePtr, |
| bool EnteringContext) { |
| // Determine where to perform name lookup. |
| |
| // FIXME: This area of the standard is very messy, and the current |
| // wording is rather unclear about which scopes we search for the |
| // destructor name; see core issues 399 and 555. Issue 399 in |
| // particular shows where the current description of destructor name |
| // lookup is completely out of line with existing practice, e.g., |
| // this appears to be ill-formed: |
| // |
| // namespace N { |
| // template <typename T> struct S { |
| // ~S(); |
| // }; |
| // } |
| // |
| // void f(N::S<int>* s) { |
| // s->N::S<int>::~S(); |
| // } |
| // |
| // See also PR6358 and PR6359. |
| // For this reason, we're currently only doing the C++03 version of this |
| // code; the C++0x version has to wait until we get a proper spec. |
| QualType SearchType; |
| DeclContext *LookupCtx = 0; |
| bool isDependent = false; |
| bool LookInScope = false; |
| |
| // If we have an object type, it's because we are in a |
| // pseudo-destructor-expression or a member access expression, and |
| // we know what type we're looking for. |
| if (ObjectTypePtr) |
| SearchType = GetTypeFromParser(ObjectTypePtr); |
| |
| if (SS.isSet()) { |
| NestedNameSpecifier *NNS = 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, |
| // 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 |
| // |
| // 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 |
| // |
| // 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 |
| // nested-name-specifier. |
| DeclContext *DC = computeDeclContext(SS, EnteringContext); |
| if (DC && DC->isFileContext()) { |
| AlreadySearched = true; |
| LookupCtx = DC; |
| 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) { |
| // Nothing left to do. |
| } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) { |
| CXXScopeSpec PrefixSS; |
| PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data())); |
| LookupCtx = computeDeclContext(PrefixSS, EnteringContext); |
| isDependent = isDependentScopeSpecifier(PrefixSS); |
| } else if (ObjectTypePtr) { |
| LookupCtx = computeDeclContext(SearchType); |
| isDependent = SearchType->isDependentType(); |
| } else { |
| LookupCtx = computeDeclContext(SS, EnteringContext); |
| isDependent = LookupCtx && LookupCtx->isDependentContext(); |
| } |
| |
| LookInScope = false; |
| } else if (ObjectTypePtr) { |
| // C++ [basic.lookup.classref]p3: |
| // If the unqualified-id is ~type-name, the type-name is looked up |
| // in the context of the entire postfix-expression. If the type T |
| // of the object expression is of a class type C, the type-name is |
| // also looked up in the scope of class C. At least one of the |
| // lookups shall find a name that refers to (possibly |
| // cv-qualified) T. |
| LookupCtx = computeDeclContext(SearchType); |
| isDependent = SearchType->isDependentType(); |
| assert((isDependent || !SearchType->isIncompleteType()) && |
| "Caller should have completed object type"); |
| |
| LookInScope = true; |
| } else { |
| // Perform lookup into the current scope (only). |
| LookInScope = true; |
| } |
| |
| TypeDecl *NonMatchingTypeDecl = 0; |
| LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); |
| for (unsigned Step = 0; Step != 2; ++Step) { |
| // Look for the name first in the computed lookup context (if we |
| // have one) and, if that fails to find a match, in the scope (if |
| // we're allowed to look there). |
| Found.clear(); |
| if (Step == 0 && LookupCtx) |
| LookupQualifiedName(Found, LookupCtx); |
| else if (Step == 1 && LookInScope && S) |
| LookupName(Found, S); |
| else |
| continue; |
| |
| // FIXME: Should we be suppressing ambiguities here? |
| if (Found.isAmbiguous()) |
| return ParsedType(); |
| |
| if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) { |
| QualType T = Context.getTypeDeclType(Type); |
| |
| if (SearchType.isNull() || SearchType->isDependentType() || |
| Context.hasSameUnqualifiedType(T, SearchType)) { |
| // We found our type! |
| |
| return CreateParsedType(T, |
| Context.getTrivialTypeSourceInfo(T, NameLoc)); |
| } |
| |
| if (!SearchType.isNull()) |
| NonMatchingTypeDecl = Type; |
| } |
| |
| // If the name that we found is a class template name, and it is |
| // the same name as the template name in the last part of the |
| // 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. |
| if (ClassTemplateDecl *Template = Found.getAsSingle<ClassTemplateDecl>()) { |
| QualType MemberOfType; |
| if (SS.isSet()) { |
| if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) { |
| // Figure out the type of the context, if it has one. |
| if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) |
| MemberOfType = Context.getTypeDeclType(Record); |
| } |
| } |
| if (MemberOfType.isNull()) |
| MemberOfType = SearchType; |
| |
| if (MemberOfType.isNull()) |
| continue; |
| |
| // We're referring into a class template specialization. If the |
| // class template we found is the same as the template being |
| // specialized, we found what we are looking for. |
| if (const RecordType *Record = MemberOfType->getAs<RecordType>()) { |
| if (ClassTemplateSpecializationDecl *Spec |
| = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { |
| if (Spec->getSpecializedTemplate()->getCanonicalDecl() == |
| Template->getCanonicalDecl()) |
| return CreateParsedType( |
| MemberOfType, |
| Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); |
| } |
| |
| 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 |
| // know which template is being specialized, that it at least |
| // has the same name. |
| if (const TemplateSpecializationType *SpecType |
| = MemberOfType->getAs<TemplateSpecializationType>()) { |
| TemplateName SpecName = SpecType->getTemplateName(); |
| |
| // The class template we found is the same template being |
| // specialized. |
| if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) { |
| if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl()) |
| return CreateParsedType( |
| MemberOfType, |
| Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); |
| |
| continue; |
| } |
| |
| // The class template we found has the same name as the |
| // (dependent) template name being specialized. |
| if (DependentTemplateName *DepTemplate |
| = SpecName.getAsDependentTemplateName()) { |
| if (DepTemplate->isIdentifier() && |
| DepTemplate->getIdentifier() == Template->getIdentifier()) |
| return CreateParsedType( |
| MemberOfType, |
| Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); |
| |
| continue; |
| } |
| } |
| } |
| } |
| |
| if (isDependent) { |
| // We didn't find our type, but that's okay: it's dependent |
| // anyway. |
| |
| // FIXME: What if we have no nested-name-specifier? |
| QualType T = CheckTypenameType(ETK_None, SourceLocation(), |
| SS.getWithLocInContext(Context), |
| II, NameLoc); |
| return ParsedType::make(T); |
| } |
| |
| if (NonMatchingTypeDecl) { |
| QualType T = Context.getTypeDeclType(NonMatchingTypeDecl); |
| Diag(NameLoc, diag::err_destructor_expr_type_mismatch) |
| << T << SearchType; |
| Diag(NonMatchingTypeDecl->getLocation(), diag::note_destructor_type_here) |
| << T; |
| } else if (ObjectTypePtr) |
| Diag(NameLoc, diag::err_ident_in_dtor_not_a_type) |
| << &II; |
| else { |
| SemaDiagnosticBuilder DtorDiag = Diag(NameLoc, |
| diag::err_destructor_class_name); |
| if (S) { |
| const DeclContext *Ctx = S->getEntity(); |
| if (const CXXRecordDecl *Class = dyn_cast_or_null<CXXRecordDecl>(Ctx)) |
| DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc), |
| Class->getNameAsString()); |
| } |
| } |
| |
| return ParsedType(); |
| } |
| |
| ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) { |
| if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType) |
| return ParsedType(); |
| assert(DS.getTypeSpecType() == DeclSpec::TST_decltype |
| && "only get destructor types from declspecs"); |
| QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); |
| QualType SearchType = GetTypeFromParser(ObjectType); |
| if (SearchType->isDependentType() || Context.hasSameUnqualifiedType(SearchType, T)) { |
| return ParsedType::make(T); |
| } |
| |
| Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch) |
| << T << SearchType; |
| return ParsedType(); |
| } |
| |
| bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, |
| const UnqualifiedId &Name) { |
| assert(Name.getKind() == UnqualifiedId::IK_LiteralOperatorId); |
| |
| if (!SS.isValid()) |
| return false; |
| |
| switch (SS.getScopeRep()->getKind()) { |
| case NestedNameSpecifier::Identifier: |
| case NestedNameSpecifier::TypeSpec: |
| case NestedNameSpecifier::TypeSpecWithTemplate: |
| // Per C++11 [over.literal]p2, literal operators can only be declared at |
| // namespace scope. Therefore, this unqualified-id cannot name anything. |
| // Reject it early, because we have no AST representation for this in the |
| // case where the scope is dependent. |
| Diag(Name.getLocStart(), diag::err_literal_operator_id_outside_namespace) |
| << SS.getScopeRep(); |
| return true; |
| |
| case NestedNameSpecifier::Global: |
| case NestedNameSpecifier::Namespace: |
| case NestedNameSpecifier::NamespaceAlias: |
| return false; |
| } |
| |
| llvm_unreachable("unknown nested name specifier kind"); |
| } |
| |
| /// \brief Build a C++ typeid expression with a type operand. |
| ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, |
| SourceLocation TypeidLoc, |
| TypeSourceInfo *Operand, |
| SourceLocation RParenLoc) { |
| // C++ [expr.typeid]p4: |
| // 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 |
| // type, the class shall be completely-defined. |
| Qualifiers Quals; |
| QualType T |
| = Context.getUnqualifiedArrayType(Operand->getType().getNonReferenceType(), |
| Quals); |
| if (T->getAs<RecordType>() && |
| RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) |
| return ExprError(); |
| |
| return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), |
| Operand, |
| SourceRange(TypeidLoc, RParenLoc))); |
| } |
| |
| /// \brief Build a C++ typeid expression with an expression operand. |
| ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, |
| SourceLocation TypeidLoc, |
| Expr *E, |
| SourceLocation RParenLoc) { |
| if (E && !E->isTypeDependent()) { |
| if (E->getType()->isPlaceholderType()) { |
| ExprResult result = CheckPlaceholderExpr(E); |
| if (result.isInvalid()) return ExprError(); |
| E = result.take(); |
| } |
| |
| QualType T = E->getType(); |
| if (const RecordType *RecordT = T->getAs<RecordType>()) { |
| CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); |
| // C++ [expr.typeid]p3: |
| // [...] If the type of the expression is a class type, the class |
| // 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 |
| // operand. [...] |
| if (RecordD->isPolymorphic() && E->isGLValue()) { |
| // The subexpression is potentially evaluated; switch the context |
| // and recheck the subexpression. |
| ExprResult Result = TransformToPotentiallyEvaluated(E); |
| if (Result.isInvalid()) return ExprError(); |
| E = Result.take(); |
| |
| // We require a vtable to query the type at run time. |
| 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 |
| // type. |
| Qualifiers Quals; |
| QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); |
| if (!Context.hasSameType(T, UnqualT)) { |
| T = UnqualT; |
| E = ImpCastExprToType(E, UnqualT, CK_NoOp, E->getValueKind()).take(); |
| } |
| } |
| |
| return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), |
| E, |
| SourceRange(TypeidLoc, RParenLoc))); |
| } |
| |
| /// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression); |
| ExprResult |
| Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, |
| bool isType, void *TyOrExpr, SourceLocation RParenLoc) { |
| // Find the std::type_info type. |
| if (!getStdNamespace()) |
| return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); |
| |
| if (!CXXTypeInfoDecl) { |
| IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); |
| LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); |
| LookupQualifiedName(R, getStdNamespace()); |
| CXXTypeInfoDecl = R.getAsSingle<RecordDecl>(); |
| // Microsoft's typeinfo doesn't have type_info in std but in the global |
| // namespace if _HAS_EXCEPTIONS is defined to 0. See PR13153. |
| if (!CXXTypeInfoDecl && LangOpts.MSVCCompat) { |
| LookupQualifiedName(R, Context.getTranslationUnitDecl()); |
| CXXTypeInfoDecl = R.getAsSingle<RecordDecl>(); |
| } |
| if (!CXXTypeInfoDecl) |
| return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); |
| } |
| |
| if (!getLangOpts().RTTI) { |
| return ExprError(Diag(OpLoc, diag::err_no_typeid_with_fno_rtti)); |
| } |
| |
| QualType TypeInfoType = Context.getTypeDeclType(CXXTypeInfoDecl); |
| |
| 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 BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc); |
| } |
| |
| // The operand is an expression. |
| return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); |
| } |
| |
| /// \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()) { |
| bool HasMultipleGUIDs = false; |
| if (!CXXUuidofExpr::GetUuidAttrOfType(Operand->getType(), |
| &HasMultipleGUIDs)) { |
| if (HasMultipleGUIDs) |
| return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); |
| else |
| return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); |
| } |
| } |
| |
| 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()) { |
| bool HasMultipleGUIDs = false; |
| if (!CXXUuidofExpr::GetUuidAttrOfType(E->getType(), &HasMultipleGUIDs) && |
| !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { |
| if (HasMultipleGUIDs) |
| return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); |
| else |
| return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); |
| } |
| } |
| |
| 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) { |
| assert((Kind == tok::kw_true || Kind == tok::kw_false) && |
| "Unknown C++ Boolean value!"); |
| return Owned(new (Context) CXXBoolLiteralExpr(Kind == tok::kw_true, |
| Context.BoolTy, OpLoc)); |
| } |
| |
| /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. |
| ExprResult |
| Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { |
| return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc)); |
| } |
| |
| /// ActOnCXXThrow - Parse throw expressions. |
| ExprResult |
| Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) { |
| bool IsThrownVarInScope = false; |
| if (Ex) { |
| // C++0x [class.copymove]p31: |
| // When certain criteria are met, an implementation is allowed to omit the |
| // copy/move construction of a class object [...] |
| // |
| // - in a throw-expression, when the operand is the name of a |
| // non-volatile automatic object (other than a function or catch- |
| // clause parameter) whose scope does not extend beyond the end of the |
| // innermost enclosing try-block (if there is one), the copy/move |
| // operation from the operand to the exception object (15.1) can be |
| // omitted by constructing the automatic object directly into the |
| // exception object |
| if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex->IgnoreParens())) |
| if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { |
| if (Var->hasLocalStorage() && !Var->getType().isVolatileQualified()) { |
| for( ; S; S = S->getParent()) { |
| if (S->isDeclScope(Var)) { |
| IsThrownVarInScope = true; |
| break; |
| } |
| |
| if (S->getFlags() & |
| (Scope::FnScope | Scope::ClassScope | Scope::BlockScope | |
| Scope::FunctionPrototypeScope | Scope::ObjCMethodScope | |
| Scope::TryScope)) |
| break; |
| } |
| } |
| } |
| } |
| |
| return BuildCXXThrow(OpLoc, Ex, IsThrownVarInScope); |
| } |
| |
| ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, |
| bool IsThrownVarInScope) { |
| // Don't report an error if 'throw' is used in system headers. |
| if (!getLangOpts().CXXExceptions && |
| !getSourceManager().isInSystemHeader(OpLoc)) |
| Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; |
| |
| if (Ex && !Ex->isTypeDependent()) { |
| ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope); |
| if (ExRes.isInvalid()) |
| return ExprError(); |
| Ex = ExRes.take(); |
| } |
| |
| return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc, |
| IsThrownVarInScope)); |
| } |
| |
| /// CheckCXXThrowOperand - Validate the operand of a throw. |
| ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, |
| bool IsThrownVarInScope) { |
| // C++ [except.throw]p3: |
| // 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" |
| // or "pointer to function returning T", [...] |
| if (E->getType().hasQualifiers()) |
| E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, |
| E->getValueKind()).take(); |
| |
| ExprResult Res = DefaultFunctionArrayConversion(E); |
| if (Res.isInvalid()) |
| return ExprError(); |
| E = Res.take(); |
| |
| // If the type of the exception would be an incomplete type or a pointer |
| // to an incomplete type other than (cv) void the program is ill-formed. |
| QualType Ty = E->getType(); |
| bool isPointer = false; |
| if (const PointerType* Ptr = Ty->getAs<PointerType>()) { |
| Ty = Ptr->getPointeeType(); |
| isPointer = true; |
| } |
| if (!isPointer || !Ty->isVoidType()) { |
| if (RequireCompleteType(ThrowLoc, Ty, |
| isPointer? diag::err_throw_incomplete_ptr |
| : diag::err_throw_incomplete, |
| E->getSourceRange())) |
| return ExprError(); |
| |
| if (RequireNonAbstractType(ThrowLoc, E->getType(), |
| diag::err_throw_abstract_type, E)) |
| return ExprError(); |
| } |
| |
| // Initialize the exception result. This implicitly weeds out |
| // abstract types or types with inaccessible copy constructors. |
| |
| // C++0x [class.copymove]p31: |
| // When certain criteria are met, an implementation is allowed to omit the |
| // copy/move construction of a class object [...] |
| // |
| // - in a throw-expression, when the operand is the name of a |
| // non-volatile automatic object (other than a function or catch-clause |
| // parameter) whose scope does not extend beyond the end of the |
| // innermost enclosing try-block (if there is one), the copy/move |
| // operation from the operand to the exception object (15.1) can be |
| // omitted by constructing the automatic object directly into the |
| // exception object |
| const VarDecl *NRVOVariable = 0; |
| if (IsThrownVarInScope) |
| NRVOVariable = getCopyElisionCandidate(QualType(), E, false); |
| |
| InitializedEntity Entity = |
| InitializedEntity::InitializeException(ThrowLoc, E->getType(), |
| /*NRVO=*/NRVOVariable != 0); |
| Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable, |
| QualType(), E, |
| IsThrownVarInScope); |
| if (Res.isInvalid()) |
| return ExprError(); |
| E = Res.take(); |
| |
| // If the exception has class type, we need additional handling. |
| const RecordType *RecordTy = Ty->getAs<RecordType>(); |
| if (!RecordTy) |
| return Owned(E); |
| CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); |
| |
| // If we are throwing a polymorphic class type or pointer thereof, |
| // 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 Owned(E); |
| |
| // If the class has a destructor, we must be able to call it. |
| if (RD->hasIrrelevantDestructor()) |
| return Owned(E); |
| |
| CXXDestructorDecl *Destructor = LookupDestructor(RD); |
| if (!Destructor) |
| return Owned(E); |
| |
| MarkFunctionReferenced(E->getExprLoc(), Destructor); |
| CheckDestructorAccess(E->getExprLoc(), Destructor, |
| PDiag(diag::err_access_dtor_exception) << Ty); |
| if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) |
| return ExprError(); |
| return Owned(E); |
| } |
| |
| QualType Sema::getCurrentThisType() { |
| DeclContext *DC = getFunctionLevelDeclContext(); |
| QualType ThisTy = CXXThisTypeOverride; |
| if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) { |
| if (method && method->isInstance()) |
| ThisTy = method->getThisType(Context); |
| } |
| |
| return ThisTy; |
| } |
| |
| Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, |
| Decl *ContextDecl, |
| unsigned CXXThisTypeQuals, |
| bool Enabled) |
| : S(S), OldCXXThisTypeOverride(S.CXXThisTypeOverride), Enabled(false) |
| { |
| if (!Enabled || !ContextDecl) |
| return; |
| |
| CXXRecordDecl *Record = 0; |
| if (ClassTemplateDecl *Template = dyn_cast<ClassTemplateDecl>(ContextDecl)) |
| Record = Template->getTemplatedDecl(); |
| else |
| Record = cast<CXXRecordDecl>(ContextDecl); |
| |
| S.CXXThisTypeOverride |
| = S.Context.getPointerType( |
| S.Context.getRecordType(Record).withCVRQualifiers(CXXThisTypeQuals)); |
| |
| this->Enabled = true; |
| } |
| |
| |
| Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { |
| if (Enabled) { |
| S.CXXThisTypeOverride = OldCXXThisTypeOverride; |
| } |
| } |
| |
| static Expr *captureThis(ASTContext &Context, RecordDecl *RD, |
| QualType ThisTy, SourceLocation Loc) { |
| FieldDecl *Field |
| = FieldDecl::Create(Context, RD, Loc, Loc, 0, ThisTy, |
| Context.getTrivialTypeSourceInfo(ThisTy, Loc), |
| 0, false, ICIS_NoInit); |
| Field->setImplicit(true); |
| Field->setAccess(AS_private); |
| RD->addDecl(Field); |
| return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true); |
| } |
| |
| bool Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit, |
| bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt) { |
| // We don't need to capture this in an unevaluated context. |
| if (isUnevaluatedContext() && !Explicit) |
| return true; |
| |
| const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? |
| *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; |
| // Otherwise, check that we can capture 'this'. |
| unsigned NumClosures = 0; |
| for (unsigned idx = MaxFunctionScopesIndex; idx != 0; idx--) { |
| if (CapturingScopeInfo *CSI = |
| dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) { |
| if (CSI->CXXThisCaptureIndex != 0) { |
| // 'this' is already being captured; there isn't anything more to do. |
| break; |
| } |
| LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI); |
| if (LSI && isGenericLambdaCallOperatorSpecialization(LSI->CallOperator)) { |
| // This context can't implicitly capture 'this'; fail out. |
| if (BuildAndDiagnose) |
| Diag(Loc, diag::err_this_capture) << Explicit; |
| return true; |
| } |
| if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref || |
| CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval || |
| CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block || |
| CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_CapturedRegion || |
| Explicit) { |
| // This closure can capture 'this'; continue looking upwards. |
| NumClosures++; |
| Explicit = false; |
| continue; |
| } |
| // This context can't implicitly capture 'this'; fail out. |
| if (BuildAndDiagnose) |
| Diag(Loc, diag::err_this_capture) << Explicit; |
| return true; |
| } |
| break; |
| } |
| if (!BuildAndDiagnose) return false; |
| // Mark that we're implicitly capturing 'this' in all the scopes we skipped. |
| // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated |
| // contexts. |
| for (unsigned idx = MaxFunctionScopesIndex; NumClosures; |
| --idx, --NumClosures) { |
| CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]); |
| Expr *ThisExpr = 0; |
| QualType ThisTy = getCurrentThisType(); |
| if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) |
| // For lambda expressions, build a field and an initializing expression. |
| ThisExpr = captureThis(Context, LSI->Lambda, ThisTy, Loc); |
| else if (CapturedRegionScopeInfo *RSI |
| = dyn_cast<CapturedRegionScopeInfo>(FunctionScopes[idx])) |
| ThisExpr = captureThis(Context, RSI->TheRecordDecl, ThisTy, Loc); |
| |
| bool isNested = NumClosures > 1; |
| CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr); |
| } |
| return false; |
| } |
| |
| 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. |
| |
| QualType ThisTy = getCurrentThisType(); |
| if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use); |
| |
| CheckCXXThisCapture(Loc); |
| return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false)); |
| } |
| |
| bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { |
| // If we're outside the body of a member function, then we'll have a specified |
| // type for 'this'. |
| if (CXXThisTypeOverride.isNull()) |
| return false; |
| |
| // Determine whether we're looking into a class that's currently being |
| // defined. |
| CXXRecordDecl *Class = BaseType->getAsCXXRecordDecl(); |
| return Class && Class->isBeingDefined(); |
| } |
| |
| ExprResult |
| Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, |
| SourceLocation LParenLoc, |
| MultiExprArg exprs, |
| SourceLocation RParenLoc) { |
| if (!TypeRep) |
| return ExprError(); |
| |
| TypeSourceInfo *TInfo; |
| 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(); |
| SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); |
| |
| if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { |
| return Owned(CXXUnresolvedConstructExpr::Create(Context, TInfo, |
| LParenLoc, |
| Exprs, |
| RParenLoc)); |
| } |
| |
| bool ListInitialization = LParenLoc.isInvalid(); |
| assert((!ListInitialization || (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) |
| && "List initialization must have initializer list as expression."); |
| SourceRange FullRange = SourceRange(TyBeginLoc, |
| ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc); |
| |
| // C++ [expr.type.conv]p1: |
| // If the expression list is a single expression, the type conversion |
| // expression is equivalent (in definedness, and if defined in meaning) to the |
| // corresponding cast expression. |
| if (Exprs.size() == 1 && !ListInitialization) { |
| Expr *Arg = Exprs[0]; |
| return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc); |
| } |
| |
| QualType ElemTy = Ty; |
| if (Ty->isArrayType()) { |
| if (!ListInitialization) |
| return ExprError(Diag(TyBeginLoc, |
| diag::err_value_init_for_array_type) << FullRange); |
| ElemTy = Context.getBaseElementType(Ty); |
| } |
| |
| if (!Ty->isVoidType() && |
| RequireCompleteType(TyBeginLoc, ElemTy, |
| diag::err_invalid_incomplete_type_use, FullRange)) |
| return ExprError(); |
| |
| if (RequireNonAbstractType(TyBeginLoc, Ty, |
| diag::err_allocation_of_abstract_type)) |
| return ExprError(); |
| |
| InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); |
| InitializationKind Kind = |
| Exprs.size() ? ListInitialization |
| ? InitializationKind::CreateDirectList(TyBeginLoc) |
| : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, RParenLoc) |
| : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); |
| InitializationSequence InitSeq(*this, Entity, Kind, Exprs); |
| ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs); |
| |
| if (Result.isInvalid() || !ListInitialization) |
| return Result; |
| |
| Expr *Inner = Result.get(); |
| if (CXXBindTemporaryExpr *BTE = dyn_cast_or_null<CXXBindTemporaryExpr>(Inner)) |
| Inner = BTE->getSubExpr(); |
| if (isa<InitListExpr>(Inner)) { |
| // If the list-initialization doesn't involve a constructor call, we'll get |
| // the initializer-list (with corrected type) back, but that's not what we |
| // want, since it will be treated as an initializer list in further |
| // processing. Explicitly insert a cast here. |
| QualType ResultType = Result.get()->getType(); |
| Result = Owned(CXXFunctionalCastExpr::Create( |
| Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo, |
| CK_NoOp, Result.take(), /*Path=*/ 0, LParenLoc, RParenLoc)); |
| } |
| |
| // FIXME: Improve AST representation? |
| return 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(); |
| |
| // 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(); |
| |
| if (!ops.isSingleResult()) return false; |
| |
| const FunctionDecl *del = cast<FunctionDecl>(ops.getFoundDecl()); |
| return (del->getNumParams() == 2); |
| } |
| |
| /// \brief Parsed a C++ 'new' expression (C++ 5.3.4). |
| /// |
| /// E.g.: |
| /// @code new (memory) int[size][4] @endcode |
| /// or |
| /// @code ::new Foo(23, "hello") @endcode |
| /// |
| /// \param StartLoc The first location of the expression. |
| /// \param UseGlobal True if 'new' was prefixed with '::'. |
| /// \param PlacementLParen Opening paren of the placement arguments. |
| /// \param PlacementArgs Placement new arguments. |
| /// \param PlacementRParen Closing paren of the placement arguments. |
| /// \param TypeIdParens If the type is in parens, the source range. |
| /// \param D The type to be allocated, as well as array dimensions. |
| /// \param Initializer The initializing expression or initializer-list, or null |
| /// if there is none. |
| ExprResult |
| Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, |
| SourceLocation PlacementLParen, MultiExprArg PlacementArgs, |
| SourceLocation PlacementRParen, SourceRange TypeIdParens, |
| Declarator &D, Expr *Initializer) { |
| bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType(); |
| |
| 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()); |
| if (!Chunk.Arr.NumElts) |
| return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) |
| << D.getSourceRange()); |
| |
| ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts); |
| D.DropFirstTypeObject(); |
| } |
| |
| // Every dimension shall be of constant size. |
| if (ArraySize) { |
| for (unsigned I = 0, N = D.getNumTypeObjects(); I < N; ++I) { |
| if (D.getTypeObject(I).Kind != DeclaratorChunk::Array) |
| break; |
| |
| DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr; |
| if (Expr *NumElts = (Expr *)Array.NumElts) { |
| if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) { |
| if (getLangOpts().CPlusPlus1y) { |
| // C++1y [expr.new]p6: Every constant-expression in a noptr-new-declarator |
| // shall be a converted constant expression (5.19) of type std::size_t |
| // and shall evaluate to a strictly positive value. |
| unsigned IntWidth = Context.getTargetInfo().getIntWidth(); |
| assert(IntWidth && "Builtin type of size 0?"); |
| llvm::APSInt Value(IntWidth); |
| Array.NumElts |
| = CheckConvertedConstantExpression(NumElts, Context.getSizeType(), Value, |
| CCEK_NewExpr) |
| .take(); |
| } else { |
| Array.NumElts |
| = VerifyIntegerConstantExpression(NumElts, 0, |
| diag::err_new_array_nonconst) |
| .take(); |
| } |
| if (!Array.NumElts) |
| return ExprError(); |
| } |
| } |
| } |
| } |
| |
| TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0); |
| QualType AllocType = TInfo->getType(); |
| if (D.isInvalidType()) |
| return ExprError(); |
| |
| SourceRange DirectInitRange; |
| if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) |
| DirectInitRange = List->getSourceRange(); |
| |
| return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal, |
| PlacementLParen, |
| PlacementArgs, |
| PlacementRParen, |
| TypeIdParens, |
| AllocType, |
| TInfo, |
| ArraySize, |
| DirectInitRange, |
| Initializer, |
| TypeContainsAuto); |
| } |
| |
| static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style, |
| Expr *Init) { |
| if (!Init) |
| return true; |
| if (ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init)) |
| return PLE->getNumExprs() == 0; |
| if (isa<ImplicitValueInitExpr>(Init)) |
| return true; |
| else if (CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) |
| return !CCE->isListInitialization() && |
| CCE->getConstructor()->isDefaultConstructor(); |
| else if (Style == CXXNewExpr::ListInit) { |
| assert(isa<InitListExpr>(Init) && |
| "Shouldn't create list CXXConstructExprs for arrays."); |
| return true; |
| } |
| return false; |
| } |
| |
| ExprResult |
| Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, |
| SourceLocation PlacementLParen, |
| MultiExprArg PlacementArgs, |
| SourceLocation PlacementRParen, |
| SourceRange TypeIdParens, |
| QualType AllocType, |
| TypeSourceInfo *AllocTypeInfo, |
| Expr *ArraySize, |
| SourceRange DirectInitRange, |
| Expr *Initializer, |
| bool TypeMayContainAuto) { |
| SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange(); |
| SourceLocation StartLoc = Range.getBegin(); |
| |
| CXXNewExpr::InitializationStyle initStyle; |
| if (DirectInitRange.isValid()) { |
| assert(Initializer && "Have parens but no initializer."); |
| initStyle = CXXNewExpr::CallInit; |
| } else if (Initializer && isa<InitListExpr>(Initializer)) |
| initStyle = CXXNewExpr::ListInit; |
| else { |
| assert((!Initializer || isa<ImplicitValueInitExpr>(Initializer) || |
| isa<CXXConstructExpr>(Initializer)) && |
| "Initializer expression that cannot have been implicitly created."); |
| initStyle = CXXNewExpr::NoInit; |
| } |
| |
| Expr **Inits = &Initializer; |
| unsigned NumInits = Initializer ? 1 : 0; |
| if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) { |
| assert(initStyle == CXXNewExpr::CallInit && "paren init for non-call init"); |
| Inits = List->getExprs(); |
| NumInits = List->getNumExprs(); |
| } |
| |
| // Determine whether we've already built the initializer. |
| bool HaveCompleteInit = false; |
| if (Initializer && isa<CXXConstructExpr>(Initializer) && |
| !isa<CXXTemporaryObjectExpr>(Initializer)) |
| HaveCompleteInit = true; |
| else if (Initializer && isa<ImplicitValueInitExpr>(Initializer)) |
| HaveCompleteInit = true; |
| |
| // C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for. |
| if (TypeMayContainAuto && AllocType->isUndeducedType()) { |
| if (initStyle == CXXNewExpr::NoInit || NumInits == 0) |
| return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) |
| << AllocType << TypeRange); |
| if (initStyle == CXXNewExpr::ListInit || |
| (NumInits == 1 && isa<InitListExpr>(Inits[0]))) |
| return ExprError(Diag(Inits[0]->getLocStart(), |
| diag::err_auto_new_list_init) |
| << AllocType << TypeRange); |
| if (NumInits > 1) { |
| Expr *FirstBad = Inits[1]; |
| return ExprError(Diag(FirstBad->getLocStart(), |
| diag::err_auto_new_ctor_multiple_expressions) |
| << AllocType << TypeRange); |
| } |
| Expr *Deduce = Inits[0]; |
| QualType DeducedType; |
| if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) |
| return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) |
| << AllocType << Deduce->getType() |
| << TypeRange << Deduce->getSourceRange()); |
| if (DeducedType.isNull()) |
| return ExprError(); |
| AllocType = DeducedType; |
| } |
| |
| // Per C++0x [expr.new]p5, the type being constructed may be a |
| // typedef of an array type. |
| if (!ArraySize) { |
| if (const ConstantArrayType *Array |
| = Context.getAsConstantArrayType(AllocType)) { |
| ArraySize = IntegerLiteral::Create(Context, Array->getSize(), |
| Context.getSizeType(), |
| TypeRange.getEnd()); |
| AllocType = Array->getElementType(); |
| } |
| } |
| |
| if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange)) |
| return ExprError(); |
| |
| if (initStyle == CXXNewExpr::ListInit && isStdInitializerList(AllocType, 0)) { |
| Diag(AllocTypeInfo->getTypeLoc().getBeginLoc(), |
| diag::warn_dangling_std_initializer_list) |
| << /*at end of FE*/0 << Inits[0]->getSourceRange(); |
| } |
| |
| // In ARC, infer 'retaining' for the allocated |
| if (getLangOpts().ObjCAutoRefCount && |
| AllocType.getObjCLifetime() == Qualifiers::OCL_None && |
| AllocType->isObjCLifetimeType()) { |
| AllocType = Context.getLifetimeQualifiedType(AllocType, |
| AllocType->getObjCARCImplicitLifetime()); |
| } |
| |
| QualType ResultType = Context.getPointerType(AllocType); |
| |
| if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) { |
| ExprResult result = CheckPlaceholderExpr(ArraySize); |
| if (result.isInvalid()) return ExprError(); |
| ArraySize = result.take(); |
| } |
| // C++98 5.3.4p6: "The expression in a direct-new-declarator shall have |
| // integral or enumeration type with a non-negative value." |
| // C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped |
| // enumeration type, or a class type for which a single non-explicit |
| // conversion function to integral or unscoped enumeration type exists. |
| // C++1y [expr.new]p6: The expression [...] is implicitly converted to |
| // std::size_t. |
| if (ArraySize && !ArraySize->isTypeDependent()) { |
| ExprResult ConvertedSize; |
| if (getLangOpts().CPlusPlus1y) { |
| assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?"); |
| |
| ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(), |
| AA_Converting); |
| |
| if (!ConvertedSize.isInvalid() && |
| ArraySize->getType()->getAs<RecordType>()) |
| // Diagnose the compatibility of this conversion. |
| Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion) |
| << ArraySize->getType() << 0 << "'size_t'"; |
| } else { |
| class SizeConvertDiagnoser : public ICEConvertDiagnoser { |
| protected: |
| Expr *ArraySize; |
| |
| public: |
| SizeConvertDiagnoser(Expr *ArraySize) |
| : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, false, false), |
| ArraySize(ArraySize) {} |
| |
| SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, |
| QualType T) override { |
| return S.Diag(Loc, diag::err_array_size_not_integral) |
| << S.getLangOpts().CPlusPlus11 << T; |
| } |
| |
| SemaDiagnosticBuilder diagnoseIncomplete( |
| Sema &S, SourceLocation Loc, QualType T) override { |
| return S.Diag(Loc, diag::err_array_size_incomplete_type) |
| << T << ArraySize->getSourceRange(); |
| } |
| |
| SemaDiagnosticBuilder diagnoseExplicitConv( |
| Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { |
| return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy; |
| } |
| |
| SemaDiagnosticBuilder noteExplicitConv( |
| Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { |
| return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) |
| << ConvTy->isEnumeralType() << ConvTy; |
| } |
| |
| SemaDiagnosticBuilder diagnoseAmbiguous( |
| Sema &S, SourceLocation Loc, QualType T) override { |
| return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T; |
| } |
| |
| SemaDiagnosticBuilder noteAmbiguous( |
| Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { |
| return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) |
| << ConvTy->isEnumeralType() << ConvTy; |
| } |
| |
| virtual SemaDiagnosticBuilder diagnoseConversion( |
| Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { |
| return S.Diag(Loc, |
| S.getLangOpts().CPlusPlus11 |
| ? diag::warn_cxx98_compat_array_size_conversion |
| : diag::ext_array_size_conversion) |
| << T << ConvTy->isEnumeralType() << ConvTy; |
| } |
| } SizeDiagnoser(ArraySize); |
| |
| ConvertedSize = PerformContextualImplicitConversion(StartLoc, ArraySize, |
| SizeDiagnoser); |
| } |
| if (ConvertedSize.isInvalid()) |
| return ExprError(); |
| |
| ArraySize = ConvertedSize.take(); |
| QualType SizeType = ArraySize->getType(); |
| |
| if (!SizeType->isIntegralOrUnscopedEnumerationType()) |
| return ExprError(); |
| |
| // C++98 [expr.new]p7: |
| // The expression in a direct-new-declarator shall have integral type |
| // with a non-negative value. |
| // |
| // Let's see if this is a constant < 0. If so, we reject it out of |
| // hand. Otherwise, if it's not a constant, we must have an unparenthesized |
| // array type. |
| // |
| // Note: such a construct has well-defined semantics in C++11: it throws |
| // std::bad_array_new_length. |
| if (!ArraySize->isValueDependent()) { |
| llvm::APSInt Value; |
| // We've already performed any required implicit conversion to integer or |
| // unscoped enumeration type. |
| if (ArraySize->isIntegerConstantExpr(Value, Context)) { |
| if (Value < llvm::APSInt( |
| llvm::APInt::getNullValue(Value.getBitWidth()), |
| Value.isUnsigned())) { |
| if (getLangOpts().CPlusPlus11) |
| Diag(ArraySize->getLocStart(), |
| diag::warn_typecheck_negative_array_new_size) |
| << ArraySize->getSourceRange(); |
| else |
| return ExprError(Diag(ArraySize->getLocStart(), |
| diag::err_typecheck_negative_array_size) |
| << ArraySize->getSourceRange()); |
| } else if (!AllocType->isDependentType()) { |
| unsigned ActiveSizeBits = |
| ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); |
| if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { |
| if (getLangOpts().CPlusPlus11) |
| Diag(ArraySize->getLocStart(), |
| diag::warn_array_new_too_large) |
| << Value.toString(10) |
| << ArraySize->getSourceRange(); |
| else |
| return ExprError(Diag(ArraySize->getLocStart(), |
| diag::err_array_too_large) |
| << Value.toString(10) |
| << ArraySize->getSourceRange()); |
| } |
| } |
| } else if (TypeIdParens.isValid()) { |
| // Can't have dynamic array size when the type-id is in parentheses. |
| Diag(ArraySize->getLocStart(), diag::ext_new_paren_array_nonconst) |
| << ArraySize->getSourceRange() |
| << FixItHint::CreateRemoval(TypeIdParens.getBegin()) |
| << FixItHint::CreateRemoval(TypeIdParens.getEnd()); |
| |
| TypeIdParens = SourceRange(); |
| } |
| } |
| |
| // Note that we do *not* convert the argument in any way. It can |
| // be signed, larger than size_t, whatever. |
| } |
| |
| FunctionDecl *OperatorNew = 0; |
| FunctionDecl *OperatorDelete = 0; |
| |
| if (!AllocType->isDependentType() && |
| !Expr::hasAnyTypeDependentArguments(PlacementArgs) && |
| FindAllocationFunctions(StartLoc, |
| SourceRange(PlacementLParen, PlacementRParen), |
| UseGlobal, AllocType, ArraySize, PlacementArgs, |
| 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); |
| |
| SmallVector<Expr *, 8> AllPlaceArgs; |
| if (OperatorNew) { |
| // Add default arguments, if any. |
| const FunctionProtoType *Proto = |
| OperatorNew->getType()->getAs<FunctionProtoType>(); |
| VariadicCallType CallType = |
| Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; |
| |
| if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, 1, |
| PlacementArgs, AllPlaceArgs, CallType)) |
| return ExprError(); |
| |
| if (!AllPlaceArgs.empty()) |
| PlacementArgs = AllPlaceArgs; |
| |
| DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs); |
| |
| // FIXME: Missing call to CheckFunctionCall or equivalent |
| } |
| |
| // Warn if the type is over-aligned and is being allocated by global operator |
| // new. |
| if (PlacementArgs.empty() && OperatorNew && |
| (OperatorNew->isImplicit() || |
| getSourceManager().isInSystemHeader(OperatorNew->getLocStart()))) { |
| if (unsigned Align = Context.getPreferredTypeAlign(AllocType.getTypePtr())){ |
| unsigned SuitableAlign = Context.getTargetInfo().getSuitableAlign(); |
| if (Align > SuitableAlign) |
| Diag(StartLoc, diag::warn_overaligned_type) |
| << AllocType |
| << unsigned(Align / Context.getCharWidth()) |
| << unsigned(SuitableAlign / Context.getCharWidth()); |
| } |
| } |
| |
| QualType InitType = AllocType; |
| // Array 'new' can't have any initializers except empty parentheses. |
| // Initializer lists are also allowed, in C++11. Rely on the parser for the |
| // dialect distinction. |
| if (ResultType->isArrayType() || ArraySize) { |
| if (!isLegalArrayNewInitializer(initStyle, Initializer)) { |
| SourceRange InitRange(Inits[0]->getLocStart(), |
| Inits[NumInits - 1]->getLocEnd()); |
| Diag(StartLoc, diag::err_new_array_init_args) << InitRange; |
| return ExprError(); |
| } |
| if (InitListExpr *ILE = dyn_cast_or_null<InitListExpr>(Initializer)) { |
| // We do the initialization typechecking against the array type |
| // corresponding to the number of initializers + 1 (to also check |
| // default-initialization). |
| unsigned NumElements = ILE->getNumInits() + 1; |
| InitType = Context.getConstantArrayType(AllocType, |
| llvm::APInt(Context.getTypeSize(Context.getSizeType()), NumElements), |
| ArrayType::Normal, 0); |
| } |
| } |
| |
| // If we can perform the initialization, and we've not already done so, |
| // do it now. |
| if (!AllocType->isDependentType() && |
| !Expr::hasAnyTypeDependentArguments( |
| llvm::makeArrayRef(Inits, NumInits)) && |
| !HaveCompleteInit) { |
| // C++11 [expr.new]p15: |
| // A new-expression that creates an object of type T initializes that |
| // object as follows: |
| InitializationKind Kind |
| // - If the new-initializer is omitted, the object is default- |
| // initialized (8.5); if no initialization is performed, |
| // the object has indeterminate value |
| = initStyle == CXXNewExpr::NoInit |
| ? InitializationKind::CreateDefault(TypeRange.getBegin()) |
| // - Otherwise, the new-initializer is interpreted according to the |
| // initialization rules of 8.5 for direct-initialization. |
| : initStyle == CXXNewExpr::ListInit |
| ? InitializationKind::CreateDirectList(TypeRange.getBegin()) |
| : InitializationKind::CreateDirect(TypeRange.getBegin(), |
| DirectInitRange.getBegin(), |
| DirectInitRange.getEnd()); |
| |
| InitializedEntity Entity |
| = InitializedEntity::InitializeNew(StartLoc, InitType); |
| InitializationSequence InitSeq(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); |
| ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, |
| MultiExprArg(Inits, NumInits)); |
| if (FullInit.isInvalid()) |
| return ExprError(); |
| |
| // FullInit is our initializer; strip off CXXBindTemporaryExprs, because |
| // we don't want the initialized object to be destructed. |
| if (CXXBindTemporaryExpr *Binder = |
| dyn_cast_or_null<CXXBindTemporaryExpr>(FullInit.get())) |
| FullInit = Owned(Binder->getSubExpr()); |
| |
| Initializer = FullInit.take(); |
| } |
| |
| // Mark the new and delete operators as referenced. |
| if (OperatorNew) { |
| if (DiagnoseUseOfDecl(OperatorNew, StartLoc)) |
| return ExprError(); |
| MarkFunctionReferenced(StartLoc, OperatorNew); |
| } |
| if (OperatorDelete) { |
| if (DiagnoseUseOfDecl(OperatorDelete, StartLoc)) |
| return ExprError(); |
| MarkFunctionReferenced(StartLoc, OperatorDelete); |
| } |
| |
| // C++0x [expr.new]p17: |
| // If the new expression creates an array of objects of class type, |
| // access and ambiguity control are done for the destructor. |
| QualType BaseAllocType = Context.getBaseElementType(AllocType); |
| if (ArraySize && !BaseAllocType->isDependentType()) { |
| if (const RecordType *BaseRecordType = BaseAllocType->getAs<RecordType>()) { |
| if (CXXDestructorDecl *dtor = LookupDestructor( |
| cast<CXXRecordDecl>(BaseRecordType->getDecl()))) { |
| MarkFunctionReferenced(StartLoc, dtor); |
| CheckDestructorAccess(StartLoc, dtor, |
| PDiag(diag::err_access_dtor) |
| << BaseAllocType); |
| if (DiagnoseUseOfDecl(dtor, StartLoc)) |
| return ExprError(); |
| } |
| } |
| } |
| |
| return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, |
| OperatorDelete, |
| UsualArrayDeleteWantsSize, |
| PlacementArgs, TypeIdParens, |
| ArraySize, initStyle, Initializer, |
| ResultType, AllocTypeInfo, |
| Range, DirectInitRange)); |
| } |
| |
| /// \brief Checks that a type is suitable as the allocated type |
| /// in a new-expression. |
| bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, |
| SourceRange R) { |
| // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an |
| // abstract class type or array thereof. |
| if (AllocType->isFunctionType()) |
| return Diag(Loc, diag::err_bad_new_type) |
| << AllocType << 0 << R; |
| else if (AllocType->isReferenceType()) |
| return Diag(Loc, diag::err_bad_new_type) |
| << AllocType << 1 << R; |
| else if (!AllocType->isDependentType() && |
| RequireCompleteType(Loc, AllocType, diag::err_new_incomplete_type,R)) |
| return true; |
| 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; |
| else if (unsigned AddressSpace = AllocType.getAddressSpace()) |
| return Diag(Loc, diag::err_address_space_qualified_new) |
| << AllocType.getUnqualifiedType() << AddressSpace; |
| else if (getLangOpts().ObjCAutoRefCount) { |
| if (const ArrayType *AT = Context.getAsArrayType(AllocType)) { |
| QualType BaseAllocType = Context.getBaseElementType(AT); |
| if (BaseAllocType.getObjCLifetime() == Qualifiers::OCL_None && |
| BaseAllocType->isObjCLifetimeType()) |
| return Diag(Loc, diag::err_arc_new_array_without_ownership) |
| << BaseAllocType; |
| } |
| } |
| |
| return false; |
| } |
| |
| /// \brief Determine whether the given function is a non-placement |
| /// deallocation function. |
| static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) { |
| if (FD->isInvalidDecl()) |
| return false; |
| |
| if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) |
| return Method->isUsualDeallocationFunction(); |
| |
| if (FD->getOverloadedOperator() != OO_Delete && |
| FD->getOverloadedOperator() != OO_Array_Delete) |
| return false; |
| |
| if (FD->getNumParams() == 1) |
| return true; |
| |
| return S.getLangOpts().SizedDeallocation && FD->getNumParams() == 2 && |
| S.Context.hasSameUnqualifiedType(FD->getParamDecl(1)->getType(), |
| S.Context.getSizeType()); |
| } |
| |
| /// FindAllocationFunctions - Finds the overloads of operator new and delete |
| /// that are appropriate for the allocation. |
| bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, |
| bool UseGlobal, QualType AllocType, |
| bool IsArray, MultiExprArg PlaceArgs, |
| FunctionDecl *&OperatorNew, |
| FunctionDecl *&OperatorDelete) { |
| // --- Choosing an allocation function --- |
| // C++ 5.3.4p8 - 14 & 18 |
| // 1) If UseGlobal is true, only look in the global scope. Else, also look |
| // in the scope of the allocated class. |
| // 2) If an array size is given, look for operator new[], else look for |
| // operator new. |
| // 3) The first argument is always size_t. Append the arguments from the |
| // placement form. |
| |
| SmallVector<Expr*, 8> AllocArgs(1 + PlaceArgs.size()); |
| // We don't care about the actual value of this argument. |
| // FIXME: Should the Sema create the expression and embed it in the syntax |
| // tree? Or should the consumer just recalculate the value? |
| IntegerLiteral Size(Context, llvm::APInt::getNullValue( |
| Context.getTargetInfo().getPointerWidth(0)), |
| Context.getSizeType(), |
| SourceLocation()); |
| AllocArgs[0] = &Size; |
| std::copy(PlaceArgs.begin(), PlaceArgs.end(), AllocArgs.begin() + 1); |
| |
| // 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 |
| // 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[]. |
| DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( |
| IsArray ? OO_Array_New : OO_New); |
| DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( |
| IsArray ? OO_Array_Delete : OO_Delete); |
| |
| QualType AllocElemType = Context.getBaseElementType(AllocType); |
| |
| if (AllocElemType->isRecordType() && !UseGlobal) { |
| CXXRecordDecl *Record |
| = cast<CXXRecordDecl>(AllocElemType->getAs<RecordType>()->getDecl()); |
| if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, Record, |
| /*AllowMissing=*/true, OperatorNew)) |
| return true; |
| } |
| |
| if (!OperatorNew) { |
| // Didn't find a member overload. Look for a global one. |
| DeclareGlobalNewDelete(); |
| DeclContext *TUDecl = Context.getTranslationUnitDecl(); |
| bool FallbackEnabled = IsArray && Context.getLangOpts().MSVCCompat; |
| if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl, |
| /*AllowMissing=*/FallbackEnabled, OperatorNew, |
| /*Diagnose=*/!FallbackEnabled)) { |
| if (!FallbackEnabled) |
| return true; |
| |
| // MSVC will fall back on trying to find a matching global operator new |
| // if operator new[] cannot be found. Also, MSVC will leak by not |
| // generating a call to operator delete or operator delete[], but we |
| // will not replicate that bug. |
| NewName = Context.DeclarationNames.getCXXOperatorName(OO_New); |
| DeleteName = Context.DeclarationNames.getCXXOperatorName(OO_Delete); |
| if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl, |
| /*AllowMissing=*/false, OperatorNew)) |
| return true; |
| } |
| } |
| |
| // We don't need an operator delete if we're running under |
| // -fno-exceptions. |
| if (!getLangOpts().Exceptions) { |
| OperatorDelete = 0; |
| return false; |
| } |
| |
| // FindAllocationOverload can change the passed in arguments, so we need to |
| // copy them back. |
| if (!PlaceArgs.empty()) |
| std::copy(AllocArgs.begin() + 1, AllocArgs.end(), PlaceArgs.data()); |
| |
| // C++ [expr.new]p19: |
| // |
| // If the new-expression begins with a unary :: operator, the |
| // 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 |
| // 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. |
| LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); |
| if (AllocElemType->isRecordType() && !UseGlobal) { |
| CXXRecordDecl *RD |
| = cast<CXXRecordDecl>(AllocElemType->getAs<RecordType>()->getDecl()); |
| LookupQualifiedName(FoundDelete, RD); |
| } |
| if (FoundDelete.isAmbiguous()) |
| return true; // FIXME: clean up expressions? |
| |
| if (FoundDelete.empty()) { |
| DeclareGlobalNewDelete(); |
| LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); |
| } |
| |
| FoundDelete.suppressDiagnostics(); |
| |
| SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches; |
| |
| // 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 = (!PlaceArgs.empty() || 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>(); |
| |
| SmallVector<QualType, 4> ArgTypes; |
| ArgTypes.push_back(Context.VoidPtrTy); |
| for (unsigned I = 1, N = Proto->getNumParams(); I < N; ++I) |
| ArgTypes.push_back(Proto->getParamType(I)); |
| |
| FunctionProtoType::ExtProtoInfo EPI; |
| EPI.Variadic = Proto->isVariadic(); |
| |
| ExpectedFunctionType |
| = Context.getFunctionType(Context.VoidTy, ArgTypes, EPI); |
| } |
| |
| for (LookupResult::iterator D = FoundDelete.begin(), |
| DEnd = FoundDelete.end(); |
| D != DEnd; ++D) { |
| FunctionDecl *Fn = 0; |
| if (FunctionTemplateDecl *FnTmpl |
| = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { |
| // Perform template argument deduction to try to match the |
| // expected function type. |
| TemplateDeductionInfo Info(StartLoc); |
| if (DeduceTemplateArguments(FnTmpl, 0, ExpectedFunctionType, Fn, Info)) |
| continue; |
| } else |
| Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl()); |
| |
| if (Context.hasSameType(Fn->getType(), ExpectedFunctionType)) |
| Matches.push_back(std::make_pair(D.getPair(), Fn)); |
| } |
| } else { |
| // C++ [expr.new]p20: |
| // [...] Any non-placement deallocation function matches a |
| // non-placement allocation function. [...] |
| for (LookupResult::iterator D = FoundDelete.begin(), |
| DEnd = FoundDelete.end(); |
| D != DEnd; ++D) { |
| if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl())) |
| if (isNonPlacementDeallocationFunction(*this, Fn)) |
| Matches.push_back(std::make_pair(D.getPair(), Fn)); |
| } |
| |
| // C++1y [expr.new]p22: |
| // For a non-placement allocation function, the normal deallocation |
| // function lookup is used |
| // C++1y [expr.delete]p?: |
| // If [...] deallocation function lookup finds both a usual deallocation |
| // function with only a pointer parameter and a usual deallocation |
| // function with both a pointer parameter and a size parameter, then the |
| // selected deallocation function shall be the one with two parameters. |
| // Otherwise, the selected deallocation function shall be the function |
| // with one parameter. |
| if (getLangOpts().SizedDeallocation && Matches.size() == 2) { |
| if (Matches[0].second->getNumParams() == 1) |
| Matches.erase(Matches.begin()); |
| else |
| Matches.erase(Matches.begin() + 1); |
| assert(Matches[0].second->getNumParams() == 2 && |
| "found an unexpected usual deallocation function"); |
| } |
| } |
| |
| // C++ [expr.new]p20: |
| // [...] If the lookup finds a single matching deallocation |
| // function, that function will be called; otherwise, no |
| // deallocation function will be called. |
| if (Matches.size() == 1) { |
| OperatorDelete = Matches[0].second; |
| |
| // C++0x [expr.new]p20: |
| // If the lookup finds the two-parameter form of a usual |
| // deallocation function (3.7.4.2) and that function, considered |
| // as a placement deallocation function, would have been |
| // selected as a match for the allocation function, the program |
| // is ill-formed. |
| if (!PlaceArgs.empty() && getLangOpts().CPlusPlus11 && |
| isNonPlacementDeallocationFunction(*this, OperatorDelete)) { |
| Diag(StartLoc, diag::err_placement_new_non_placement_delete) |
| << SourceRange(PlaceArgs.front()->getLocStart(), |
| PlaceArgs.back()->getLocEnd()); |
| if (!OperatorDelete->isImplicit()) |
| Diag(OperatorDelete->getLocation(), diag::note_previous_decl) |
| << DeleteName; |
| } else { |
| CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(), |
| Matches[0].first); |
| } |
| } |
| |
| return false; |
| } |
| |
| /// FindAllocationOverload - Find an fitting overload for the allocation |
| /// function in the specified scope. |
| bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, |
| DeclarationName Name, MultiExprArg Args, |
| DeclContext *Ctx, |
| bool AllowMissing, FunctionDecl *&Operator, |
| bool Diagnose) { |
| LookupResult R(*this, Name, StartLoc, LookupOrdinaryName); |
| LookupQualifiedName(R, Ctx); |
| if (R.empty()) { |
| if (AllowMissing || !Diagnose) |
| return false; |
| return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) |
| << Name << Range; |
| } |
| |
| if (R.isAmbiguous()) |
| return true; |
| |
| R.suppressDiagnostics(); |
| |
| OverloadCandidateSet Candidates(StartLoc, OverloadCandidateSet::CSK_Normal); |
| 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. |
| NamedDecl *D = (*Alloc)->getUnderlyingDecl(); |
| |
| if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) { |
| AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), |
| /*ExplicitTemplateArgs=*/0, |
| Args, Candidates, |
| /*SuppressUserConversions=*/false); |
| continue; |
| } |
| |
| FunctionDecl *Fn = cast<FunctionDecl>(D); |
| AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates, |
| /*SuppressUserConversions=*/false); |
| } |
| |
| // Do the resolution. |
| OverloadCandidateSet::iterator Best; |
| switch (Candidates.BestViableFunction(*this, StartLoc, Best)) { |
| case OR_Success: { |
| // Got one! |
| FunctionDecl *FnDecl = Best->Function; |
| MarkFunctionReferenced(StartLoc, FnDecl); |
| // The first argument is size_t, and the first parameter must be size_t, |
| // too. This is checked on declaration and can be assumed. (It can't be |
| // asserted on, though, since invalid decls are left in there.) |
| // Watch out for variadic allocator function. |
| unsigned NumArgsInFnDecl = FnDecl->getNumParams(); |
| for (unsigned i = 0; (i < Args.size() && i < NumArgsInFnDecl); ++i) { |
| InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, |
| FnDecl->getParamDecl(i)); |
| |
| if (!Diagnose && !CanPerformCopyInitialization(Entity, Owned(Args[i]))) |
| return true; |
| |
| ExprResult Result |
| = PerformCopyInitialization(Entity, SourceLocation(), Owned(Args[i])); |
| if (Result.isInvalid()) |
| return true; |
| |
| Args[i] = Result.takeAs<Expr>(); |
| } |
| |
| Operator = FnDecl; |
| |
| if (CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), |
| Best->FoundDecl, Diagnose) == AR_inaccessible) |
| return true; |
| |
| return false; |
| } |
| |
| case OR_No_Viable_Function: |
| if (Diagnose) { |
| Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) |
| << Name << Range; |
| Candidates.NoteCandidates(*this, OCD_AllCandidates, Args); |
| } |
| return true; |
| |
| case OR_Ambiguous: |
| if (Diagnose) { |
| Diag(StartLoc, diag::err_ovl_ambiguous_call) |
| << Name << Range; |
| Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args); |
| } |
| return true; |
| |
| case OR_Deleted: { |
| if (Diagnose) { |
| Diag(StartLoc, diag::err_ovl_deleted_call) |
| << Best->Function->isDeleted() |
| << Name |
| << getDeletedOrUnavailableSuffix(Best->Function) |
| << Range; |
| Candidates.NoteCandidates(*this, OCD_AllCandidates, Args); |
| } |
| return true; |
| } |
| } |
| llvm_unreachable("Unreachable, bad result from BestViableFunction"); |
| } |
| |
| |
| /// DeclareGlobalNewDelete - Declare the global forms of operator new and |
| /// delete. These are: |
| /// @code |
| /// // C++03: |
| /// void* operator new(std::size_t) throw(std::bad_alloc); |
| /// void* operator new[](std::size_t) throw(std::bad_alloc); |
| /// void operator delete(void *) throw(); |
| /// void operator delete[](void *) throw(); |
| /// // C++11: |
| /// void* operator new(std::size_t); |
| /// void* operator new[](std::size_t); |
| /// void operator delete(void *) noexcept; |
| /// void operator delete[](void *) noexcept; |
| /// // C++1y: |
| /// void* operator new(std::size_t); |
| /// void* operator new[](std::size_t); |
| /// void operator delete(void *) noexcept; |
| /// void operator delete[](void *) noexcept; |
| /// void operator delete(void *, std::size_t) noexcept; |
| /// void operator delete[](void *, std::size_t) noexcept; |
| /// @endcode |
| /// Note that the placement and nothrow forms of new are *not* implicitly |
| /// declared. Their use requires including \<new\>. |
| void Sema::DeclareGlobalNewDelete() { |
| if (GlobalNewDeleteDeclared) |
| return; |
| |
| // C++ [basic.std.dynamic]p2: |
| // [...] The following allocation and deallocation functions (18.4) are |
| // implicitly declared in global scope in each translation unit of a |
| // program |
| // |
| // C++03: |
| // void* operator new(std::size_t) throw(std::bad_alloc); |
| // void* operator new[](std::size_t) throw(std::bad_alloc); |
| // void operator delete(void*) throw(); |
| // void operator delete[](void*) throw(); |
| // C++11: |
| // void* operator new(std::size_t); |
| // void* operator new[](std::size_t); |
| // void operator delete(void*) noexcept; |
| // void operator delete[](void*) noexcept; |
| // C++1y: |
| // void* operator new(std::size_t); |
| // void* operator new[](std::size_t); |
| // void operator delete(void*) noexcept; |
| // void operator delete[](void*) noexcept; |
| // void operator delete(void*, std::size_t) noexcept; |
| // void operator delete[](void*, std::size_t) noexcept; |
| // |
| // These implicit declarations introduce only the function names operator |
| // new, operator new[], operator delete, operator delete[]. |
| // |
| // Here, we need to refer to std::bad_alloc, so we will implicitly declare |
| // "std" or "bad_alloc" as necessary to form the exception specification. |
| // However, we do not make these implicit declarations visible to name |
| // lookup. |
| if (!StdBadAlloc && !getLangOpts().CPlusPlus11) { |
| // The "std::bad_alloc" class has not yet been declared, so build it |
| // implicitly. |
| StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, |
| getOrCreateStdNamespace(), |
| SourceLocation(), SourceLocation(), |
| &PP.getIdentifierTable().get("bad_alloc"), |
| 0); |
| getStdBadAlloc()->setImplicit(true); |
| } |
| |
| GlobalNewDeleteDeclared = true; |
| |
| QualType VoidPtr = Context.getPointerType(Context.VoidTy); |
| QualType SizeT = Context.getSizeType(); |
| bool AssumeSaneOperatorNew = getLangOpts().AssumeSaneOperatorNew; |
| |
| DeclareGlobalAllocationFunction( |
| Context.DeclarationNames.getCXXOperatorName(OO_New), |
| VoidPtr, SizeT, QualType(), AssumeSaneOperatorNew); |
| DeclareGlobalAllocationFunction( |
| Context.DeclarationNames.getCXXOperatorName(OO_Array_New), |
| VoidPtr, SizeT, QualType(), AssumeSaneOperatorNew); |
| DeclareGlobalAllocationFunction( |
| Context.DeclarationNames.getCXXOperatorName(OO_Delete), |
| Context.VoidTy, VoidPtr); |
| DeclareGlobalAllocationFunction( |
| Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete), |
| Context.VoidTy, VoidPtr); |
| if (getLangOpts().SizedDeallocation) { |
| DeclareGlobalAllocationFunction( |
| Context.DeclarationNames.getCXXOperatorName(OO_Delete), |
| Context.VoidTy, VoidPtr, Context.getSizeType()); |
| DeclareGlobalAllocationFunction( |
| Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete), |
| Context.VoidTy, VoidPtr, Context.getSizeType()); |
| } |
| } |
| |
| /// DeclareGlobalAllocationFunction - Declares a single implicit global |
| /// allocation function if it doesn't already exist. |
| void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, |
| QualType Return, |
| QualType Param1, QualType Param2, |
| bool AddMallocAttr) { |
| DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); |
| unsigned NumParams = Param2.isNull() ? 1 : 2; |
| |
| // Check if this function is already declared. |
| DeclContext::lookup_result R = GlobalCtx->lookup(Name); |
| for (DeclContext::lookup_iterator Alloc = R.begin(), AllocEnd = R.end(); |
| Alloc != AllocEnd; ++Alloc) { |
| // Only look at non-template functions, as it is the predefined, |
| // non-templated allocation function we are trying to declare here. |
| if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*Alloc)) { |
| if (Func->getNumParams() == NumParams) { |
| QualType InitialParam1Type = |
| Context.getCanonicalType(Func->getParamDecl(0) |
| ->getType().getUnqualifiedType()); |
| QualType InitialParam2Type = |
| NumParams == 2 |
| ? Context.getCanonicalType(Func->getParamDecl(1) |
| ->getType().getUnqualifiedType()) |
| : QualType(); |
| // FIXME: Do we need to check for default arguments here? |
| if (InitialParam1Type == Param1 && |
| (NumParams == 1 || InitialParam2Type == Param2)) { |
| if (AddMallocAttr && !Func->hasAttr<MallocAttr>()) |
| Func->addAttr(MallocAttr::CreateImplicit(Context)); |
| // Make the function visible to name lookup, even if we found it in |
| // an unimported module. It either is an implicitly-declared global |
| // allocation function, or is suppressing that function. |
| Func->setHidden(false); |
| return; |
| } |
| } |
| } |
| } |
| |
| FunctionProtoType::ExtProtoInfo EPI; |
| |
| QualType BadAllocType; |
| bool HasBadAllocExceptionSpec |
| = (Name.getCXXOverloadedOperator() == OO_New || |
| Name.getCXXOverloadedOperator() == OO_Array_New); |
| if (HasBadAllocExceptionSpec) { |
| if (!getLangOpts().CPlusPlus11) { |
| BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); |
| assert(StdBadAlloc && "Must have std::bad_alloc declared"); |
| EPI.ExceptionSpecType = EST_Dynamic; |
| EPI.NumExceptions = 1; |
| EPI.Exceptions = &BadAllocType; |
| } |
| } else { |
| EPI.ExceptionSpecType = getLangOpts().CPlusPlus11 ? |
| EST_BasicNoexcept : EST_DynamicNone; |
| } |
| |
| QualType Params[] = { Param1, Param2 }; |
| |
| QualType FnType = Context.getFunctionType( |
| Return, ArrayRef<QualType>(Params, NumParams), EPI); |
| FunctionDecl *Alloc = |
| FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), |
| SourceLocation(), Name, |
| FnType, /*TInfo=*/0, SC_None, false, true); |
| Alloc->setImplicit(); |
| |
| if (AddMallocAttr) |
| Alloc->addAttr(MallocAttr::CreateImplicit(Context)); |
| |
| ParmVarDecl *ParamDecls[2]; |
| for (unsigned I = 0; I != NumParams; ++I) { |
| ParamDecls[I] = ParmVarDecl::Create(Context, Alloc, SourceLocation(), |
| SourceLocation(), 0, |
| Params[I], /*TInfo=*/0, |
| SC_None, 0); |
| ParamDecls[I]->setImplicit(); |
| } |
| Alloc->setParams(ArrayRef<ParmVarDecl*>(ParamDecls, NumParams)); |
| |
| // FIXME: Also add this declaration to the IdentifierResolver, but |
| // make sure it is at the end of the chain to coincide with the |
| // global scope. |
| Context.getTranslationUnitDecl()->addDecl(Alloc); |
| } |
| |
| FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc, |
| bool CanProvideSize, |
| DeclarationName Name) { |
| DeclareGlobalNewDelete(); |
| |
| LookupResult FoundDelete(*this, Name, StartLoc, LookupOrdinaryName); |
| LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); |
| |
| // C++ [expr.new]p20: |
| // [...] Any non-placement deallocation function matches a |
| // non-placement allocation function. [...] |
| llvm::SmallVector<FunctionDecl*, 2> Matches; |
| for (LookupResult::iterator D = FoundDelete.begin(), |
| DEnd = FoundDelete.end(); |
| D != DEnd; ++D) { |
| if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*D)) |
| if (isNonPlacementDeallocationFunction(*this, Fn)) |
| Matches.push_back(Fn); |
| } |
| |
| // C++1y [expr.delete]p?: |
| // If the type is complete and deallocation function lookup finds both a |
| // usual deallocation function with only a pointer parameter and a usual |
| // deallocation function with both a pointer parameter and a size |
| // parameter, then the selected deallocation function shall be the one |
| // with two parameters. Otherwise, the selected deallocation function |
| // shall be the function with one parameter. |
| if (getLangOpts().SizedDeallocation && Matches.size() == 2) { |
| unsigned NumArgs = CanProvideSize ? 2 : 1; |
| if (Matches[0]->getNumParams() != NumArgs) |
| Matches.erase(Matches.begin()); |
| else |
| Matches.erase(Matches.begin() + 1); |
| assert(Matches[0]->getNumParams() == NumArgs && |
| "found an unexpected usual deallocation function"); |
| } |
| |
| assert(Matches.size() == 1 && |
| "unexpectedly have multiple usual deallocation functions"); |
| return Matches.front(); |
| } |
| |
| bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, |
| DeclarationName Name, |
| FunctionDecl* &Operator, bool Diagnose) { |
| LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); |
| // Try to find operator delete/operator delete[] in class scope. |
| LookupQualifiedName(Found, RD); |
| |
| if (Found.isAmbiguous()) |
| return true; |
| |
| Found.suppressDiagnostics(); |
| |
| SmallVector<DeclAccessPair,4> Matches; |
| for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); |
| F != FEnd; ++F) { |
| NamedDecl *ND = (*F)->getUnderlyingDecl(); |
| |
| // Ignore template operator delete members from the check for a usual |
| // deallocation function. |
| if (isa<FunctionTemplateDecl>(ND)) |
| continue; |
| |
| if (cast<CXXMethodDecl>(ND)->isUsualDeallocationFunction()) |
| Matches.push_back(F.getPair()); |
| } |
| |
| // There's exactly one suitable operator; pick it. |
| if (Matches.size() == 1) { |
| Operator = cast<CXXMethodDecl>(Matches[0]->getUnderlyingDecl()); |
| |
| if (Operator->isDeleted()) { |
| if (Diagnose) { |
| Diag(StartLoc, diag::err_deleted_function_use); |
| NoteDeletedFunction(Operator); |
| } |
| return true; |
| } |
| |
| if (CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), |
| Matches[0], Diagnose) == AR_inaccessible) |
| return true; |
| |
| return false; |
| |
| // We found multiple suitable operators; complain about the ambiguity. |
| } else if (!Matches.empty()) { |
| if (Diagnose) { |
| Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) |
| << Name << RD; |
| |
| for (SmallVectorImpl<DeclAccessPair>::iterator |
| F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) |
| Diag((*F)->getUnderlyingDecl()->getLocation(), |
| diag::note_member_declared_here) << Name; |
| } |
| return true; |
| } |
| |
| // We did find operator delete/operator delete[] declarations, but |
| // none of them were suitable. |
| if (!Found.empty()) { |
| if (Diagnose) { |
| 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(), |
| diag::note_member_declared_here) << Name; |
| } |
| return true; |
| } |
| |
| Operator = 0; |
| return false; |
| } |
| |
| /// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: |
| /// @code ::delete ptr; @endcode |
| /// or |
| /// @code delete [] ptr; @endcode |
| ExprResult |
| Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, |
| bool ArrayForm, Expr *ExE) { |
| // C++ [expr.delete]p1: |
| // The operand shall have a pointer type, or a class type having a single |
| // non-explicit conversion function to a pointer type. The result has type |
| // void. |
| // |
| // DR599 amends "pointer type" to "pointer to object type" in both cases. |
| |
| ExprResult Ex = Owned(ExE); |
| FunctionDecl *OperatorDelete = 0; |
| bool ArrayFormAsWritten = ArrayForm; |
| bool UsualArrayDeleteWantsSize = false; |
| |
| if (!Ex.get()->isTypeDependent()) { |
| // Perform lvalue-to-rvalue cast, if needed. |
| Ex = DefaultLvalueConversion(Ex.take()); |
| if (Ex.isInvalid()) |
| return ExprError(); |
| |
| QualType Type = Ex.get()->getType(); |
| |
| class DeleteConverter : public ContextualImplicitConverter { |
| public: |
| DeleteConverter() : ContextualImplicitConverter(false, true) {} |
| |
| bool match(QualType ConvType) override { |
| // FIXME: If we have an operator T* and an operator void*, we must pick |
| // the operator T*. |
| if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) |
| if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType()) |
| return true; |
| return false; |
| } |
| |
| SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, |
| QualType T) override { |
| return S.Diag(Loc, diag::err_delete_operand) << T; |
| } |
| |
| SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, |
| QualType T) override { |
| return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T; |
| } |
| |
| SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, |
| QualType T, |
| QualType ConvTy) override { |
| return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy; |
| } |
| |
| SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, |
| QualType ConvTy) override { |
| return S.Diag(Conv->getLocation(), diag::note_delete_conversion) |
| << ConvTy; |
| } |
| |
| SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, |
| QualType T) override { |
| return S.Diag(Loc, diag::err_ambiguous_delete_operand) << T; |
| } |
| |
| SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, |
| QualType ConvTy) override { |
| return S.Diag(Conv->getLocation(), diag::note_delete_conversion) |
| << ConvTy; |
| } |
| |
| SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, |
| QualType T, |
| QualType ConvTy) override { |
| llvm_unreachable("conversion functions are permitted"); |
| } |
| } Converter; |
| |
| Ex = PerformContextualImplicitConversion(StartLoc, Ex.take(), Converter); |
| if (Ex.isInvalid()) |
| return ExprError(); |
| Type = Ex.get()->getType(); |
| if (!Converter.match(Type)) |
| // FIXME: PerformContextualImplicitConversion should return ExprError |
| // itself in this case. |
| return ExprError(); |
| |
| QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); |
| QualType PointeeElem = Context.getBaseElementType(Pointee); |
| |
| if (unsigned AddressSpace = Pointee.getAddressSpace()) |
| return Diag(Ex.get()->getLocStart(), |
| diag::err_address_space_qualified_delete) |
| << Pointee.getUnqualifiedType() << AddressSpace; |
| |
| CXXRecordDecl *PointeeRD = 0; |
| if (Pointee->isVoidType() && !isSFINAEContext()) { |
| // 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) |
| << Type << Ex.get()->getSourceRange(); |
| } else if (Pointee->isFunctionType() || Pointee->isVoidType()) { |
| return ExprError(Diag(StartLoc, diag::err_delete_operand) |
| << Type << Ex.get()->getSourceRange()); |
| } else if (!Pointee->isDependentType()) { |
| if (!RequireCompleteType(StartLoc, Pointee, |
| diag::warn_delete_incomplete, Ex.get())) { |
| if (const RecordType *RT = PointeeElem->getAs<RecordType>()) |
| PointeeRD = cast<CXXRecordDecl>(RT->getDecl()); |
| } |
| } |
| |
| // C++ [expr.delete]p2: |
| // [Note: a pointer to a const type can be the operand of a |
| // delete-expression; it is not necessary to cast away the constness |
| // (5.2.11) of the pointer expression before it is used as the operand |
| // of the delete-expression. ] |
| |
| if (Pointee->isArrayType() && !ArrayForm) { |
| Diag(StartLoc, diag::warn_delete_array_type) |
| << Type << Ex.get()->getSourceRange() |
| << FixItHint::CreateInsertion(PP.getLocForEndOfToken(StartLoc), "[]"); |
| ArrayForm = true; |
| } |
| |
| DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( |
| ArrayForm ? OO_Array_Delete : OO_Delete); |
| |
| if (PointeeRD) { |
| if (!UseGlobal && |
| FindDeallocationFunction(StartLoc, PointeeRD, 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 (OperatorDelete && isa<CXXMethodDecl>(OperatorDelete)) |
| UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2); |
| } |
| |
| if (!PointeeRD->hasIrrelevantDestructor()) |
| if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { |
| MarkFunctionReferenced(StartLoc, |
| const_cast<CXXDestructorDecl*>(Dtor)); |
| if (DiagnoseUseOfDecl(Dtor, StartLoc)) |
| return ExprError(); |
| } |
| |
| // C++ [expr.delete]p3: |
| // In the first alternative (delete object), if the static type of the |
| // object to be deleted is different from its dynamic type, the static |
| // type shall be a base class of the dynamic type of the object to be |
| // deleted and the static type shall have a virtual destructor or the |
| // behavior is undefined. |
| // |
| // Note: a final class cannot be derived from, no issue there |
| if (PointeeRD->isPolymorphic() && !PointeeRD->hasAttr<FinalAttr>()) { |
| CXXDestructorDecl *dtor = PointeeRD->getDestructor(); |
| if (dtor && !dtor->isVirtual()) { |
| if (PointeeRD->isAbstract()) { |
| // If the class is abstract, we warn by default, because we're |
| // sure the code has undefined behavior. |
| Diag(StartLoc, diag::warn_delete_abstract_non_virtual_dtor) |
| << PointeeElem; |
| } else if (!ArrayForm) { |
| // Otherwise, if this is not an array delete, it's a bit suspect, |
| // but not necessarily wrong. |
| Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; |
| } |
| } |
| } |
| |
| } |
| |
| if (!OperatorDelete) |
| // Look for a global declaration. |
| OperatorDelete = FindUsualDeallocationFunction( |
| StartLoc, !RequireCompleteType(StartLoc, Pointee, 0) && |
| (!ArrayForm || UsualArrayDeleteWantsSize || |
| Pointee.isDestructedType()), |
| DeleteName); |
| |
| MarkFunctionReferenced(StartLoc, OperatorDelete); |
| |
| // Check access and ambiguity of operator delete and destructor. |
| if (PointeeRD) { |
| if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { |
| CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, |
| PDiag(diag::err_access_dtor) << PointeeElem); |
| } |
| } |
| } |
| |
| return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, |
| ArrayFormAsWritten, |
| UsualArrayDeleteWantsSize, |
| OperatorDelete, Ex.take(), 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) { |
| if (ConditionVar->isInvalidDecl()) |
| return ExprError(); |
| |
| 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(), |
| diag::err_invalid_use_of_function_type) |
| << ConditionVar->getSourceRange()); |
| else if (T->isArrayType()) |
| return ExprError(Diag(ConditionVar->getLocation(), |
| diag::err_invalid_use_of_array_type) |
| << ConditionVar->getSourceRange()); |
| |
| ExprResult Condition = |
| Owned(DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), |
| SourceLocation(), |
| ConditionVar, |
| /*enclosing*/ false, |
| ConditionVar->getLocation(), |
| ConditionVar->getType().getNonReferenceType(), |
| VK_LValue)); |
| |
| MarkDeclRefReferenced(cast<DeclRefExpr>(Condition.get())); |
| |
| if (ConvertToBoolean) { |
| Condition = CheckBooleanCondition(Condition.take(), StmtLoc); |
| if (Condition.isInvalid()) |
| return ExprError(); |
| } |
| |
| return Condition; |
| } |
| |
| /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. |
| ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr) { |
| // C++ 6.4p4: |
| // The value of a condition that is an initialized declaration in a statement |
| // other than a switch statement is the value of the declared variable |
| // implicitly converted to type bool. If that conversion is ill-formed, the |
| // program is ill-formed. |
| // The value of a condition that is an expression is the value of the |
| // expression, implicitly converted to bool. |
| // |
| return PerformContextuallyConvertToBool(CondExpr); |
| } |
| |
| /// Helper function to determine whether this is the (deprecated) C++ |
| /// conversion from a string literal to a pointer to non-const char or |
| /// non-const wchar_t (for narrow and wide string literals, |
| /// respectively). |
| bool |
| Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { |
| // Look inside the implicit cast, if it exists. |
| if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(From)) |
| From = Cast->getSubExpr(); |
| |
| // A string literal (2.13.4) that is not a wide string literal can |
| // be converted to an rvalue of type "pointer to char"; a wide |
| // string literal can be converted to an rvalue of type "pointer |
| // to wchar_t" (C++ 4.2p2). |
| if (StringLiteral *StrLit = dyn_cast<StringLiteral>(From->IgnoreParens())) |
| if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) |
| if (const BuiltinType *ToPointeeType |
| = ToPtrType->getPointeeType()->getAs<BuiltinType>()) { |
| // This conversion is considered only when there is an |
| // explicit appropriate pointer target type (C++ 4.2p2). |
| if (!ToPtrType->getPointeeType().hasQualifiers()) { |
| switch (StrLit->getKind()) { |
| case StringLiteral::UTF8: |
| case StringLiteral::UTF16: |
| case StringLiteral::UTF32: |
| // We don't allow UTF literals to be implicitly converted |
| break; |
| case StringLiteral::Ascii: |
| return (ToPointeeType->getKind() == BuiltinType::Char_U || |
| ToPointeeType->getKind() == BuiltinType::Char_S); |
| case StringLiteral::Wide: |
| return ToPointeeType->isWideCharType(); |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| static ExprResult BuildCXXCastArgument(Sema &S, |
| SourceLocation CastLoc, |
| QualType Ty, |
| CastKind Kind, |
| CXXMethodDecl *Method, |
| DeclAccessPair FoundDecl, |
| bool HadMultipleCandidates, |
| Expr *From) { |
| switch (Kind) { |
| default: llvm_unreachable("Unhandled cast kind!"); |
| case CK_ConstructorConversion: { |
| CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Method); |
| SmallVector<Expr*, 8> ConstructorArgs; |
| |
| if (S.RequireNonAbstractType(CastLoc, Ty, |
| diag::err_allocation_of_abstract_type)) |
| return ExprError(); |
| |
| if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs)) |
| return ExprError(); |
| |
| S.CheckConstructorAccess(CastLoc, Constructor, |
| InitializedEntity::InitializeTemporary(Ty), |
| Constructor->getAccess()); |
| |
| ExprResult Result |
| = S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), |
| ConstructorArgs, HadMultipleCandidates, |
| /*ListInit*/ false, /*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. |
| CXXConversionDecl *Conv = cast<CXXConversionDecl>(Method); |
| ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Conv, |
| HadMultipleCandidates); |
| if (Result.isInvalid()) |
| return ExprError(); |
| // Record usage of conversion in an implicit cast. |
| Result = S.Owned(ImplicitCastExpr::Create(S.Context, |
| Result.get()->getType(), |
| CK_UserDefinedConversion, |
| Result.get(), 0, |
| Result.get()->getValueKind())); |
| |
| S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ 0, FoundDecl); |
| |
| return S.MaybeBindToTemporary(Result.get()); |
| } |
| } |
| } |
| |
| /// PerformImplicitConversion - Perform an implicit conversion of the |
| /// expression From to the type ToType using the pre-computed implicit |
| /// conversion sequence ICS. Returns the converted |
| /// expression. Action is the kind of conversion we're performing, |
| /// used in the error message. |
| ExprResult |
| Sema::PerformImplicitConversion(Expr *From, QualType ToType, |
| const ImplicitConversionSequence &ICS, |
| AssignmentAction Action, |
| CheckedConversionKind CCK) { |
| switch (ICS.getKind()) { |
| case ImplicitConversionSequence::StandardConversion: { |
| ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard, |
| Action, CCK); |
| if (Res.isInvalid()) |
| return ExprError(); |
| From = Res.take(); |
| break; |
| } |
| |
| case ImplicitConversionSequence::UserDefinedConversion: { |
| |
| FunctionDecl *FD = ICS.UserDefined.ConversionFunction; |
| CastKind CastKind; |
| QualType BeforeToType; |
| assert(FD && "FIXME: aggregate initialization from init list"); |
| 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 { |
| 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 |
| // initial standard conversion sequence converts the source type to the |
| // type required by the argument of the constructor |
| BeforeToType = Ctor->getParamDecl(0)->getType().getNonReferenceType(); |
| } |
| } |
| // Watch out for ellipsis conversion. |
| if (!ICS.UserDefined.EllipsisConversion) { |
| ExprResult Res = |
| PerformImplicitConversion(From, BeforeToType, |
| ICS.UserDefined.Before, AA_Converting, |
| CCK); |
| if (Res.isInvalid()) |
| return ExprError(); |
| From = Res.take(); |
| } |
| |
| ExprResult CastArg |
| = BuildCXXCastArgument(*this, |
| From->getLocStart(), |
| ToType.getNonReferenceType(), |
| CastKind, cast<CXXMethodDecl>(FD), |
| ICS.UserDefined.FoundConversionFunction, |
| ICS.UserDefined.HadMultipleCandidates, |
| From); |
| |
| if (CastArg.isInvalid()) |
| return ExprError(); |
| |
| From = CastArg.take(); |
| |
| return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, |
| AA_Converting, CCK); |
| } |
| |
| case ImplicitConversionSequence::AmbiguousConversion: |
| ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(), |
| PDiag(diag::err_typecheck_ambiguous_condition) |
| << From->getSourceRange()); |
| return ExprError(); |
| |
| case ImplicitConversionSequence::EllipsisConversion: |
| llvm_unreachable("Cannot perform an ellipsis conversion"); |
| |
| case ImplicitConversionSequence::BadConversion: |
| return ExprError(); |
| } |
| |
| // Everything went well. |
| return Owned(From); |
| } |
| |
| /// PerformImplicitConversion - Perform an implicit conversion of the |
| /// expression From to the type ToType by following the standard |
| /// conversion sequence SCS. Returns the converted |
| /// expression. Flavor is the context in which we're performing this |
| /// conversion, for use in error messages. |
| ExprResult |
| Sema::PerformImplicitConversion(Expr *From, QualType ToType, |
| const StandardConversionSequence& SCS, |
| AssignmentAction Action, |
| CheckedConversionKind CCK) { |
| bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast); |
| |
| // 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, |
| // so that we don't need to recompute anything here. |
| QualType FromType = From->getType(); |
| |
| if (SCS.CopyConstructor) { |
| // FIXME: When can ToType be a reference type? |
| assert(!ToType->isReferenceType()); |
| if (SCS.Second == ICK_Derived_To_Base) { |
| SmallVector<Expr*, 8> ConstructorArgs; |
| if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor), |
| From, /*FIXME:ConstructLoc*/SourceLocation(), |
| ConstructorArgs)) |
| return ExprError(); |
| return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), |
| ToType, SCS.CopyConstructor, |
| ConstructorArgs, |
| /*HadMultipleCandidates*/ false, |
| /*ListInit*/ false, /*ZeroInit*/ false, |
| CXXConstructExpr::CK_Complete, |
| SourceRange()); |
| } |
| return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), |
| ToType, SCS.CopyConstructor, |
| From, /*HadMultipleCandidates*/ |