| //===--- 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 "TreeTransform.h" |
| #include "TypeLocBuilder.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/ASTLambda.h" |
| #include "clang/AST/CXXInheritance.h" |
| #include "clang/AST/CharUnits.h" |
| #include "clang/AST/DeclObjC.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::Super: |
| 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 = nullptr; |
| bool isDependent = false; |
| bool LookInScope = false; |
| |
| if (SS.isInvalid()) |
| return ParsedType(); |
| |
| // 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++11 [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. Similarly, in a qualified-id of the form: |
| // |
| // nested-name-specifier[opt] class-name :: ~ class-name |
| // |
| // the second class-name is looked up in the same scope as the first. |
| // |
| // Here, we 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; |
| LookInScope = true; |
| } |
| |
| // The second case from the C++03 rules quoted further above. |
| NestedNameSpecifier *Prefix = nullptr; |
| 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(); |
| } |
| } 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 = nullptr; |
| 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); |
| MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); |
| |
| 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::Super: |
| 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(); |
| |
| if (T->isVariablyModifiedType()) |
| return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T); |
| |
| return 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) { |
| bool WasEvaluated = false; |
| if (E && !E->isTypeDependent()) { |
| if (E->getType()->isPlaceholderType()) { |
| ExprResult result = CheckPlaceholderExpr(E); |
| if (result.isInvalid()) return ExprError(); |
| E = result.get(); |
| } |
| |
| 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.get(); |
| |
| // We require a vtable to query the type at run time. |
| MarkVTableUsed(TypeidLoc, RecordD); |
| WasEvaluated = true; |
| } |
| } |
| |
| // 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()).get(); |
| } |
| } |
| |
| if (E->getType()->isVariablyModifiedType()) |
| return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) |
| << E->getType()); |
| else if (ActiveTemplateInstantiations.empty() && |
| E->HasSideEffects(Context, WasEvaluated)) { |
| // The expression operand for typeid is in an unevaluated expression |
| // context, so side effects could result in unintended consequences. |
| Diag(E->getExprLoc(), WasEvaluated |
| ? diag::warn_side_effects_typeid |
| : diag::warn_side_effects_unevaluated_context); |
| } |
| |
| return 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 = nullptr; |
| 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 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 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 = nullptr; |
| 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 new (Context) |
| CXXBoolLiteralExpr(Kind == tok::kw_true, Context.BoolTy, OpLoc); |
| } |
| |
| /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. |
| ExprResult |
| Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { |
| return 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 (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) |
| Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw"; |
| |
| if (Ex && !Ex->isTypeDependent()) { |
| QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType()); |
| if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex)) |
| 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 = nullptr; |
| if (IsThrownVarInScope) |
| NRVOVariable = getCopyElisionCandidate(QualType(), Ex, false); |
| |
| InitializedEntity Entity = InitializedEntity::InitializeException( |
| OpLoc, ExceptionObjectTy, |
| /*NRVO=*/NRVOVariable != nullptr); |
| ExprResult Res = PerformMoveOrCopyInitialization( |
| Entity, NRVOVariable, QualType(), Ex, IsThrownVarInScope); |
| if (Res.isInvalid()) |
| return ExprError(); |
| Ex = Res.get(); |
| } |
| |
| return new (Context) |
| CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope); |
| } |
| |
| static void |
| collectPublicBases(CXXRecordDecl *RD, |
| llvm::DenseMap<CXXRecordDecl *, unsigned> &SubobjectsSeen, |
| llvm::SmallPtrSetImpl<CXXRecordDecl *> &VBases, |
| llvm::SetVector<CXXRecordDecl *> &PublicSubobjectsSeen, |
| bool ParentIsPublic) { |
| for (const CXXBaseSpecifier &BS : RD->bases()) { |
| CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); |
| bool NewSubobject; |
| // Virtual bases constitute the same subobject. Non-virtual bases are |
| // always distinct subobjects. |
| if (BS.isVirtual()) |
| NewSubobject = VBases.insert(BaseDecl).second; |
| else |
| NewSubobject = true; |
| |
| if (NewSubobject) |
| ++SubobjectsSeen[BaseDecl]; |
| |
| // Only add subobjects which have public access throughout the entire chain. |
| bool PublicPath = ParentIsPublic && BS.getAccessSpecifier() == AS_public; |
| if (PublicPath) |
| PublicSubobjectsSeen.insert(BaseDecl); |
| |
| // Recurse on to each base subobject. |
| collectPublicBases(BaseDecl, SubobjectsSeen, VBases, PublicSubobjectsSeen, |
| PublicPath); |
| } |
| } |
| |
| static void getUnambiguousPublicSubobjects( |
| CXXRecordDecl *RD, llvm::SmallVectorImpl<CXXRecordDecl *> &Objects) { |
| llvm::DenseMap<CXXRecordDecl *, unsigned> SubobjectsSeen; |
| llvm::SmallSet<CXXRecordDecl *, 2> VBases; |
| llvm::SetVector<CXXRecordDecl *> PublicSubobjectsSeen; |
| SubobjectsSeen[RD] = 1; |
| PublicSubobjectsSeen.insert(RD); |
| collectPublicBases(RD, SubobjectsSeen, VBases, PublicSubobjectsSeen, |
| /*ParentIsPublic=*/true); |
| |
| for (CXXRecordDecl *PublicSubobject : PublicSubobjectsSeen) { |
| // Skip ambiguous objects. |
| if (SubobjectsSeen[PublicSubobject] > 1) |
| continue; |
| |
| Objects.push_back(PublicSubobject); |
| } |
| } |
| |
| /// CheckCXXThrowOperand - Validate the operand of a throw. |
| bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, |
| QualType ExceptionObjectTy, Expr *E) { |
| // 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 = ExceptionObjectTy; |
| 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 true; |
| |
| if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy, |
| diag::err_throw_abstract_type, E)) |
| return true; |
| } |
| |
| // If the exception has class type, we need additional handling. |
| CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); |
| if (!RD) |
| return false; |
| |
| // 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 false; |
| |
| // If the class has a destructor, we must be able to call it. |
| if (!RD->hasIrrelevantDestructor()) { |
| if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) { |
| MarkFunctionReferenced(E->getExprLoc(), Destructor); |
| CheckDestructorAccess(E->getExprLoc(), Destructor, |
| PDiag(diag::err_access_dtor_exception) << Ty); |
| if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) |
| return true; |
| } |
| } |
| |
| // The MSVC ABI creates a list of all types which can catch the exception |
| // object. This list also references the appropriate copy constructor to call |
| // if the object is caught by value and has a non-trivial copy constructor. |
| if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { |
| // We are only interested in the public, unambiguous bases contained within |
| // the exception object. Bases which are ambiguous or otherwise |
| // inaccessible are not catchable types. |
| llvm::SmallVector<CXXRecordDecl *, 2> UnambiguousPublicSubobjects; |
| getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects); |
| |
| for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) { |
| // Attempt to lookup the copy constructor. Various pieces of machinery |
| // will spring into action, like template instantiation, which means this |
| // cannot be a simple walk of the class's decls. Instead, we must perform |
| // lookup and overload resolution. |
| CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0); |
| if (!CD) |
| continue; |
| |
| // Mark the constructor referenced as it is used by this throw expression. |
| MarkFunctionReferenced(E->getExprLoc(), CD); |
| |
| // Skip this copy constructor if it is trivial, we don't need to record it |
| // in the catchable type data. |
| if (CD->isTrivial()) |
| continue; |
| |
| // The copy constructor is non-trivial, create a mapping from this class |
| // type to this constructor. |
| // N.B. The selection of copy constructor is not sensitive to this |
| // particular throw-site. Lookup will be performed at the catch-site to |
| // ensure that the copy constructor is, in fact, accessible (via |
| // friendship or any other means). |
| Context.addCopyConstructorForExceptionObject(Subobject, CD); |
| |
| // We don't keep the instantiated default argument expressions around so |
| // we must rebuild them here. |
| for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) { |
| // Skip any default arguments that we've already instantiated. |
| if (Context.getDefaultArgExprForConstructor(CD, I)) |
| continue; |
| |
| Expr *DefaultArg = |
| BuildCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)).get(); |
| Context.addDefaultArgExprForConstructor(CD, I, DefaultArg); |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| QualType Sema::getCurrentThisType() { |
| DeclContext *DC = getFunctionLevelDeclContext(); |
| QualType ThisTy = CXXThisTypeOverride; |
| if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) { |
| if (method && method->isInstance()) |
| ThisTy = method->getThisType(Context); |
| } |
| if (ThisTy.isNull()) { |
| if (isGenericLambdaCallOperatorSpecialization(CurContext) && |
| CurContext->getParent()->getParent()->isRecord()) { |
| // This is a generic lambda call operator that is being instantiated |
| // within a default initializer - so use the enclosing class as 'this'. |
| // There is no enclosing member function to retrieve the 'this' pointer |
| // from. |
| QualType ClassTy = Context.getTypeDeclType( |
| cast<CXXRecordDecl>(CurContext->getParent()->getParent())); |
| // There are no cv-qualifiers for 'this' within default initializers, |
| // per [expr.prim.general]p4. |
| return Context.getPointerType(ClassTy); |
| } |
| } |
| 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 = nullptr; |
| 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, nullptr, ThisTy, |
| Context.getTrivialTypeSourceInfo(ThisTy, Loc), |
| nullptr, 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 = nullptr; |
| 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 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 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); |
| } |
| |
| // C++14 [expr.type.conv]p2: The expression T(), where T is a |
| // simple-type-specifier or typename-specifier for a non-array complete |
| // object type or the (possibly cv-qualified) void type, creates a prvalue |
| // of the specified type, whose value is that produced by value-initializing |
| // an object of type T. |
| 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 (!ListInitialization && Ty->isFunctionType()) |
| return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_function_type) |
| << FullRange); |
| |
| 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<CXXTemporaryObjectExpr>(Inner)) { |
| // If we created a CXXTemporaryObjectExpr, that node also represents the |
| // functional cast. Otherwise, create an explicit cast to represent |
| // the syntactic form of a functional-style cast that was used here. |
| // |
| // FIXME: Creating a CXXFunctionalCastExpr around a CXXConstructExpr |
| // would give a more consistent AST representation than using a |
| // CXXTemporaryObjectExpr. It's also weird that the functional cast |
| // is sometimes handled by initialization and sometimes not. |
| QualType ResultType = Result.get()->getType(); |
| Result = CXXFunctionalCastExpr::Create( |
| Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo, |
| CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc); |
| } |
| |
| 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 = nullptr; |
| // 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().CPlusPlus14) { |
| // 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) |
| .get(); |
| } else { |
| Array.NumElts |
| = VerifyIntegerConstantExpression(NumElts, nullptr, |
| diag::err_new_array_nonconst) |
| .get(); |
| } |
| if (!Array.NumElts) |
| return ExprError(); |
| } |
| } |
| } |
| } |
| |
| TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/nullptr); |
| 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(); |
| } |
| |
| // 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, nullptr)) { |
| 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.get(); |
| } |
| // 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().CPlusPlus14) { |
| 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; |
| } |
| |
| 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.get(); |
| 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 = nullptr; |
| FunctionDecl *OperatorDelete = nullptr; |
| |
| 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) { |
| const FunctionProtoType *Proto = |
| OperatorNew->getType()->getAs<FunctionProtoType>(); |
| VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction |
| : VariadicDoesNotApply; |
| |
| // We've already converted the placement args, just fill in any default |
| // arguments. Skip the first parameter because we don't have a corresponding |
| // argument. |
| if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, 1, |
| PlacementArgs, AllPlaceArgs, CallType)) |
| return ExprError(); |
| |
| if (!AllPlaceArgs.empty()) |
| PlacementArgs = AllPlaceArgs; |
| |
| // FIXME: This is wrong: PlacementArgs misses out the first (size) argument. |
| 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))) { |
| // 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 = Binder->getSubExpr(); |
| |
| Initializer = FullInit.get(); |
| } |
| |
| // 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 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 = nullptr; |
| return false; |
| } |
| |
| // 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 = nullptr; |
| 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, nullptr, 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; |
| } |
| |
| /// \brief Find an fitting overload for the allocation function |
| /// in the specified scope. |
| /// |
| /// \param StartLoc The location of the 'new' token. |
| /// \param Range The range of the placement arguments. |
| /// \param Name The name of the function ('operator new' or 'operator new[]'). |
| /// \param Args The placement arguments specified. |
| /// \param Ctx The scope in which we should search; either a class scope or the |
| /// translation unit. |
| /// \param AllowMissing If \c true, report an error if we can't find any |
| /// allocation functions. Otherwise, succeed but don't fill in \p |
| /// Operator. |
| /// \param Operator Filled in with the found allocation function. Unchanged if |
| /// no allocation function was found. |
| /// \param Diagnose If \c true, issue errors if the allocation function is not |
| /// usable. |
| 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=*/nullptr, |
| 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; |
| if (CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), |
| Best->FoundDecl, Diagnose) == AR_inaccessible) |
| return true; |
| |
| Operator = FnDecl; |
| 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"), |
| nullptr); |
| 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 AddRestrictAttr) { |
| 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 (AddRestrictAttr && !Func->hasAttr<RestrictAttr>()) |
| Func->addAttr(RestrictAttr::CreateImplicit( |
| Context, RestrictAttr::GNU_malloc)); |
| // 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.ExceptionSpec.Type = EST_Dynamic; |
| EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType); |
| } |
| } else { |
| EPI.ExceptionSpec = |
| getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; |
| } |
| |
| QualType Params[] = { Param1, Param2 }; |
| |
| QualType FnType = Context.getFunctionType( |
| Return, llvm::makeArrayRef(Params, NumParams), EPI); |
| FunctionDecl *Alloc = |
| FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), |
| SourceLocation(), Name, |
| FnType, /*TInfo=*/nullptr, SC_None, false, true); |
| Alloc->setImplicit(); |
| |
| // Implicit sized deallocation functions always have default visibility. |
| Alloc->addAttr(VisibilityAttr::CreateImplicit(Context, |
| VisibilityAttr::Default)); |
| |
| if (AddRestrictAttr) |
| Alloc->addAttr( |
| RestrictAttr::CreateImplicit(Context, RestrictAttr::GNU_malloc)); |
| |
| ParmVarDecl *ParamDecls[2]; |
| for (unsigned I = 0; I != NumParams; ++I) { |
| ParamDecls[I] = ParmVarDecl::Create(Context, Alloc, SourceLocation(), |
| SourceLocation(), nullptr, |
| Params[I], /*TInfo=*/nullptr, |
| SC_None, nullptr); |
| ParamDecls[I]->setImplicit(); |
| } |
| Alloc->setParams(llvm::makeArrayRef(ParamDecls, NumParams)); |
| |
| Context.getTranslationUnitDecl()->addDecl(Alloc); |
| IdResolver.tryAddTopLevelDecl(Alloc, Name); |
| } |
| |
| 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"); |
| } |
| |
| if (getLangOpts().CUDA && getLangOpts().CUDATargetOverloads) |
| EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches); |
| |
| 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()); |
| } |
| |
| if (getLangOpts().CUDA && getLangOpts().CUDATargetOverloads) |
| EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches); |
| |
| // 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 = nullptr; |
| return false; |
| } |
| |
| namespace { |
| /// \brief Checks whether delete-expression, and new-expression used for |
| /// initializing deletee have the same array form. |
| class MismatchingNewDeleteDetector { |
| public: |
| enum MismatchResult { |
| /// Indicates that there is no mismatch or a mismatch cannot be proven. |
| NoMismatch, |
| /// Indicates that variable is initialized with mismatching form of \a new. |
| VarInitMismatches, |
| /// Indicates that member is initialized with mismatching form of \a new. |
| MemberInitMismatches, |
| /// Indicates that 1 or more constructors' definitions could not been |
| /// analyzed, and they will be checked again at the end of translation unit. |
| AnalyzeLater |
| }; |
| |
| /// \param EndOfTU True, if this is the final analysis at the end of |
| /// translation unit. False, if this is the initial analysis at the point |
| /// delete-expression was encountered. |
| explicit MismatchingNewDeleteDetector(bool EndOfTU) |
| : IsArrayForm(false), Field(nullptr), EndOfTU(EndOfTU), |
| HasUndefinedConstructors(false) {} |
| |
| /// \brief Checks whether pointee of a delete-expression is initialized with |
| /// matching form of new-expression. |
| /// |
| /// If return value is \c VarInitMismatches or \c MemberInitMismatches at the |
| /// point where delete-expression is encountered, then a warning will be |
| /// issued immediately. If return value is \c AnalyzeLater at the point where |
| /// delete-expression is seen, then member will be analyzed at the end of |
| /// translation unit. \c AnalyzeLater is returned iff at least one constructor |
| /// couldn't be analyzed. If at least one constructor initializes the member |
| /// with matching type of new, the return value is \c NoMismatch. |
| MismatchResult analyzeDeleteExpr(const CXXDeleteExpr *DE); |
| /// \brief Analyzes a class member. |
| /// \param Field Class member to analyze. |
| /// \param DeleteWasArrayForm Array form-ness of the delete-expression used |
| /// for deleting the \p Field. |
| MismatchResult analyzeField(FieldDecl *Field, bool DeleteWasArrayForm); |
| /// List of mismatching new-expressions used for initialization of the pointee |
| llvm::SmallVector<const CXXNewExpr *, 4> NewExprs; |
| /// Indicates whether delete-expression was in array form. |
| bool IsArrayForm; |
| FieldDecl *Field; |
| |
| private: |
| const bool EndOfTU; |
| /// \brief Indicates that there is at least one constructor without body. |
| bool HasUndefinedConstructors; |
| /// \brief Returns \c CXXNewExpr from given initialization expression. |
| /// \param E Expression used for initializing pointee in delete-expression. |
| /// E can be a single-element \c InitListExpr consisting of new-expression. |
| const CXXNewExpr *getNewExprFromInitListOrExpr(const Expr *E); |
| /// \brief Returns whether member is initialized with mismatching form of |
| /// \c new either by the member initializer or in-class initialization. |
| /// |
| /// If bodies of all constructors are not visible at the end of translation |
| /// unit or at least one constructor initializes member with the matching |
| /// form of \c new, mismatch cannot be proven, and this function will return |
| /// \c NoMismatch. |
| MismatchResult analyzeMemberExpr(const MemberExpr *ME); |
| /// \brief Returns whether variable is initialized with mismatching form of |
| /// \c new. |
| /// |
| /// If variable is initialized with matching form of \c new or variable is not |
| /// initialized with a \c new expression, this function will return true. |
| /// If variable is initialized with mismatching form of \c new, returns false. |
| /// \param D Variable to analyze. |
| bool hasMatchingVarInit(const DeclRefExpr *D); |
| /// \brief Checks whether the constructor initializes pointee with mismatching |
| /// form of \c new. |
| /// |
| /// Returns true, if member is initialized with matching form of \c new in |
| /// member initializer list. Returns false, if member is initialized with the |
| /// matching form of \c new in this constructor's initializer or given |
| /// constructor isn't defined at the point where delete-expression is seen, or |
| /// member isn't initialized by the constructor. |
| bool hasMatchingNewInCtor(const CXXConstructorDecl *CD); |
| /// \brief Checks whether member is initialized with matching form of |
| /// \c new in member initializer list. |
| bool hasMatchingNewInCtorInit(const CXXCtorInitializer *CI); |
| /// Checks whether member is initialized with mismatching form of \c new by |
| /// in-class initializer. |
| MismatchResult analyzeInClassInitializer(); |
| }; |
| } |
| |
| MismatchingNewDeleteDetector::MismatchResult |
| MismatchingNewDeleteDetector::analyzeDeleteExpr(const CXXDeleteExpr *DE) { |
| NewExprs.clear(); |
| assert(DE && "Expected delete-expression"); |
| IsArrayForm = DE->isArrayForm(); |
| const Expr *E = DE->getArgument()->IgnoreParenImpCasts(); |
| if (const MemberExpr *ME = dyn_cast<const MemberExpr>(E)) { |
| return analyzeMemberExpr(ME); |
| } else if (const DeclRefExpr *D = dyn_cast<const DeclRefExpr>(E)) { |
| if (!hasMatchingVarInit(D)) |
| return VarInitMismatches; |
| } |
| return NoMismatch; |
| } |
| |
| const CXXNewExpr * |
| MismatchingNewDeleteDetector::getNewExprFromInitListOrExpr(const Expr *E) { |
| assert(E != nullptr && "Expected a valid initializer expression"); |
| E = E->IgnoreParenImpCasts(); |
| if (const InitListExpr *ILE = dyn_cast<const InitListExpr>(E)) { |
| if (ILE->getNumInits() == 1) |
| E = dyn_cast<const CXXNewExpr>(ILE->getInit(0)->IgnoreParenImpCasts()); |
| } |
| |
| return dyn_cast_or_null<const CXXNewExpr>(E); |
| } |
| |
| bool MismatchingNewDeleteDetector::hasMatchingNewInCtorInit( |
| const CXXCtorInitializer *CI) { |
| const CXXNewExpr *NE = nullptr; |
| if (Field == CI->getMember() && |
| (NE = getNewExprFromInitListOrExpr(CI->getInit()))) { |
| if (NE->isArray() == IsArrayForm) |
| return true; |
| else |
| NewExprs.push_back(NE); |
| } |
| return false; |
| } |
| |
| bool MismatchingNewDeleteDetector::hasMatchingNewInCtor( |
| const CXXConstructorDecl *CD) { |
| if (CD->isImplicit()) |
| return false; |
| const FunctionDecl *Definition = CD; |
| if (!CD->isThisDeclarationADefinition() && !CD->isDefined(Definition)) { |
| HasUndefinedConstructors = true; |
| return EndOfTU; |
| } |
| for (const auto *CI : cast<const CXXConstructorDecl>(Definition)->inits()) { |
| if (hasMatchingNewInCtorInit(CI)) |
| return true; |
| } |
| return false; |
| } |
| |
| MismatchingNewDeleteDetector::MismatchResult |
| MismatchingNewDeleteDetector::analyzeInClassInitializer() { |
| assert(Field != nullptr && "This should be called only for members"); |
| const Expr *InitExpr = Field->getInClassInitializer(); |
| if (!InitExpr) |
| return EndOfTU ? NoMismatch : AnalyzeLater; |
| if (const CXXNewExpr *NE = getNewExprFromInitListOrExpr(InitExpr)) { |
| if (NE->isArray() != IsArrayForm) { |
| NewExprs.push_back(NE); |
| return MemberInitMismatches; |
| } |
| } |
| return NoMismatch; |
| } |
| |
| MismatchingNewDeleteDetector::MismatchResult |
| MismatchingNewDeleteDetector::analyzeField(FieldDecl *Field, |
| bool DeleteWasArrayForm) { |
| assert(Field != nullptr && "Analysis requires a valid class member."); |
| this->Field = Field; |
| IsArrayForm = DeleteWasArrayForm; |
| const CXXRecordDecl *RD = cast<const CXXRecordDecl>(Field->getParent()); |
| for (const auto *CD : RD->ctors()) { |
| if (hasMatchingNewInCtor(CD)) |
| return NoMismatch; |
| } |
| if (HasUndefinedConstructors) |
| return EndOfTU ? NoMismatch : AnalyzeLater; |
| if (!NewExprs.empty()) |
| return MemberInitMismatches; |
| return Field->hasInClassInitializer() ? analyzeInClassInitializer() |
| : NoMismatch; |
| } |
| |
| MismatchingNewDeleteDetector::MismatchResult |
| MismatchingNewDeleteDetector::analyzeMemberExpr(const MemberExpr *ME) { |
| assert(ME != nullptr && "Expected a member expression"); |
| if (FieldDecl *F = dyn_cast<FieldDecl>(ME->getMemberDecl())) |
| return analyzeField(F, IsArrayForm); |
| return NoMismatch; |
| } |
| |
| bool MismatchingNewDeleteDetector::hasMatchingVarInit(const DeclRefExpr *D) { |
| const CXXNewExpr *NE = nullptr; |
| if (const VarDecl *VD = dyn_cast<const VarDecl>(D->getDecl())) { |
| if (VD->hasInit() && (NE = getNewExprFromInitListOrExpr(VD->getInit())) && |
| NE->isArray() != IsArrayForm) { |
| NewExprs.push_back(NE); |
| } |
| } |
| return NewExprs.empty(); |
| } |
| |
| static void |
| DiagnoseMismatchedNewDelete(Sema &SemaRef, SourceLocation DeleteLoc, |
| const MismatchingNewDeleteDetector &Detector) { |
| SourceLocation EndOfDelete = SemaRef.getLocForEndOfToken(DeleteLoc); |
| FixItHint H; |
| if (!Detector.IsArrayForm) |
| H = FixItHint::CreateInsertion(EndOfDelete, "[]"); |
| else { |
| SourceLocation RSquare = Lexer::findLocationAfterToken( |
| DeleteLoc, tok::l_square, SemaRef.getSourceManager(), |
| SemaRef.getLangOpts(), true); |
| if (RSquare.isValid()) |
| H = FixItHint::CreateRemoval(SourceRange(EndOfDelete, RSquare)); |
| } |
| SemaRef.Diag(DeleteLoc, diag::warn_mismatched_delete_new) |
| << Detector.IsArrayForm << H; |
| |
| for (const auto *NE : Detector.NewExprs) |
| SemaRef.Diag(NE->getExprLoc(), diag::note_allocated_here) |
| << Detector.IsArrayForm; |
| } |
| |
| void Sema::AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE) { |
| if (Diags.isIgnored(diag::warn_mismatched_delete_new, SourceLocation())) |
| return; |
| MismatchingNewDeleteDetector Detector(/*EndOfTU=*/false); |
| switch (Detector.analyzeDeleteExpr(DE)) { |
| case MismatchingNewDeleteDetector::VarInitMismatches: |
| case MismatchingNewDeleteDetector::MemberInitMismatches: { |
| DiagnoseMismatchedNewDelete(*this, DE->getLocStart(), Detector); |
| break; |
| } |
| case MismatchingNewDeleteDetector::AnalyzeLater: { |
| DeleteExprs[Detector.Field].push_back( |
| std::make_pair(DE->getLocStart(), DE->isArrayForm())); |
| break; |
| } |
| case MismatchingNewDeleteDetector::NoMismatch: |
| break; |
| } |
| } |
| |
| void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, |
| bool DeleteWasArrayForm) { |
| MismatchingNewDeleteDetector Detector(/*EndOfTU=*/true); |
| switch (Detector.analyzeField(Field, DeleteWasArrayForm)) { |
| case MismatchingNewDeleteDetector::VarInitMismatches: |
| llvm_unreachable("This analysis should have been done for class members."); |
| case MismatchingNewDeleteDetector::AnalyzeLater: |
| llvm_unreachable("Analysis cannot be postponed any point beyond end of " |
| "translation unit."); |
| case MismatchingNewDeleteDetector::MemberInitMismatches: |
| DiagnoseMismatchedNewDelete(*this, DeleteLoc, Detector); |
| break; |
| case MismatchingNewDeleteDetector::NoMismatch: |
| break; |
| } |
| } |
| |
| /// 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 = ExE; |
| FunctionDecl *OperatorDelete = nullptr; |
| bool ArrayFormAsWritten = ArrayForm; |
| bool UsualArrayDeleteWantsSize = false; |
| |
| if (!Ex.get()->isTypeDependent()) { |
| // Perform lvalue-to-rvalue cast, if needed. |
| Ex = DefaultLvalueConversion(Ex.get()); |
| 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.get(), 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 = nullptr; |
| 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()); |
| } |
| } |
| |
| if (Pointee->isArrayType() && !ArrayForm) { |
| Diag(StartLoc, diag::warn_delete_array_type) |
| << Type << Ex.get()->getSourceRange() |
| << FixItHint:: |