diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 21:29:30 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 21:29:30 +0000 |
commit | 442906470441699a0cffb2c475ee2fa6e6e57515 (patch) | |
tree | bbbef432354ebeb711fa2c51fe72874e072a8be9 /contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp | |
parent | d88c1a5a572cdb661c111098831fa526e933756f (diff) | |
parent | bab175ec4b075c8076ba14c762900392533f6ee4 (diff) | |
download | src-442906470441699a0cffb2c475ee2fa6e6e57515.tar.gz src-442906470441699a0cffb2c475ee2fa6e6e57515.zip |
Update clang to trunk r290819 and resolve conflicts.
Notes
Notes:
svn path=/projects/clang400-import/; revision=311143
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp | 1908 |
1 files changed, 1116 insertions, 792 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index dfdd36752bf6..5f769cc40ded 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -292,7 +292,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, 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), @@ -326,14 +326,14 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) { if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType) return nullptr; - assert(DS.getTypeSpecType() == DeclSpec::TST_decltype + 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 nullptr; @@ -520,17 +520,17 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT, else if (QT->isArrayType()) Ty = Ty->getBaseElementTypeUnsafe(); - const auto *RD = Ty->getAsCXXRecordDecl(); - if (!RD) + const auto *TD = Ty->getAsTagDecl(); + if (!TD) return; - if (const auto *Uuid = RD->getMostRecentDecl()->getAttr<UuidAttr>()) { + if (const auto *Uuid = TD->getMostRecentDecl()->getAttr<UuidAttr>()) { UuidAttrs.insert(Uuid); return; } // __uuidof can grab UUIDs from template arguments. - if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { + if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(TD)) { const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); for (const TemplateArgument &TA : TAL.asArray()) { const UuidAttr *UuidForTA = nullptr; @@ -662,7 +662,7 @@ Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) { IsThrownVarInScope = true; break; } - + if (S->getFlags() & (Scope::FnScope | Scope::ClassScope | Scope::BlockScope | Scope::FunctionPrototypeScope | Scope::ObjCMethodScope | @@ -672,17 +672,22 @@ Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) { } } } - + return BuildCXXThrow(OpLoc, Ex, IsThrownVarInScope); } -ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, +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"; + // Exceptions aren't allowed in CUDA device code. + if (getLangOpts().CUDA) + CUDADiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions) + << "throw" << CurrentCUDATarget(); + if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw"; @@ -858,13 +863,8 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, // 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); + if (CheckCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I))) + return true; } } } @@ -903,10 +903,10 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda( I-- && isa<LambdaScopeInfo>(FunctionScopes[I]); CurDC = getLambdaAwareParentOfDeclContext(CurDC)) { CurLSI = cast<LambdaScopeInfo>(FunctionScopes[I]); - - if (!CurLSI->isCXXThisCaptured()) + + if (!CurLSI->isCXXThisCaptured()) continue; - + auto C = CurLSI->getCXXThisCapture(); if (C.isCopyCapture()) { @@ -922,7 +922,7 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda( assert(CurLSI); assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator)); assert(CurDC == getLambdaAwareParentOfDeclContext(CurLSI->CallOperator)); - + auto IsThisCaptured = [](CXXRecordDecl *Closure, bool &IsByCopy, bool &IsConst) { IsConst = false; @@ -992,10 +992,10 @@ QualType Sema::getCurrentThisType() { return ThisTy; } -Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, +Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals, - bool Enabled) + bool Enabled) : S(S), OldCXXThisTypeOverride(S.CXXThisTypeOverride), Enabled(false) { if (!Enabled || !ContextDecl) @@ -1006,13 +1006,13 @@ Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, Record = Template->getTemplatedDecl(); else Record = cast<CXXRecordDecl>(ContextDecl); - + // We care only for CVR qualifiers here, so cut everything else. CXXThisTypeQuals &= Qualifiers::FastMask; S.CXXThisTypeOverride = S.Context.getPointerType( S.Context.getRecordType(Record).withCVRQualifiers(CXXThisTypeQuals)); - + this->Enabled = true; } @@ -1026,7 +1026,7 @@ Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD, QualType ThisTy, SourceLocation Loc, const bool ByCopy) { - + QualType AdjustedThisTy = ThisTy; // The type of the corresponding data member (not a 'this' pointer if 'by // copy'). @@ -1039,7 +1039,7 @@ static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD, CaptureThisFieldTy.removeLocalCVRQualifiers(Qualifiers::CVRMask); AdjustedThisTy = Context.getPointerType(CaptureThisFieldTy); } - + FieldDecl *Field = FieldDecl::Create( Context, RD, Loc, Loc, nullptr, CaptureThisFieldTy, Context.getTrivialTypeSourceInfo(CaptureThisFieldTy, Loc), nullptr, false, @@ -1065,24 +1065,24 @@ static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD, return This; } -bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, +bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt, const bool ByCopy) { // We don't need to capture this in an unevaluated context. if (isUnevaluatedContext() && !Explicit) return true; - + assert((!ByCopy || Explicit) && "cannot implicitly capture *this by value"); const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; - + // Check that we can capture the *enclosing object* (referred to by '*this') - // by the capturing-entity/closure (lambda/block/etc) at - // MaxFunctionScopesIndex-deep on the FunctionScopes stack. + // by the capturing-entity/closure (lambda/block/etc) at + // MaxFunctionScopesIndex-deep on the FunctionScopes stack. - // Note: The *enclosing object* can only be captured by-value by a - // closure that is a lambda, using the explicit notation: + // Note: The *enclosing object* can only be captured by-value by a + // closure that is a lambda, using the explicit notation: // [*this] { ... }. // Every other capture of the *enclosing object* results in its by-reference // capture. @@ -1091,15 +1091,15 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, // stack), we can capture the *enclosing object* only if: // - 'L' has an explicit byref or byval capture of the *enclosing object* // - or, 'L' has an implicit capture. - // AND + // AND // -- there is no enclosing closure - // -- or, there is some enclosing closure 'E' that has already captured the - // *enclosing object*, and every intervening closure (if any) between 'E' + // -- or, there is some enclosing closure 'E' that has already captured the + // *enclosing object*, and every intervening closure (if any) between 'E' // and 'L' can implicitly capture the *enclosing object*. - // -- or, every enclosing closure can implicitly capture the + // -- or, every enclosing closure can implicitly capture the // *enclosing object* - - + + unsigned NumCapturingClosures = 0; for (unsigned idx = MaxFunctionScopesIndex; idx != 0; idx--) { if (CapturingScopeInfo *CSI = @@ -1145,7 +1145,7 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, // In the loop below, respect the ByCopy flag only for the closure requesting // the capture (i.e. first iteration through the loop below). Ignore it for - // all enclosing closure's upto NumCapturingClosures (since they must be + // all enclosing closure's up to NumCapturingClosures (since they must be // implicitly capturing the *enclosing object* by reference (see loop // above)). assert((!ByCopy || @@ -1155,18 +1155,18 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated // contexts. QualType ThisTy = getCurrentThisType(); - for (unsigned idx = MaxFunctionScopesIndex; NumCapturingClosures; + for (unsigned idx = MaxFunctionScopesIndex; NumCapturingClosures; --idx, --NumCapturingClosures) { CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]); Expr *ThisExpr = nullptr; - + if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) { // For lambda expressions, build a field and an initializing expression, // and capture the *enclosing object* by copy only if this is the first // iteration. ThisExpr = captureThis(*this, Context, LSI->Lambda, ThisTy, Loc, ByCopy && idx == MaxFunctionScopesIndex); - + } else if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(FunctionScopes[idx])) ThisExpr = @@ -1196,7 +1196,7 @@ bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { // 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(); @@ -1216,6 +1216,17 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); + // Handle errors like: int({0}) + if (exprs.size() == 1 && !canInitializeWithParenthesizedList(Ty) && + LParenLoc.isValid() && RParenLoc.isValid()) + if (auto IList = dyn_cast<InitListExpr>(exprs[0])) { + Diag(TInfo->getTypeLoc().getLocStart(), diag::err_list_init_in_parens) + << Ty << IList->getSourceRange() + << FixItHint::CreateRemoval(LParenLoc) + << FixItHint::CreateRemoval(RParenLoc); + LParenLoc = RParenLoc = SourceLocation(); + } + auto Result = BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc); // Avoid creating a non-type-dependent expression that contains typos. // Non-type-dependent expressions are liable to be discarded without @@ -1280,10 +1291,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, 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 @@ -1317,8 +1324,133 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, return Result; } -/// doesUsualArrayDeleteWantSize - Answers whether the usual -/// operator delete[] for the given type has a size_t parameter. +/// \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; + + unsigned UsualParams = 1; + + if (S.getLangOpts().SizedDeallocation && UsualParams < FD->getNumParams() && + S.Context.hasSameUnqualifiedType( + FD->getParamDecl(UsualParams)->getType(), + S.Context.getSizeType())) + ++UsualParams; + + if (S.getLangOpts().AlignedAllocation && UsualParams < FD->getNumParams() && + S.Context.hasSameUnqualifiedType( + FD->getParamDecl(UsualParams)->getType(), + S.Context.getTypeDeclType(S.getStdAlignValT()))) + ++UsualParams; + + return UsualParams == FD->getNumParams(); +} + +namespace { + struct UsualDeallocFnInfo { + UsualDeallocFnInfo() : Found(), FD(nullptr) {} + UsualDeallocFnInfo(Sema &S, DeclAccessPair Found) + : Found(Found), FD(dyn_cast<FunctionDecl>(Found->getUnderlyingDecl())), + HasSizeT(false), HasAlignValT(false), CUDAPref(Sema::CFP_Native) { + // A function template declaration is never a usual deallocation function. + if (!FD) + return; + if (FD->getNumParams() == 3) + HasAlignValT = HasSizeT = true; + else if (FD->getNumParams() == 2) { + HasSizeT = FD->getParamDecl(1)->getType()->isIntegerType(); + HasAlignValT = !HasSizeT; + } + + // In CUDA, determine how much we'd like / dislike to call this. + if (S.getLangOpts().CUDA) + if (auto *Caller = dyn_cast<FunctionDecl>(S.CurContext)) + CUDAPref = S.IdentifyCUDAPreference(Caller, FD); + } + + operator bool() const { return FD; } + + bool isBetterThan(const UsualDeallocFnInfo &Other, bool WantSize, + bool WantAlign) const { + // C++17 [expr.delete]p10: + // If the type has new-extended alignment, a function with a parameter + // of type std::align_val_t is preferred; otherwise a function without + // such a parameter is preferred + if (HasAlignValT != Other.HasAlignValT) + return HasAlignValT == WantAlign; + + if (HasSizeT != Other.HasSizeT) + return HasSizeT == WantSize; + + // Use CUDA call preference as a tiebreaker. + return CUDAPref > Other.CUDAPref; + } + + DeclAccessPair Found; + FunctionDecl *FD; + bool HasSizeT, HasAlignValT; + Sema::CUDAFunctionPreference CUDAPref; + }; +} + +/// Determine whether a type has new-extended alignment. This may be called when +/// the type is incomplete (for a delete-expression with an incomplete pointee +/// type), in which case it will conservatively return false if the alignment is +/// not known. +static bool hasNewExtendedAlignment(Sema &S, QualType AllocType) { + return S.getLangOpts().AlignedAllocation && + S.getASTContext().getTypeAlignIfKnown(AllocType) > + S.getASTContext().getTargetInfo().getNewAlign(); +} + +/// Select the correct "usual" deallocation function to use from a selection of +/// deallocation functions (either global or class-scope). +static UsualDeallocFnInfo resolveDeallocationOverload( + Sema &S, LookupResult &R, bool WantSize, bool WantAlign, + llvm::SmallVectorImpl<UsualDeallocFnInfo> *BestFns = nullptr) { + UsualDeallocFnInfo Best; + + for (auto I = R.begin(), E = R.end(); I != E; ++I) { + UsualDeallocFnInfo Info(S, I.getPair()); + if (!Info || !isNonPlacementDeallocationFunction(S, Info.FD) || + Info.CUDAPref == Sema::CFP_Never) + continue; + + if (!Best) { + Best = Info; + if (BestFns) + BestFns->push_back(Info); + continue; + } + + if (Best.isBetterThan(Info, WantSize, WantAlign)) + continue; + + // If more than one preferred function is found, all non-preferred + // functions are eliminated from further consideration. + if (BestFns && Info.isBetterThan(Best, WantSize, WantAlign)) + BestFns->clear(); + + Best = Info; + if (BestFns) + BestFns->push_back(Info); + } + + return Best; +} + +/// Determine whether a given type is a class for which 'delete[]' would call +/// a member 'operator delete[]' with a 'size_t' parameter. This implies that +/// we need to store the array size (even if the type is +/// trivially-destructible). static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, QualType allocType) { const RecordType *record = @@ -1342,35 +1474,13 @@ static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, // 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); + // C++17 [expr.delete]p10: + // If the deallocation functions have class scope, the one without a + // parameter of type std::size_t is selected. + auto Best = resolveDeallocationOverload( + S, ops, /*WantSize*/false, + /*WantAlign*/hasNewExtendedAlignment(S, allocType)); + return Best && Best.HasSizeT; } /// \brief Parsed a C++ 'new' expression (C++ 5.3.4). @@ -1454,8 +1564,20 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, return ExprError(); SourceRange DirectInitRange; - if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) + if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) { DirectInitRange = List->getSourceRange(); + // Handle errors like: new int a({0}) + if (List->getNumExprs() == 1 && + !canInitializeWithParenthesizedList(AllocType)) + if (auto IList = dyn_cast<InitListExpr>(List->getExpr(0))) { + Diag(TInfo->getTypeLoc().getLocStart(), diag::err_list_init_in_parens) + << AllocType << List->getSourceRange() + << FixItHint::CreateRemoval(List->getLocStart()) + << FixItHint::CreateRemoval(List->getLocEnd()); + DirectInitRange = SourceRange(); + Initializer = IList; + } + } return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal, PlacementLParen, @@ -1574,7 +1696,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, << /*at end of FE*/0 << Inits[0]->getSourceRange(); } - // In ARC, infer 'retaining' for the allocated + // In ARC, infer 'retaining' for the allocated if (getLangOpts().ObjCAutoRefCount && AllocType.getObjCLifetime() == Qualifiers::OCL_None && AllocType->isObjCLifetimeType()) { @@ -1583,7 +1705,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, } QualType ResultType = Context.getPointerType(AllocType); - + if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(ArraySize); if (result.isInvalid()) return ExprError(); @@ -1596,6 +1718,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // conversion function to integral or unscoped enumeration type exists. // C++1y [expr.new]p6: The expression [...] is implicitly converted to // std::size_t. + llvm::Optional<uint64_t> KnownArraySize; if (ArraySize && !ArraySize->isTypeDependent()) { ExprResult ConvertedSize; if (getLangOpts().CPlusPlus14) { @@ -1604,7 +1727,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(), AA_Converting); - if (!ConvertedSize.isInvalid() && + if (!ConvertedSize.isInvalid() && ArraySize->getType()->getAs<RecordType>()) // Diagnose the compatibility of this conversion. Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion) @@ -1613,7 +1736,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, class SizeConvertDiagnoser : public ICEConvertDiagnoser { protected: Expr *ArraySize; - + public: SizeConvertDiagnoser(Expr *ArraySize) : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, false, false), @@ -1680,44 +1803,34 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // 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. + // Let's see if this is a constant < 0. If so, we reject it out of hand, + // per CWG1464. Otherwise, if it's not a constant, we must have an + // unparenthesized array type. if (!ArraySize->isValueDependent()) { llvm::APSInt Value; // We've already performed any required implicit conversion to integer or // unscoped enumeration type. + // FIXME: Per CWG1464, we are required to check the value prior to + // converting to size_t. This will never find a negative array size in + // C++14 onwards, because Value is always unsigned here! 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()) { + if (Value.isSigned() && Value.isNegative()) { + return ExprError(Diag(ArraySize->getLocStart(), + diag::err_typecheck_negative_array_size) + << ArraySize->getSourceRange()); + } + + 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()); - } + if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) + return ExprError(Diag(ArraySize->getLocStart(), + diag::err_array_too_large) + << Value.toString(10) + << ArraySize->getSourceRange()); } + + KnownArraySize = Value.getZExtValue(); } 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) @@ -1735,21 +1848,26 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, FunctionDecl *OperatorNew = nullptr; FunctionDecl *OperatorDelete = nullptr; + unsigned Alignment = + AllocType->isDependentType() ? 0 : Context.getTypeAlign(AllocType); + unsigned NewAlignment = Context.getTargetInfo().getNewAlign(); + bool PassAlignment = getLangOpts().AlignedAllocation && + Alignment > NewAlignment; if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlacementArgs) && FindAllocationFunctions(StartLoc, SourceRange(PlacementLParen, PlacementRParen), - UseGlobal, AllocType, ArraySize, PlacementArgs, - OperatorNew, OperatorDelete)) + UseGlobal, AllocType, ArraySize, PassAlignment, + 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); + UsualArrayDeleteWantsSize = + doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); SmallVector<Expr *, 8> AllPlaceArgs; if (OperatorNew) { @@ -1760,9 +1878,11 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // 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)) + // argument. Skip the second parameter too if we're passing in the + // alignment; we've already filled it in. + if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, + PassAlignment ? 2 : 1, PlacementArgs, + AllPlaceArgs, CallType)) return ExprError(); if (!AllPlaceArgs.empty()) @@ -1772,44 +1892,29 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, 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() || - (OperatorNew->getLocStart().isValid() && - getSourceManager().isInSystemHeader(OperatorNew->getLocStart())))) { - if (unsigned Align = Context.getPreferredTypeAlign(AllocType.getTypePtr())){ - unsigned SuitableAlign = Context.getTargetInfo().getSuitableAlign(); - if (Align > SuitableAlign) + // Warn if the type is over-aligned and is being allocated by (unaligned) + // global operator new. + if (PlacementArgs.empty() && !PassAlignment && + (OperatorNew->isImplicit() || + (OperatorNew->getLocStart().isValid() && + getSourceManager().isInSystemHeader(OperatorNew->getLocStart())))) { + if (Alignment > NewAlignment) Diag(StartLoc, diag::warn_overaligned_type) << AllocType - << unsigned(Align / Context.getCharWidth()) - << unsigned(SuitableAlign / Context.getCharWidth()); + << unsigned(Alignment / Context.getCharWidth()) + << unsigned(NewAlignment / 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 (ArraySize && !isLegalArrayNewInitializer(initStyle, Initializer)) { + SourceRange InitRange(Inits[0]->getLocStart(), + Inits[NumInits - 1]->getLocEnd()); + Diag(StartLoc, diag::err_new_array_init_args) << InitRange; + return ExprError(); } // If we can perform the initialization, and we've not already done so, @@ -1817,6 +1922,19 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments( llvm::makeArrayRef(Inits, NumInits))) { + // The type we initialize is the complete type, including the array bound. + QualType InitType; + if (KnownArraySize) + InitType = Context.getConstantArrayType( + AllocType, llvm::APInt(Context.getTypeSize(Context.getSizeType()), + *KnownArraySize), + ArrayType::Normal, 0); + else if (ArraySize) + InitType = + Context.getIncompleteArrayType(AllocType, ArrayType::Normal, 0); + else + InitType = AllocType; + // C++11 [expr.new]p15: // A new-expression that creates an object of type T initializes that // object as follows: @@ -1836,7 +1954,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, InitType); - InitializationSequence InitSeq(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); + InitializationSequence InitSeq(*this, Entity, Kind, + MultiExprArg(Inits, NumInits)); ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); if (FullInit.isInvalid()) @@ -1844,6 +1963,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // FullInit is our initializer; strip off CXXBindTemporaryExprs, because // we don't want the initialized object to be destructed. + // FIXME: We should not create these in the first place. if (CXXBindTemporaryExpr *Binder = dyn_cast_or_null<CXXBindTemporaryExpr>(FullInit.get())) FullInit = Binder->getSubExpr(); @@ -1872,7 +1992,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (CXXDestructorDecl *dtor = LookupDestructor( cast<CXXRecordDecl>(BaseRecordType->getDecl()))) { MarkFunctionReferenced(StartLoc, dtor); - CheckDestructorAccess(StartLoc, dtor, + CheckDestructorAccess(StartLoc, dtor, PDiag(diag::err_access_dtor) << BaseAllocType); if (DiagnoseUseOfDecl(dtor, StartLoc)) @@ -1882,7 +2002,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, } return new (Context) - CXXNewExpr(Context, UseGlobal, OperatorNew, OperatorDelete, + CXXNewExpr(Context, UseGlobal, OperatorNew, OperatorDelete, PassAlignment, UsualArrayDeleteWantsSize, PlacementArgs, TypeIdParens, ArraySize, initStyle, Initializer, ResultType, AllocTypeInfo, Range, DirectInitRange); @@ -1921,36 +2041,132 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, << 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; +static bool +resolveAllocationOverload(Sema &S, LookupResult &R, SourceRange Range, + SmallVectorImpl<Expr *> &Args, bool &PassAlignment, + FunctionDecl *&Operator, + OverloadCandidateSet *AlignedCandidates = nullptr, + Expr *AlignArg = nullptr) { + OverloadCandidateSet Candidates(R.getNameLoc(), + 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 (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) - return Method->isUsualDeallocationFunction(); + if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) { + S.AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), + /*ExplicitTemplateArgs=*/nullptr, Args, + Candidates, + /*SuppressUserConversions=*/false); + continue; + } - if (FD->getOverloadedOperator() != OO_Delete && - FD->getOverloadedOperator() != OO_Array_Delete) + FunctionDecl *Fn = cast<FunctionDecl>(D); + S.AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates, + /*SuppressUserConversions=*/false); + } + + // Do the resolution. + OverloadCandidateSet::iterator Best; + switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) { + case OR_Success: { + // Got one! + FunctionDecl *FnDecl = Best->Function; + if (S.CheckAllocationAccess(R.getNameLoc(), Range, R.getNamingClass(), + Best->FoundDecl) == Sema::AR_inaccessible) + return true; + + Operator = FnDecl; return false; + } + + case OR_No_Viable_Function: + // C++17 [expr.new]p13: + // If no matching function is found and the allocated object type has + // new-extended alignment, the alignment argument is removed from the + // argument list, and overload resolution is performed again. + if (PassAlignment) { + PassAlignment = false; + AlignArg = Args[1]; + Args.erase(Args.begin() + 1); + return resolveAllocationOverload(S, R, Range, Args, PassAlignment, + Operator, &Candidates, AlignArg); + } - if (FD->getNumParams() == 1) + // 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. + // FIXME: Find out how this interacts with the std::align_val_t fallback + // once MSVC implements it. + if (R.getLookupName().getCXXOverloadedOperator() == OO_Array_New && + S.Context.getLangOpts().MSVCCompat) { + R.clear(); + R.setLookupName(S.Context.DeclarationNames.getCXXOperatorName(OO_New)); + S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl()); + // FIXME: This will give bad diagnostics pointing at the wrong functions. + return resolveAllocationOverload(S, R, Range, Args, PassAlignment, + Operator, nullptr); + } + + S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) + << R.getLookupName() << Range; + + // If we have aligned candidates, only note the align_val_t candidates + // from AlignedCandidates and the non-align_val_t candidates from + // Candidates. + if (AlignedCandidates) { + auto IsAligned = [](OverloadCandidate &C) { + return C.Function->getNumParams() > 1 && + C.Function->getParamDecl(1)->getType()->isAlignValT(); + }; + auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); }; + + // This was an overaligned allocation, so list the aligned candidates + // first. + Args.insert(Args.begin() + 1, AlignArg); + AlignedCandidates->NoteCandidates(S, OCD_AllCandidates, Args, "", + R.getNameLoc(), IsAligned); + Args.erase(Args.begin() + 1); + Candidates.NoteCandidates(S, OCD_AllCandidates, Args, "", R.getNameLoc(), + IsUnaligned); + } else { + Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + } + return true; + + case OR_Ambiguous: + S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) + << R.getLookupName() << Range; + Candidates.NoteCandidates(S, OCD_ViableCandidates, Args); return true; - return S.getLangOpts().SizedDeallocation && FD->getNumParams() == 2 && - S.Context.hasSameUnqualifiedType(FD->getParamDecl(1)->getType(), - S.Context.getSizeType()); + case OR_Deleted: { + S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call) + << Best->Function->isDeleted() + << R.getLookupName() + << S.getDeletedOrUnavailableSuffix(Best->Function) + << Range; + Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + return true; + } + } + llvm_unreachable("Unreachable, bad result from BestViableFunction"); } + /// 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, + bool IsArray, bool &PassAlignment, + MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, FunctionDecl *&OperatorDelete) { // --- Choosing an allocation function --- @@ -1962,16 +2178,29 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // 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. + SmallVector<Expr*, 8> AllocArgs; + AllocArgs.reserve((PassAlignment ? 2 : 1) + PlaceArgs.size()); + + // We don't care about the actual value of these arguments. // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? + // FIXME: Using a dummy value will interact poorly with attribute enable_if. 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); + AllocArgs.push_back(&Size); + + QualType AlignValT = Context.VoidTy; + if (PassAlignment) { + DeclareGlobalNewDelete(); + AlignValT = Context.getTypeDeclType(getStdAlignValT()); + } + CXXScalarValueInitExpr Align(AlignValT, nullptr, SourceLocation()); + if (PassAlignment) + AllocArgs.push_back(&Align); + + AllocArgs.insert(AllocArgs.end(), PlaceArgs.begin(), PlaceArgs.end()); // C++ [expr.new]p8: // If the allocated type is a non-array type, the allocation @@ -1980,50 +2209,57 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // 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); + IsArray ? OO_Array_New : OO_New); 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)) + // Find the allocation function. + { + LookupResult R(*this, NewName, StartLoc, LookupOrdinaryName); + + // C++1z [expr.new]p9: + // If the new-expression begins with a unary :: operator, the allocation + // function's name is looked up in the global scope. Otherwise, if the + // allocated type is a class type T or array thereof, the allocation + // function's name is looked up in the scope of T. + if (AllocElemType->isRecordType() && !UseGlobal) + LookupQualifiedName(R, AllocElemType->getAsCXXRecordDecl()); + + // We can see ambiguity here if the allocation function is found in + // multiple base classes. + if (R.isAmbiguous()) 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; + // If this lookup fails to find the name, or if the allocated type is not + // a class type, the allocation function's name is looked up in the + // global scope. + if (R.empty()) + LookupQualifiedName(R, Context.getTranslationUnitDecl()); + + assert(!R.empty() && "implicitly declared allocation functions not found"); + assert(!R.isAmbiguous() && "global allocation functions are ambiguous"); - // 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)) + // We do our own custom access checks below. + R.suppressDiagnostics(); + + if (resolveAllocationOverload(*this, R, Range, AllocArgs, PassAlignment, + OperatorNew)) return true; - } } - // We don't need an operator delete if we're running under - // -fno-exceptions. + // We don't need an operator delete if we're running under -fno-exceptions. if (!getLangOpts().Exceptions) { OperatorDelete = nullptr; return false; } + // Note, the name of OperatorNew might have been changed from array to + // non-array by resolveAllocationOverload. + DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( + OperatorNew->getDeclName().getCXXOverloadedOperator() == OO_Array_New + ? OO_Array_Delete + : OO_Delete); + // C++ [expr.new]p19: // // If the new-expression begins with a unary :: operator, the @@ -2042,6 +2278,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, if (FoundDelete.isAmbiguous()) return true; // FIXME: clean up expressions? + bool FoundGlobalDelete = FoundDelete.empty(); if (FoundDelete.empty()) { DeclareGlobalNewDelete(); LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); @@ -2056,7 +2293,16 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // 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); + // + // We don't have any definition for what a "placement allocation function" + // is, but we assume it's any allocation function whose + // parameter-declaration-clause is anything other than (size_t). + // + // FIXME: Should (size_t, std::align_val_t) also be considered non-placement? + // This affects whether an exception from the constructor of an overaligned + // type uses the sized or non-sized form of aligned operator delete. + bool isPlacementNew = !PlaceArgs.empty() || OperatorNew->param_size() != 1 || + OperatorNew->isVariadic(); if (isPlacementNew) { // C++ [expr.new]p20: @@ -2069,8 +2315,6 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // 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 @@ -2082,6 +2326,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, ArgTypes.push_back(Proto->getParamType(I)); FunctionProtoType::ExtProtoInfo EPI; + // FIXME: This is not part of the standard's rule. EPI.Variadic = Proto->isVariadic(); ExpectedFunctionType @@ -2092,8 +2337,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, DEnd = FoundDelete.end(); D != DEnd; ++D) { FunctionDecl *Fn = nullptr; - if (FunctionTemplateDecl *FnTmpl - = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { + if (FunctionTemplateDecl *FnTmpl = + dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { // Perform template argument deduction to try to match the // expected function type. TemplateDeductionInfo Info(StartLoc); @@ -2103,38 +2348,35 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, } else Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl()); - if (Context.hasSameType(Fn->getType(), ExpectedFunctionType)) + if (Context.hasSameType(adjustCCAndNoReturn(Fn->getType(), + ExpectedFunctionType, + /*AdjustExcpetionSpec*/true), + 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)); - } + if (getLangOpts().CUDA) + EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches); + } else { // 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"); + // + // Per [expr.delete]p10, this lookup prefers a member operator delete + // without a size_t argument, but prefers a non-member operator delete + // with a size_t where possible (which it always is in this case). + llvm::SmallVector<UsualDeallocFnInfo, 4> BestDeallocFns; + UsualDeallocFnInfo Selected = resolveDeallocationOverload( + *this, FoundDelete, /*WantSize*/ FoundGlobalDelete, + /*WantAlign*/ hasNewExtendedAlignment(*this, AllocElemType), + &BestDeallocFns); + if (Selected) + Matches.push_back(std::make_pair(Selected.Found, Selected.FD)); + else { + // If we failed to select an operator, all remaining functions are viable + // but ambiguous. + for (auto Fn : BestDeallocFns) + Matches.push_back(std::make_pair(Fn.Found, Fn.FD)); } } @@ -2145,130 +2387,59 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, 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 + // C++1z [expr.new]p23: + // If the lookup finds a usual deallocation function (3.7.4.2) + // with a parameter of type std::size_t 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 && + if (getLangOpts().CPlusPlus11 && isPlacementNew && 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(); + UsualDeallocFnInfo Info(*this, + DeclAccessPair::make(OperatorDelete, AS_public)); + // Core issue, per mail to core reflector, 2016-10-09: + // If this is a member operator delete, and there is a corresponding + // non-sized member operator delete, this isn't /really/ a sized + // deallocation function, it just happens to have a size_t parameter. + bool IsSizedDelete = Info.HasSizeT; + if (IsSizedDelete && !FoundGlobalDelete) { + auto NonSizedDelete = + resolveDeallocationOverload(*this, FoundDelete, /*WantSize*/false, + /*WantAlign*/Info.HasAlignValT); + if (NonSizedDelete && !NonSizedDelete.HasSizeT && + NonSizedDelete.HasAlignValT == Info.HasAlignValT) + IsSizedDelete = false; + } - if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) { - AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), - /*ExplicitTemplateArgs=*/nullptr, - Args, Candidates, - /*SuppressUserConversions=*/false); - continue; + if (IsSizedDelete) { + SourceRange R = PlaceArgs.empty() + ? SourceRange() + : SourceRange(PlaceArgs.front()->getLocStart(), + PlaceArgs.back()->getLocEnd()); + Diag(StartLoc, diag::err_placement_new_non_placement_delete) << R; + if (!OperatorDelete->isImplicit()) + Diag(OperatorDelete->getLocation(), diag::note_previous_decl) + << DeleteName; + } } - 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; + CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(), + Matches[0].first); + } else if (!Matches.empty()) { + // We found multiple suitable operators. Per [expr.new]p20, that means we + // call no 'operator delete' function, but we should at least warn the user. + // FIXME: Suppress this warning if the construction cannot throw. + Diag(StartLoc, diag::warn_ambiguous_suitable_delete_function_found) + << DeleteName << AllocElemType; - Operator = FnDecl; - return false; + for (auto &Match : Matches) + Diag(Match.second->getLocation(), + diag::note_member_declared_here) << DeleteName; } - 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"); + return false; } - /// DeclareGlobalNewDelete - Declare the global forms of operator new and /// delete. These are: /// @code @@ -2336,41 +2507,64 @@ void Sema::DeclareGlobalNewDelete() { nullptr); getStdBadAlloc()->setImplicit(true); } + if (!StdAlignValT && getLangOpts().AlignedAllocation) { + // The "std::align_val_t" enum class has not yet been declared, so build it + // implicitly. + auto *AlignValT = EnumDecl::Create( + Context, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(), + &PP.getIdentifierTable().get("align_val_t"), nullptr, true, true, true); + AlignValT->setIntegerType(Context.getSizeType()); + AlignValT->setPromotionType(Context.getSizeType()); + AlignValT->setImplicit(true); + StdAlignValT = AlignValT; + } GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); QualType SizeT = Context.getSizeType(); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_New), - VoidPtr, SizeT, QualType()); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Array_New), - VoidPtr, SizeT, QualType()); - 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()); - } + auto DeclareGlobalAllocationFunctions = [&](OverloadedOperatorKind Kind, + QualType Return, QualType Param) { + llvm::SmallVector<QualType, 3> Params; + Params.push_back(Param); + + // Create up to four variants of the function (sized/aligned). + bool HasSizedVariant = getLangOpts().SizedDeallocation && + (Kind == OO_Delete || Kind == OO_Array_Delete); + bool HasAlignedVariant = getLangOpts().AlignedAllocation; + + int NumSizeVariants = (HasSizedVariant ? 2 : 1); + int NumAlignVariants = (HasAlignedVariant ? 2 : 1); + for (int Sized = 0; Sized < NumSizeVariants; ++Sized) { + if (Sized) + Params.push_back(SizeT); + + for (int Aligned = 0; Aligned < NumAlignVariants; ++Aligned) { + if (Aligned) + Params.push_back(Context.getTypeDeclType(getStdAlignValT())); + + DeclareGlobalAllocationFunction( + Context.DeclarationNames.getCXXOperatorName(Kind), Return, Params); + + if (Aligned) + Params.pop_back(); + } + } + }; + + DeclareGlobalAllocationFunctions(OO_New, VoidPtr, SizeT); + DeclareGlobalAllocationFunctions(OO_Array_New, VoidPtr, SizeT); + DeclareGlobalAllocationFunctions(OO_Delete, Context.VoidTy, VoidPtr); + DeclareGlobalAllocationFunctions(OO_Array_Delete, Context.VoidTy, VoidPtr); } /// 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) { + ArrayRef<QualType> Params) { DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); - unsigned NumParams = Param2.isNull() ? 1 : 2; // Check if this function is already declared. DeclContext::lookup_result R = GlobalCtx->lookup(Name); @@ -2379,18 +2573,12 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, // 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 (Func->getNumParams() == Params.size()) { + llvm::SmallVector<QualType, 3> FuncParams; + for (auto *P : Func->parameters()) + FuncParams.push_back( + Context.getCanonicalType(P->getType().getUnqualifiedType())); + if (llvm::makeArrayRef(FuncParams) == Params) { // 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. @@ -2419,82 +2607,80 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, 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)); - - 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); + auto CreateAllocationFunctionDecl = [&](Attr *ExtraAttr) { + QualType FnType = Context.getFunctionType(Return, Params, 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)); + + llvm::SmallVector<ParmVarDecl *, 3> ParamDecls; + for (QualType T : Params) { + ParamDecls.push_back(ParmVarDecl::Create( + Context, Alloc, SourceLocation(), SourceLocation(), nullptr, T, + /*TInfo=*/nullptr, SC_None, nullptr)); + ParamDecls.back()->setImplicit(); + } + Alloc->setParams(ParamDecls); + if (ExtraAttr) + Alloc->addAttr(ExtraAttr); + Context.getTranslationUnitDecl()->addDecl(Alloc); + IdResolver.tryAddTopLevelDecl(Alloc, Name); + }; + + if (!LangOpts.CUDA) + CreateAllocationFunctionDecl(nullptr); + else { + // Host and device get their own declaration so each can be + // defined or re-declared independently. + CreateAllocationFunctionDecl(CUDAHostAttr::CreateImplicit(Context)); + CreateAllocationFunctionDecl(CUDADeviceAttr::CreateImplicit(Context)); + } } FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc, bool CanProvideSize, + bool Overaligned, 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"); - } + // FIXME: It's possible for this to result in ambiguity, through a + // user-declared variadic operator delete or the enable_if attribute. We + // should probably not consider those cases to be usual deallocation + // functions. But for now we just make an arbitrary choice in that case. + auto Result = resolveDeallocationOverload(*this, FoundDelete, CanProvideSize, + Overaligned); + assert(Result.FD && "operator delete missing from global scope?"); + return Result.FD; +} - if (getLangOpts().CUDA) - EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches); +FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc, + CXXRecordDecl *RD) { + DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete); - assert(Matches.size() == 1 && - "unexpectedly have multiple usual deallocation functions"); - return Matches.front(); + FunctionDecl *OperatorDelete = nullptr; + if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete)) + return nullptr; + if (OperatorDelete) + return OperatorDelete; + + // If there's no class-specific operator delete, look up the global + // non-array delete. + return FindUsualDeallocationFunction( + Loc, true, hasNewExtendedAlignment(*this, Context.getRecordType(RD)), + Name); } bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, - FunctionDecl* &Operator, bool Diagnose) { + FunctionDecl *&Operator, bool Diagnose) { LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); @@ -2504,27 +2690,20 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Found.suppressDiagnostics(); - SmallVector<DeclAccessPair,4> Matches; - for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); - F != FEnd; ++F) { - NamedDecl *ND = (*F)->getUnderlyingDecl(); + bool Overaligned = hasNewExtendedAlignment(*this, Context.getRecordType(RD)); - // Ignore template operator delete members from the check for a usual - // deallocation function. - if (isa<FunctionTemplateDecl>(ND)) - continue; + // C++17 [expr.delete]p10: + // If the deallocation functions have class scope, the one without a + // parameter of type std::size_t is selected. + llvm::SmallVector<UsualDeallocFnInfo, 4> Matches; + resolveDeallocationOverload(*this, Found, /*WantSize*/ false, + /*WantAlign*/ Overaligned, &Matches); - if (cast<CXXMethodDecl>(ND)->isUsualDeallocationFunction()) - Matches.push_back(F.getPair()); - } - - if (getLangOpts().CUDA) - EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches); - - // There's exactly one suitable operator; pick it. + // If we could find an overload, use it. if (Matches.size() == 1) { - Operator = cast<CXXMethodDecl>(Matches[0]->getUnderlyingDecl()); + Operator = cast<CXXMethodDecl>(Matches[0].FD); + // FIXME: DiagnoseUseOfDecl? if (Operator->isDeleted()) { if (Diagnose) { Diag(StartLoc, diag::err_deleted_function_use); @@ -2534,21 +2713,21 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, } if (CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), - Matches[0], Diagnose) == AR_inaccessible) + Matches[0].Found, Diagnose) == AR_inaccessible) return true; return false; + } - // We found multiple suitable operators; complain about the ambiguity. - } else if (!Matches.empty()) { + // We found multiple suitable operators; complain about the ambiguity. + // FIXME: The standard doesn't say to do this; it appears that the intent + // is that this should never happen. + 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; + for (auto &Match : Matches) + Diag(Match.FD->getLocation(), diag::note_member_declared_here) << Name; } return true; } @@ -2560,9 +2739,8 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, 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(), + for (NamedDecl *D : Found) + Diag(D->getUnderlyingDecl()->getLocation(), diag::note_member_declared_here) << Name; } return true; @@ -2593,7 +2771,7 @@ public: /// 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), + : Field(nullptr), IsArrayForm(false), EndOfTU(EndOfTU), HasUndefinedConstructors(false) {} /// \brief Checks whether pointee of a delete-expression is initialized with @@ -2612,11 +2790,11 @@ public: /// \param DeleteWasArrayForm Array form-ness of the delete-expression used /// for deleting the \p Field. MismatchResult analyzeField(FieldDecl *Field, bool DeleteWasArrayForm); + FieldDecl *Field; /// 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; @@ -2921,7 +3099,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType PointeeElem = Context.getBaseElementType(Pointee); if (unsigned AddressSpace = Pointee.getAddressSpace()) - return Diag(Ex.get()->getLocStart(), + return Diag(Ex.get()->getLocStart(), diag::err_address_space_qualified_delete) << Pointee.getUnqualifiedType() << AddressSpace; @@ -2973,7 +3151,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // Otherwise, the usual operator delete[] should be the // function we just found. else if (OperatorDelete && isa<CXXMethodDecl>(OperatorDelete)) - UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2); + UsualArrayDeleteWantsSize = + UsualDeallocFnInfo(*this, + DeclAccessPair::make(OperatorDelete, AS_public)) + .HasSizeT; } if (!PointeeRD->hasIrrelevantDestructor()) @@ -2990,20 +3171,24 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, SourceLocation()); } - if (!OperatorDelete) + if (!OperatorDelete) { + bool IsComplete = isCompleteType(StartLoc, Pointee); + bool CanProvideSize = + IsComplete && (!ArrayForm || UsualArrayDeleteWantsSize || + Pointee.isDestructedType()); + bool Overaligned = hasNewExtendedAlignment(*this, Pointee); + // Look for a global declaration. - OperatorDelete = FindUsualDeallocationFunction( - StartLoc, isCompleteType(StartLoc, Pointee) && - (!ArrayForm || UsualArrayDeleteWantsSize || - Pointee.isDestructedType()), - DeleteName); + OperatorDelete = FindUsualDeallocationFunction(StartLoc, CanProvideSize, + Overaligned, DeleteName); + } MarkFunctionReferenced(StartLoc, OperatorDelete); // Check access and ambiguity of operator delete and destructor. if (PointeeRD) { if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { - CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, + CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, PDiag(diag::err_access_dtor) << PointeeElem); } } @@ -3234,7 +3419,7 @@ static ExprResult BuildCXXCastArgument(Sema &S, ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence &ICS, - AssignmentAction Action, + AssignmentAction Action, CheckedConversionKind CCK) { switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: { @@ -3309,6 +3494,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, llvm_unreachable("Cannot perform an ellipsis conversion"); case ImplicitConversionSequence::BadConversion: + bool Diagnosed = + DiagnoseAssignmentResult(Incompatible, From->getExprLoc(), ToType, + From->getType(), From, Action); + assert(Diagnosed && "failed to diagnose bad conversion"); (void)Diagnosed; return ExprError(); } @@ -3324,16 +3513,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, - AssignmentAction Action, + AssignmentAction Action, CheckedConversionKind CCK) { bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast); - + // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, // so that we don't need to recompute anything here. QualType FromType = From->getType(); - + if (SCS.CopyConstructor) { // FIXME: When can ToType be a reference type? assert(!ToType->isReferenceType()); @@ -3403,13 +3592,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); - From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay, + From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Function_To_Pointer: FromType = Context.getPointerType(FromType); - From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, + From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -3446,16 +3635,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Nothing else to do. break; - case ICK_NoReturn_Adjustment: - // If both sides are functions (or pointers/references to them), there could - // be incompatible exception declarations. - if (CheckExceptionSpecCompatibility(From, ToType)) - return ExprError(); - - From = ImpCastExprToType(From, ToType, CK_NoOp, - VK_RValue, /*BasePath=*/nullptr, CCK).get(); - break; - case ICK_Integral_Promotion: case ICK_Integral_Conversion: if (ToType->isBooleanType()) { @@ -3472,7 +3651,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Floating_Promotion: case ICK_Floating_Conversion: - From = ImpCastExprToType(From, ToType, CK_FloatingCast, + From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -3491,22 +3670,22 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } else { CK = CK_IntegralComplexCast; } - From = ImpCastExprToType(From, ToType, CK, + From = ImpCastExprToType(From, ToType, CK, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_Floating_Integral: if (ToType->isRealFloatingType()) - From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, + From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_RValue, /*BasePath=*/nullptr, CCK).get(); else - From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, + From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Compatible_Conversion: - From = ImpCastExprToType(From, ToType, CK_NoOp, + From = ImpCastExprToType(From, ToType, CK_NoOp, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -3528,20 +3707,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, if (From->getType()->isObjCObjectPointerType() && ToType->isObjCObjectPointerType()) EmitRelatedResultTypeNote(From); - } + } else if (getLangOpts().ObjCAutoRefCount && - !CheckObjCARCUnavailableWeakConversion(ToType, + !CheckObjCARCUnavailableWeakConversion(ToType, From->getType())) { if (Action == AA_Initializing) - Diag(From->getLocStart(), + Diag(From->getLocStart(), diag::err_arc_weak_unavailable_assign); else Diag(From->getLocStart(), - diag::err_arc_convesion_of_weak_unavailable) - << (Action == AA_Casting) << From->getType() << ToType + diag::err_arc_convesion_of_weak_unavailable) + << (Action == AA_Casting) << From->getType() << ToType << From->getSourceRange(); } - + CastKind Kind = CK_Invalid; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) @@ -3589,7 +3768,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } From = ImpCastExprToType(From, Context.BoolTy, - ScalarTypeToBooleanCastKind(FromType), + ScalarTypeToBooleanCastKind(FromType), VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -3610,7 +3789,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } case ICK_Vector_Conversion: - From = ImpCastExprToType(From, ToType, CK_BitCast, + From = ImpCastExprToType(From, ToType, CK_BitCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -3655,7 +3834,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // _Complex x -> x From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_FloatingComplexToReal - : CK_IntegralComplexToReal, + : CK_IntegralComplexToReal, VK_RValue, /*BasePath=*/nullptr, CCK).get(); // x -> y @@ -3663,23 +3842,23 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // do nothing } else if (ToType->isRealFloatingType()) { From = ImpCastExprToType(From, ToType, - isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating, + isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } else { assert(ToType->isIntegerType()); From = ImpCastExprToType(From, ToType, - isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast, + isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } } break; - + case ICK_Block_Pointer_Conversion: { From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } - + case ICK_TransparentUnionConversion: { ExprResult FromRes = From; Sema::AssignConvertType ConvTy = @@ -3699,12 +3878,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, From->getValueKind()).get(); break; + case ICK_Zero_Queue_Conversion: + From = ImpCastExprToType(From, ToType, + CK_ZeroToOCLQueue, + From->getValueKind()).get(); + break; + case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: + case ICK_Function_Conversion: case ICK_Qualification: case ICK_Num_Conversion_Kinds: case ICK_C_Only_Conversion: + case ICK_Incompatible_Pointer_Conversion: llvm_unreachable("Improper second standard conversion"); } @@ -3713,6 +3900,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Nothing to do. break; + case ICK_Function_Conversion: + // If both sides are functions (or pointers/references to them), there could + // be incompatible exception declarations. + if (CheckExceptionSpecCompatibility(From, ToType)) + return ExprError(); + + From = ImpCastExprToType(From, ToType, CK_NoOp, + VK_RValue, /*BasePath=*/nullptr, CCK).get(); + break; + case ICK_Qualification: { // The qualification keeps the category of the inner expression, unless the // target type isn't a reference. @@ -3882,8 +4079,8 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, Sema &Self, SourceLocation KeyLoc, ASTContext &C, - bool (CXXRecordDecl::*HasTrivial)() const, - bool (CXXRecordDecl::*HasNonTrivial)() const, + bool (CXXRecordDecl::*HasTrivial)() const, + bool (CXXRecordDecl::*HasNonTrivial)() const, bool (CXXMethodDecl::*IsDesiredOp)() const) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); @@ -3979,7 +4176,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return false; } } - + return T->isScalarType(); case UTT_IsCompound: return T->isCompoundType(); @@ -4158,12 +4355,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, // false. if (T.isPODType(C) || T->isReferenceType()) return true; - + // Objective-C++ ARC: autorelease types don't require destruction. - if (T->isObjCLifetimeType() && + if (T->isObjCLifetimeType() && T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) return true; - + if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialDestructor(); return false; @@ -4345,9 +4542,9 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, // definition for is_constructible, as defined below, is known to call // no operation that is not trivial. // - // The predicate condition for a template specialization - // is_constructible<T, Args...> shall be satisfied if and only if the - // following variable definition would be well-formed for some invented + // The predicate condition for a template specialization + // is_constructible<T, Args...> shall be satisfied if and only if the + // following variable definition would be well-formed for some invented // variable t: // // T t(create<Args>()...); @@ -4361,7 +4558,7 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType()) continue; - if (S.RequireCompleteType(KWLoc, ArgTy, + if (S.RequireCompleteType(KWLoc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr)) return false; } @@ -4391,7 +4588,7 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, for (Expr &E : OpaqueArgExprs) ArgExprs.push_back(&E); - // Perform the initialization in an unevaluated context within a SFINAE + // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); @@ -4430,12 +4627,12 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, } default: llvm_unreachable("not a TT"); } - + return false; } -ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, - ArrayRef<TypeSourceInfo *> Args, +ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<TypeSourceInfo *> Args, SourceLocation RParenLoc) { QualType ResultType = Context.getLogicalOperationType(); @@ -4464,14 +4661,14 @@ ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, SourceLocation RParenLoc) { SmallVector<TypeSourceInfo *, 4> ConvertedArgs; ConvertedArgs.reserve(Args.size()); - + for (unsigned I = 0, N = Args.size(); I != N; ++I) { TypeSourceInfo *TInfo; QualType T = GetTypeFromParser(Args[I], &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, KWLoc); - - ConvertedArgs.push_back(TInfo); + + ConvertedArgs.push_back(TInfo); } return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc); @@ -4505,7 +4702,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // If Base and Derived are class types and are different types // (ignoring possible cv-qualifiers) then Derived shall be a // complete type. - if (Self.RequireCompleteType(KeyLoc, RhsT, + if (Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; @@ -4522,21 +4719,21 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // C++0x [meta.rel]p4: // Given the following function prototype: // - // template <class T> + // template <class T> // typename add_rvalue_reference<T>::type create(); // - // the predicate condition for a template specialization - // is_convertible<From, To> shall be satisfied if and only if - // the return expression in the following code would be + // the predicate condition for a template specialization + // is_convertible<From, To> shall be satisfied if and only if + // the return expression in the following code would be // well-formed, including any implicit conversions to the return // type of the function: // - // To test() { + // To test() { // return create<From>(); // } // - // Access checking is performed as if in a context unrelated to To and - // From. Only the validity of the immediate context of the expression + // Access checking is performed as if in a context unrelated to To and + // From. Only the validity of the immediate context of the expression // of the return-statement (including conversions to the return type) // is considered. // @@ -4565,10 +4762,10 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, OpaqueValueExpr From(KeyLoc, LhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(LhsT)); Expr *FromPtr = &From; - InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, + InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, SourceLocation())); - - // Perform the initialization in an unevaluated context within a SFINAE + + // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); @@ -4590,17 +4787,17 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // is_assignable, is known to call no operation that is not trivial // // is_assignable is defined as: - // The expression declval<T>() = declval<U>() is well-formed when + // The expression declval<T>() = declval<U>() is well-formed when // treated as an unevaluated operand (Clause 5). // - // For both, T and U shall be complete types, (possibly cv-qualified) + // For both, T and U shall be complete types, (possibly cv-qualified) // void, or arrays of unknown bound. if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, LhsT, + Self.RequireCompleteType(KeyLoc, LhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, RhsT, + Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; @@ -4608,7 +4805,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, if (LhsT->isVoidType() || RhsT->isVoidType()) return false; - // Build expressions that emulate the effect of declval<T>() and + // Build expressions that emulate the effect of declval<T>() and // declval<U>(). if (LhsT->isObjectType() || LhsT->isFunctionType()) LhsT = Self.Context.getRValueReferenceType(LhsT); @@ -4618,8 +4815,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, Expr::getValueKindForType(LhsT)); OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(RhsT)); - - // Attempt the assignment in an unevaluated context within a SFINAE + + // Attempt the assignment in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); @@ -4789,11 +4986,14 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, !RHS.get()->getType()->isPlaceholderType() && "placeholders should have been weeded out by now"); - // The LHS undergoes lvalue conversions if this is ->*. - if (isIndirect) { + // The LHS undergoes lvalue conversions if this is ->*, and undergoes the + // temporary materialization conversion otherwise. + if (isIndirect) LHS = DefaultLvalueConversion(LHS.get()); - if (LHS.isInvalid()) return QualType(); - } + else if (LHS.get()->isRValue()) + LHS = TemporaryMaterializationConversion(LHS.get()); + if (LHS.isInvalid()) + return QualType(); // The RHS always undergoes lvalue conversions. RHS = DefaultLvalueConversion(RHS.get()); @@ -5005,8 +5205,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // // This actually refers very narrowly to the lvalue-to-rvalue conversion, not // to the array-to-pointer or function-to-pointer conversions. - if (!TTy->getAs<TagType>()) - TTy = TTy.getUnqualifiedType(); + TTy = TTy.getNonLValueExprType(Self.Context); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, From); @@ -5052,7 +5251,7 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS Self.MarkFunctionReferenced(QuestionLoc, Best->Function); return false; } - + case OR_No_Viable_Function: // Emit a better diagnostic if one of the expressions is a null pointer @@ -5199,23 +5398,35 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // if both are glvalues of the same value category and the same type except // for cv-qualification, an attempt is made to convert each of those // operands to the type of the other. + // FIXME: + // Resolving a defect in P0012R1: we extend this to cover all cases where + // one of the operands is reference-compatible with the other, in order + // to support conditionals between functions differing in noexcept. ExprValueKind LVK = LHS.get()->getValueKind(); ExprValueKind RVK = RHS.get()->getValueKind(); if (!Context.hasSameType(LTy, RTy) && - Context.hasSameUnqualifiedType(LTy, RTy) && LVK == RVK && LVK != VK_RValue) { - // Since the unqualified types are reference-related and we require the - // result to be as if a reference bound directly, the only conversion - // we can perform is to add cv-qualifiers. - Qualifiers LCVR = Qualifiers::fromCVRMask(LTy.getCVRQualifiers()); - Qualifiers RCVR = Qualifiers::fromCVRMask(RTy.getCVRQualifiers()); - if (RCVR.isStrictSupersetOf(LCVR)) { - LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK); - LTy = LHS.get()->getType(); - } - else if (LCVR.isStrictSupersetOf(RCVR)) { + // DerivedToBase was already handled by the class-specific case above. + // FIXME: Should we allow ObjC conversions here? + bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion; + if (CompareReferenceRelationship( + QuestionLoc, LTy, RTy, DerivedToBase, + ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible && + !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion && + // [...] subject to the constraint that the reference must bind + // directly [...] + !RHS.get()->refersToBitField() && + !RHS.get()->refersToVectorElement()) { RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK); RTy = RHS.get()->getType(); + } else if (CompareReferenceRelationship( + QuestionLoc, RTy, LTy, DerivedToBase, + ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible && + !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion && + !LHS.get()->refersToBitField() && + !LHS.get()->refersToVectorElement()) { + LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK); + LTy = LHS.get()->getType(); } } @@ -5234,6 +5445,20 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (LHS.get()->getObjectKind() == OK_BitField || RHS.get()->getObjectKind() == OK_BitField) OK = OK_BitField; + + // If we have function pointer types, unify them anyway to unify their + // exception specifications, if any. + if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { + Qualifiers Qs = LTy.getQualifiers(); + LTy = FindCompositePointerType(QuestionLoc, LHS, RHS, + /*ConvertArgs*/false); + LTy = Context.getQualifiedType(LTy, Qs); + + assert(!LTy.isNull() && "failed to find composite pointer type for " + "canonically equivalent function ptr types"); + assert(Context.hasSameType(LTy, RTy) && "bad composite pointer type"); + } + return LTy; } @@ -5267,9 +5492,6 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. - if (RequireNonAbstractType(QuestionLoc, LTy, - diag::err_allocation_of_abstract_type)) - return QualType(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); ExprResult LHSCopy = PerformCopyInitialization(Entity, @@ -5288,6 +5510,14 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, RHS = RHSCopy; } + // If we have function pointer types, unify them anyway to unify their + // exception specifications, if any. + if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { + LTy = FindCompositePointerType(QuestionLoc, LHS, RHS); + assert(!LTy.isNull() && "failed to find composite pointer type for " + "canonically equivalent function ptr types"); + } + return LTy; } @@ -5329,19 +5559,9 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // performed to bring them to a common type, whose cv-qualification // shall match the cv-qualification of either the second or the third // operand. The result is of the common type. - bool NonStandardCompositeType = false; - QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS, - isSFINAEContext() ? nullptr - : &NonStandardCompositeType); - if (!Composite.isNull()) { - if (NonStandardCompositeType) - Diag(QuestionLoc, - diag::ext_typecheck_cond_incompatible_operands_nonstandard) - << LTy << RTy << Composite - << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - + QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS); + if (!Composite.isNull()) return Composite; - } // Similarly, attempt to find composite type of two objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); @@ -5358,90 +5578,176 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, return QualType(); } +static FunctionProtoType::ExceptionSpecInfo +mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, + FunctionProtoType::ExceptionSpecInfo ESI2, + SmallVectorImpl<QualType> &ExceptionTypeStorage) { + ExceptionSpecificationType EST1 = ESI1.Type; + ExceptionSpecificationType EST2 = ESI2.Type; + + // If either of them can throw anything, that is the result. + if (EST1 == EST_None) return ESI1; + if (EST2 == EST_None) return ESI2; + if (EST1 == EST_MSAny) return ESI1; + if (EST2 == EST_MSAny) return ESI2; + + // If either of them is non-throwing, the result is the other. + if (EST1 == EST_DynamicNone) return ESI2; + if (EST2 == EST_DynamicNone) return ESI1; + if (EST1 == EST_BasicNoexcept) return ESI2; + if (EST2 == EST_BasicNoexcept) return ESI1; + + // If either of them is a non-value-dependent computed noexcept, that + // determines the result. + if (EST2 == EST_ComputedNoexcept && ESI2.NoexceptExpr && + !ESI2.NoexceptExpr->isValueDependent()) + return !ESI2.NoexceptExpr->EvaluateKnownConstInt(S.Context) ? ESI2 : ESI1; + if (EST1 == EST_ComputedNoexcept && ESI1.NoexceptExpr && + !ESI1.NoexceptExpr->isValueDependent()) + return !ESI1.NoexceptExpr->EvaluateKnownConstInt(S.Context) ? ESI1 : ESI2; + // If we're left with value-dependent computed noexcept expressions, we're + // stuck. Before C++17, we can just drop the exception specification entirely, + // since it's not actually part of the canonical type. And this should never + // happen in C++17, because it would mean we were computing the composite + // pointer type of dependent types, which should never happen. + if (EST1 == EST_ComputedNoexcept || EST2 == EST_ComputedNoexcept) { + assert(!S.getLangOpts().CPlusPlus1z && + "computing composite pointer type of dependent types"); + return FunctionProtoType::ExceptionSpecInfo(); + } + + // Switch over the possibilities so that people adding new values know to + // update this function. + switch (EST1) { + case EST_None: + case EST_DynamicNone: + case EST_MSAny: + case EST_BasicNoexcept: + case EST_ComputedNoexcept: + llvm_unreachable("handled above"); + + case EST_Dynamic: { + // This is the fun case: both exception specifications are dynamic. Form + // the union of the two lists. + assert(EST2 == EST_Dynamic && "other cases should already be handled"); + llvm::SmallPtrSet<QualType, 8> Found; + for (auto &Exceptions : {ESI1.Exceptions, ESI2.Exceptions}) + for (QualType E : Exceptions) + if (Found.insert(S.Context.getCanonicalType(E)).second) + ExceptionTypeStorage.push_back(E); + + FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic); + Result.Exceptions = ExceptionTypeStorage; + return Result; + } + + case EST_Unevaluated: + case EST_Uninstantiated: + case EST_Unparsed: + llvm_unreachable("shouldn't see unresolved exception specifications here"); + } + + llvm_unreachable("invalid ExceptionSpecificationType"); +} + /// \brief Find a merged pointer type and convert the two expressions to it. /// /// This finds the composite pointer type (or member pointer type) for @p E1 -/// and @p E2 according to C++11 5.9p2. It converts both expressions to this +/// and @p E2 according to C++1z 5p14. It converts both expressions to this /// type and returns it. /// It does not emit diagnostics. /// /// \param Loc The location of the operator requiring these two expressions to /// be converted to the composite pointer type. /// -/// If \p NonStandardCompositeType is non-NULL, then we are permitted to find -/// a non-standard (but still sane) composite type to which both expressions -/// can be converted. When such a type is chosen, \c *NonStandardCompositeType -/// will be set true. +/// \param ConvertArgs If \c false, do not convert E1 and E2 to the target type. QualType Sema::FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, - bool *NonStandardCompositeType) { - if (NonStandardCompositeType) - *NonStandardCompositeType = false; - + bool ConvertArgs) { assert(getLangOpts().CPlusPlus && "This function assumes C++"); + + // C++1z [expr]p14: + // The composite pointer type of two operands p1 and p2 having types T1 + // and T2 QualType T1 = E1->getType(), T2 = E2->getType(); - // C++11 5.9p2 - // Pointer conversions and qualification conversions are performed on - // pointer operands to bring them to their composite pointer type. If - // one operand is a null pointer constant, the composite pointer type is - // std::nullptr_t if the other operand is also a null pointer constant or, - // if the other operand is a pointer, the type of the other operand. - if (!T1->isAnyPointerType() && !T1->isMemberPointerType() && - !T2->isAnyPointerType() && !T2->isMemberPointerType()) { - if (T1->isNullPtrType() && - E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).get(); - return T1; - } - if (T2->isNullPtrType() && - E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).get(); - return T2; - } + // where at least one is a pointer or pointer to member type or + // std::nullptr_t is: + bool T1IsPointerLike = T1->isAnyPointerType() || T1->isMemberPointerType() || + T1->isNullPtrType(); + bool T2IsPointerLike = T2->isAnyPointerType() || T2->isMemberPointerType() || + T2->isNullPtrType(); + if (!T1IsPointerLike && !T2IsPointerLike) return QualType(); - } - if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - if (T2->isMemberPointerType()) - E1 = ImpCastExprToType(E1, T2, CK_NullToMemberPointer).get(); - else - E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).get(); - return T2; - } - if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - if (T1->isMemberPointerType()) - E2 = ImpCastExprToType(E2, T1, CK_NullToMemberPointer).get(); - else - E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).get(); + // - if both p1 and p2 are null pointer constants, std::nullptr_t; + // This can't actually happen, following the standard, but we also use this + // to implement the end of [expr.conv], which hits this case. + // + // - if either p1 or p2 is a null pointer constant, T2 or T1, respectively; + if (T1IsPointerLike && + E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { + if (ConvertArgs) + E2 = ImpCastExprToType(E2, T1, T1->isMemberPointerType() + ? CK_NullToMemberPointer + : CK_NullToPointer).get(); return T1; } + if (T2IsPointerLike && + E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { + if (ConvertArgs) + E1 = ImpCastExprToType(E1, T2, T2->isMemberPointerType() + ? CK_NullToMemberPointer + : CK_NullToPointer).get(); + return T2; + } // Now both have to be pointers or member pointers. - if ((!T1->isPointerType() && !T1->isMemberPointerType()) || - (!T2->isPointerType() && !T2->isMemberPointerType())) + if (!T1IsPointerLike || !T2IsPointerLike) return QualType(); - - // Otherwise, of one of the operands has type "pointer to cv1 void," then - // the other has type "pointer to cv2 T" and the composite pointer type is - // "pointer to cv12 void," where cv12 is the union of cv1 and cv2. - // Otherwise, the composite pointer type is a pointer type similar to the - // type of one of the operands, with a cv-qualification signature that is - // the union of the cv-qualification signatures of the operand types. - // In practice, the first part here is redundant; it's subsumed by the second. - // What we do here is, we build the two possible composite types, and try the - // conversions in both directions. If only one works, or if the two composite - // types are the same, we have succeeded. + assert(!T1->isNullPtrType() && !T2->isNullPtrType() && + "nullptr_t should be a null pointer constant"); + + // - if T1 or T2 is "pointer to cv1 void" and the other type is + // "pointer to cv2 T", "pointer to cv12 void", where cv12 is + // the union of cv1 and cv2; + // - if T1 or T2 is "pointer to noexcept function" and the other type is + // "pointer to function", where the function types are otherwise the same, + // "pointer to function"; + // FIXME: This rule is defective: it should also permit removing noexcept + // from a pointer to member function. As a Clang extension, we also + // permit removing 'noreturn', so we generalize this rule to; + // - [Clang] If T1 and T2 are both of type "pointer to function" or + // "pointer to member function" and the pointee types can be unified + // by a function pointer conversion, that conversion is applied + // before checking the following rules. + // - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1 + // is reference-related to C2 or C2 is reference-related to C1 (8.6.3), + // the cv-combined type of T1 and T2 or the cv-combined type of T2 and T1, + // respectively; + // - if T1 is "pointer to member of C1 of type cv1 U1" and T2 is "pointer + // to member of C2 of type cv2 U2" where C1 is reference-related to C2 or + // C2 is reference-related to C1 (8.6.3), the cv-combined type of T2 and + // T1 or the cv-combined type of T1 and T2, respectively; + // - if T1 and T2 are similar types (4.5), the cv-combined type of T1 and + // T2; + // + // If looked at in the right way, these bullets all do the same thing. + // What we do here is, we build the two possible cv-combined types, and try + // the conversions in both directions. If only one works, or if the two + // composite types are the same, we have succeeded. // FIXME: extended qualifiers? - typedef SmallVector<unsigned, 4> QualifierVector; - QualifierVector QualifierUnion; - typedef SmallVector<std::pair<const Type *, const Type *>, 4> - ContainingClassVector; - ContainingClassVector MemberOfClass; - QualType Composite1 = Context.getCanonicalType(T1), - Composite2 = Context.getCanonicalType(T2); + // + // Note that this will fail to find a composite pointer type for "pointer + // to void" and "pointer to function". We can't actually perform the final + // conversion in this case, even though a composite pointer type formally + // exists. + SmallVector<unsigned, 4> QualifierUnion; + SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass; + QualType Composite1 = T1; + QualType Composite2 = T2; unsigned NeedConstBefore = 0; - do { + while (true) { const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs<PointerType>()) && (Ptr2 = Composite2->getAs<PointerType>())) { @@ -5450,8 +5756,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // If we're allowed to create a non-standard composite type, keep track // of where we need to fill in additional 'const' qualifiers. - if (NonStandardCompositeType && - Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) + if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); QualifierUnion.push_back( @@ -5468,8 +5773,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // If we're allowed to create a non-standard composite type, keep track // of where we need to fill in additional 'const' qualifiers. - if (NonStandardCompositeType && - Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) + if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); QualifierUnion.push_back( @@ -5483,109 +5787,125 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // Cannot unwrap any more types. break; - } while (true); + } - if (NeedConstBefore && NonStandardCompositeType) { + // Apply the function pointer conversion to unify the types. We've already + // unwrapped down to the function types, and we want to merge rather than + // just convert, so do this ourselves rather than calling + // IsFunctionConversion. + // + // FIXME: In order to match the standard wording as closely as possible, we + // currently only do this under a single level of pointers. Ideally, we would + // allow this in general, and set NeedConstBefore to the relevant depth on + // the side(s) where we changed anything. + if (QualifierUnion.size() == 1) { + if (auto *FPT1 = Composite1->getAs<FunctionProtoType>()) { + if (auto *FPT2 = Composite2->getAs<FunctionProtoType>()) { + FunctionProtoType::ExtProtoInfo EPI1 = FPT1->getExtProtoInfo(); + FunctionProtoType::ExtProtoInfo EPI2 = FPT2->getExtProtoInfo(); + + // The result is noreturn if both operands are. + bool Noreturn = + EPI1.ExtInfo.getNoReturn() && EPI2.ExtInfo.getNoReturn(); + EPI1.ExtInfo = EPI1.ExtInfo.withNoReturn(Noreturn); + EPI2.ExtInfo = EPI2.ExtInfo.withNoReturn(Noreturn); + + // The result is nothrow if both operands are. + SmallVector<QualType, 8> ExceptionTypeStorage; + EPI1.ExceptionSpec = EPI2.ExceptionSpec = + mergeExceptionSpecs(*this, EPI1.ExceptionSpec, EPI2.ExceptionSpec, + ExceptionTypeStorage); + + Composite1 = Context.getFunctionType(FPT1->getReturnType(), + FPT1->getParamTypes(), EPI1); + Composite2 = Context.getFunctionType(FPT2->getReturnType(), + FPT2->getParamTypes(), EPI2); + } + } + } + + if (NeedConstBefore) { // Extension: Add 'const' to qualifiers that come before the first qualifier // mismatch, so that our (non-standard!) composite type meets the // requirements of C++ [conv.qual]p4 bullet 3. - for (unsigned I = 0; I != NeedConstBefore; ++I) { - if ((QualifierUnion[I] & Qualifiers::Const) == 0) { + for (unsigned I = 0; I != NeedConstBefore; ++I) + if ((QualifierUnion[I] & Qualifiers::Const) == 0) QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const; - *NonStandardCompositeType = true; - } - } } // Rewrap the composites as pointers or member pointers with the union CVRs. - ContainingClassVector::reverse_iterator MOC - = MemberOfClass.rbegin(); - for (QualifierVector::reverse_iterator - I = QualifierUnion.rbegin(), - E = QualifierUnion.rend(); - I != E; (void)++I, ++MOC) { - Qualifiers Quals = Qualifiers::fromCVRMask(*I); - if (MOC->first && MOC->second) { + auto MOC = MemberOfClass.rbegin(); + for (unsigned CVR : llvm::reverse(QualifierUnion)) { + Qualifiers Quals = Qualifiers::fromCVRMask(CVR); + auto Classes = *MOC++; + if (Classes.first && Classes.second) { // Rebuild member pointer type Composite1 = Context.getMemberPointerType( - Context.getQualifiedType(Composite1, Quals), - MOC->first); + Context.getQualifiedType(Composite1, Quals), Classes.first); Composite2 = Context.getMemberPointerType( - Context.getQualifiedType(Composite2, Quals), - MOC->second); + Context.getQualifiedType(Composite2, Quals), Classes.second); } else { // Rebuild pointer type - Composite1 - = Context.getPointerType(Context.getQualifiedType(Composite1, Quals)); - Composite2 - = Context.getPointerType(Context.getQualifiedType(Composite2, Quals)); + Composite1 = + Context.getPointerType(Context.getQualifiedType(Composite1, Quals)); + Composite2 = + Context.getPointerType(Context.getQualifiedType(Composite2, Quals)); } } - // Try to convert to the first composite pointer type. - InitializedEntity Entity1 - = InitializedEntity::InitializeTemporary(Composite1); - InitializationKind Kind - = InitializationKind::CreateCopy(Loc, SourceLocation()); - InitializationSequence E1ToC1(*this, Entity1, Kind, E1); - InitializationSequence E2ToC1(*this, Entity1, Kind, E2); - - if (E1ToC1 && E2ToC1) { - // Conversion to Composite1 is viable. - if (!Context.hasSameType(Composite1, Composite2)) { - // Composite2 is a different type from Composite1. Check whether - // Composite2 is also viable. - InitializedEntity Entity2 - = InitializedEntity::InitializeTemporary(Composite2); - InitializationSequence E1ToC2(*this, Entity2, Kind, E1); - InitializationSequence E2ToC2(*this, Entity2, Kind, E2); - if (E1ToC2 && E2ToC2) { - // Both Composite1 and Composite2 are viable and are different; - // this is an ambiguity. - return QualType(); - } - } + struct Conversion { + Sema &S; + Expr *&E1, *&E2; + QualType Composite; + InitializedEntity Entity; + InitializationKind Kind; + InitializationSequence E1ToC, E2ToC; + bool Viable; + + Conversion(Sema &S, SourceLocation Loc, Expr *&E1, Expr *&E2, + QualType Composite) + : S(S), E1(E1), E2(E2), Composite(Composite), + Entity(InitializedEntity::InitializeTemporary(Composite)), + Kind(InitializationKind::CreateCopy(Loc, SourceLocation())), + E1ToC(S, Entity, Kind, E1), E2ToC(S, Entity, Kind, E2), + Viable(E1ToC && E2ToC) {} + + bool perform() { + ExprResult E1Result = E1ToC.Perform(S, Entity, Kind, E1); + if (E1Result.isInvalid()) + return true; + E1 = E1Result.getAs<Expr>(); - // Convert E1 to Composite1 - ExprResult E1Result - = E1ToC1.Perform(*this, Entity1, Kind, E1); - if (E1Result.isInvalid()) - return QualType(); - E1 = E1Result.getAs<Expr>(); + ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2); + if (E2Result.isInvalid()) + return true; + E2 = E2Result.getAs<Expr>(); - // Convert E2 to Composite1 - ExprResult E2Result - = E2ToC1.Perform(*this, Entity1, Kind, E2); - if (E2Result.isInvalid()) - return QualType(); - E2 = E2Result.getAs<Expr>(); + return false; + } + }; - return Composite1; + // Try to convert to each composite pointer type. + Conversion C1(*this, Loc, E1, E2, Composite1); + if (C1.Viable && Context.hasSameType(Composite1, Composite2)) { + if (ConvertArgs && C1.perform()) + return QualType(); + return C1.Composite; } + Conversion C2(*this, Loc, E1, E2, Composite2); - // Check whether Composite2 is viable. - InitializedEntity Entity2 - = InitializedEntity::InitializeTemporary(Composite2); - InitializationSequence E1ToC2(*this, Entity2, Kind, E1); - InitializationSequence E2ToC2(*this, Entity2, Kind, E2); - if (!E1ToC2 || !E2ToC2) + if (C1.Viable == C2.Viable) { + // Either Composite1 and Composite2 are viable and are different, or + // neither is viable. + // FIXME: How both be viable and different? return QualType(); + } - // Convert E1 to Composite2 - ExprResult E1Result - = E1ToC2.Perform(*this, Entity2, Kind, E1); - if (E1Result.isInvalid()) - return QualType(); - E1 = E1Result.getAs<Expr>(); - - // Convert E2 to Composite2 - ExprResult E2Result - = E2ToC2.Perform(*this, Entity2, Kind, E2); - if (E2Result.isInvalid()) + // Convert to the chosen type. + if (ConvertArgs && (C1.Viable ? C1 : C2).perform()) return QualType(); - E2 = E2Result.getAs<Expr>(); - return Composite2; + return C1.Viable ? C1.Composite : C2.Composite; } ExprResult Sema::MaybeBindToTemporary(Expr *E) { @@ -5618,14 +5938,14 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { else if (MemberExpr *Mem = dyn_cast<MemberExpr>(Callee)) T = Mem->getMemberDecl()->getType(); } - + if (const PointerType *Ptr = T->getAs<PointerType>()) T = Ptr->getPointeeType(); else if (const BlockPointerType *Ptr = T->getAs<BlockPointerType>()) T = Ptr->getPointeeType(); else if (const MemberPointerType *MemPtr = T->getAs<MemberPointerType>()) T = MemPtr->getPointeeType(); - + const FunctionType *FTy = T->getAs<FunctionType>(); assert(FTy && "call to value not of function type?"); ReturnsRetained = FTy->getExtInfo().getProducesResult(); @@ -6012,7 +6332,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, // so adjust the base type to the object type itself. if (BaseType->isObjCObjectPointerType()) BaseType = BaseType->getPointeeType(); - + // C++ [basic.lookup.classref]p2: // [...] If the type of the object expression is of pointer to scalar // type, the unqualified-id is looked up in the context of the complete @@ -6037,7 +6357,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, // The object type must be complete (or dependent), or // C++11 [expr.prim.general]p3: // Unlike the object expression in other contexts, *this is not required to - // be of complete type for purposes of class member access (5.2.5) outside + // be of complete type for purposes of class member access (5.2.5) outside // the member function body. if (!BaseType->isDependentType() && !isThisOutsideMemberFunctionBody(BaseType) && @@ -6053,7 +6373,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, return Base; } -static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base, +static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base, tok::TokenKind& OpKind, SourceLocation OpLoc) { if (Base->hasPlaceholderType()) { ExprResult result = S.CheckPlaceholderExpr(Base); @@ -6129,9 +6449,9 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); - } else if (DestructedType.getObjCLifetime() != + } else if (DestructedType.getObjCLifetime() != ObjectType.getObjCLifetime()) { - + if (DestructedType.getObjCLifetime() == Qualifiers::OCL_None) { // Okay: just pretend that the user provided the correctly-qualified // type. @@ -6140,7 +6460,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); } - + // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, @@ -6324,7 +6644,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, - SourceLocation TildeLoc, + SourceLocation TildeLoc, const DeclSpec& DS) { QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) @@ -6519,7 +6839,17 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { if (Res.isInvalid()) return E; E = Res.get(); - } + } + + // C++1z: + // If the expression is a prvalue after this optional conversion, the + // temporary materialization conversion is applied. + // + // We skip this step: IR generation is able to synthesize the storage for + // itself in the aggregate case, and adding the extra node to the AST is + // just clutter. + // FIXME: We don't emit lifetime markers for the temporaries due to this. + // FIXME: Do any other AST consumers care about this? return E; } @@ -6549,13 +6879,13 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { // we can unambiguously check if the variable is a constant expression. // - if the initializer is not value dependent - we can determine whether // it can be used to initialize a constant expression. If Init can not -// be used to initialize a constant expression we conclude that Var can +// be used to initialize a constant expression we conclude that Var can // never be a constant expression. // - FXIME: if the initializer is dependent, we can still do some analysis and // identify certain cases unambiguously as non-const by using a Visitor: // - such as those that involve odr-use of a ParmVarDecl, involve a new // delete, lambda-expr, dynamic-cast, reinterpret-cast etc... -static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, +static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, ASTContext &Context) { if (isa<ParmVarDecl>(Var)) return true; const VarDecl *DefVD = nullptr; @@ -6575,14 +6905,14 @@ static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, return false; } - return !IsVariableAConstantExpression(Var, Context); + return !IsVariableAConstantExpression(Var, Context); } -/// \brief Check if the current lambda has any potential captures -/// that must be captured by any of its enclosing lambdas that are ready to -/// capture. If there is a lambda that can capture a nested -/// potential-capture, go ahead and do so. Also, check to see if any -/// variables are uncaptureable or do not involve an odr-use so do not +/// \brief Check if the current lambda has any potential captures +/// that must be captured by any of its enclosing lambdas that are ready to +/// capture. If there is a lambda that can capture a nested +/// potential-capture, go ahead and do so. Also, check to see if any +/// variables are uncaptureable or do not involve an odr-use so do not /// need to be captured. static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( @@ -6603,7 +6933,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( ArrayRef<const FunctionScopeInfo *> FunctionScopesArrayRef( S.FunctionScopes.data(), S.FunctionScopes.size()); - + // All the potentially captureable variables in the current nested // lambda (within a generic outer lambda), must be captured by an // outer lambda that is enclosed within a non-dependent context. @@ -6614,7 +6944,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( VarDecl *Var = nullptr; CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr); // If the variable is clearly identified as non-odr-used and the full - // expression is not instantiation dependent, only then do we not + // expression is not instantiation dependent, only then do we not // need to check enclosing lambda's for speculative captures. // For e.g.: // Even though 'x' is not odr-used, it should be captured. @@ -6636,27 +6966,27 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue(); MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(), S, &FunctionScopeIndexOfCapturableLambda); - } - const bool IsVarNeverAConstantExpression = + } + const bool IsVarNeverAConstantExpression = VariableCanNeverBeAConstantExpression(Var, S.Context); if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) { // This full expression is not instantiation dependent or the variable - // can not be used in a constant expression - which means - // this variable must be odr-used here, so diagnose a + // can not be used in a constant expression - which means + // this variable must be odr-used here, so diagnose a // capture violation early, if the variable is un-captureable. // This is purely for diagnosing errors early. Otherwise, this // error would get diagnosed when the lambda becomes capture ready. QualType CaptureType, DeclRefType; SourceLocation ExprLoc = VarExpr->getExprLoc(); if (S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit, - /*EllipsisLoc*/ SourceLocation(), - /*BuildAndDiagnose*/false, CaptureType, + /*EllipsisLoc*/ SourceLocation(), + /*BuildAndDiagnose*/false, CaptureType, DeclRefType, nullptr)) { // We will never be able to capture this variable, and we need // to be able to in any and all instantiations, so diagnose it. S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit, - /*EllipsisLoc*/ SourceLocation(), - /*BuildAndDiagnose*/true, CaptureType, + /*EllipsisLoc*/ SourceLocation(), + /*BuildAndDiagnose*/true, CaptureType, DeclRefType, nullptr); } } @@ -6983,15 +7313,15 @@ Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, bool DiscardedValue, - bool IsConstexpr, + bool IsConstexpr, bool IsLambdaInitCaptureInitializer) { ExprResult FullExpr = FE; if (!FullExpr.get()) return ExprError(); - - // If we are an init-expression in a lambdas init-capture, we should not - // diagnose an unexpanded pack now (will be diagnosed once lambda-expr + + // If we are an init-expression in a lambdas init-capture, we should not + // diagnose an unexpanded pack now (will be diagnosed once lambda-expr // containing full-expression is done). // template<class ... Ts> void test(Ts ... t) { // test([&a(t)]() { <-- (t) is an init-expr that shouldn't be diagnosed now. @@ -7005,7 +7335,7 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, // lambda where we've entered the introducer but not the body, or represent a // lambda where we've entered the body, depending on where the // parser/instantiation has got to). - if (!IsLambdaInitCaptureInitializer && + if (!IsLambdaInitCaptureInitializer && DiagnoseUnexpandedParameterPack(FullExpr.get())) return ExprError(); @@ -7033,13 +7363,13 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr); - // At the end of this full expression (which could be a deeply nested - // lambda), if there is a potential capture within the nested lambda, + // At the end of this full expression (which could be a deeply nested + // lambda), if there is a potential capture within the nested lambda, // have the outer capture-able lambda try and capture it. // Consider the following code: // void f(int, int); // void f(const int&, double); - // void foo() { + // void foo() { // const int x = 10, y = 20; // auto L = [=](auto a) { // auto M = [=](auto b) { @@ -7049,35 +7379,35 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, // }; // } - // FIXME: Also consider what happens for something like this that involves - // the gnu-extension statement-expressions or even lambda-init-captures: + // FIXME: Also consider what happens for something like this that involves + // the gnu-extension statement-expressions or even lambda-init-captures: // void f() { // const int n = 0; // auto L = [&](auto a) { // +n + ({ 0; a; }); // }; // } - // - // Here, we see +n, and then the full-expression 0; ends, so we don't - // capture n (and instead remove it from our list of potential captures), - // and then the full-expression +n + ({ 0; }); ends, but it's too late + // + // Here, we see +n, and then the full-expression 0; ends, so we don't + // capture n (and instead remove it from our list of potential captures), + // and then the full-expression +n + ({ 0; }); ends, but it's too late // for us to see that we need to capture n after all. LambdaScopeInfo *const CurrentLSI = getCurLambda(/*IgnoreCapturedRegions=*/true); - // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer + // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer // even if CurContext is not a lambda call operator. Refer to that Bug Report - // for an example of the code that might cause this asynchrony. + // for an example of the code that might cause this asynchrony. // By ensuring we are in the context of a lambda's call operator // we can fix the bug (we only need to check whether we need to capture - // if we are within a lambda's body); but per the comments in that + // if we are within a lambda's body); but per the comments in that // PR, a proper fix would entail : // "Alternative suggestion: - // - Add to Sema an integer holding the smallest (outermost) scope - // index that we are *lexically* within, and save/restore/set to - // FunctionScopes.size() in InstantiatingTemplate's + // - Add to Sema an integer holding the smallest (outermost) scope + // index that we are *lexically* within, and save/restore/set to + // FunctionScopes.size() in InstantiatingTemplate's // constructor/destructor. - // - Teach the handful of places that iterate over FunctionScopes to + // - Teach the handful of places that iterate over FunctionScopes to // stop at the outermost enclosing lexical scope." DeclContext *DC = CurContext; while (DC && isa<CapturedDecl>(DC)) @@ -7096,34 +7426,34 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { return MaybeCreateStmtWithCleanups(FullStmt); } -Sema::IfExistsResult +Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, const DeclarationNameInfo &TargetNameInfo) { DeclarationName TargetName = TargetNameInfo.getName(); if (!TargetName) return IER_DoesNotExist; - + // If the name itself is dependent, then the result is dependent. if (TargetName.isDependentName()) return IER_Dependent; - + // Do the redeclaration lookup in the current scope. LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, Sema::NotForRedeclaration); LookupParsedName(R, S, &SS); R.suppressDiagnostics(); - + switch (R.getResultKind()) { case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: case LookupResult::Ambiguous: return IER_Exists; - + case LookupResult::NotFound: return IER_DoesNotExist; - + case LookupResult::NotFoundInCurrentInstantiation: return IER_Dependent; } @@ -7131,23 +7461,17 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, llvm_unreachable("Invalid LookupResult Kind!"); } -Sema::IfExistsResult +Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name) { DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); - - // Check for unexpanded parameter packs. - SmallVector<UnexpandedParameterPack, 4> Unexpanded; - collectUnexpandedParameterPacks(SS, Unexpanded); - collectUnexpandedParameterPacks(TargetNameInfo, Unexpanded); - if (!Unexpanded.empty()) { - DiagnoseUnexpandedParameterPacks(KeywordLoc, - IsIfExists? UPPC_IfExists - : UPPC_IfNotExists, - Unexpanded); + + // Check for an unexpanded parameter pack. + auto UPPC = IsIfExists ? UPPC_IfExists : UPPC_IfNotExists; + if (DiagnoseUnexpandedParameterPack(SS, UPPC) || + DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC)) return IER_Error; - } - + return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); } |