diff options
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 345 |
1 files changed, 207 insertions, 138 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 3afa95f7d1f2..d65570fcef76 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -323,20 +323,31 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, return nullptr; } -ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) { - if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType) - return nullptr; - 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); - } +ParsedType Sema::getDestructorTypeForDecltype(const DeclSpec &DS, + ParsedType ObjectType) { + if (DS.getTypeSpecType() == DeclSpec::TST_error) + return nullptr; + + if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto) { + Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); + return nullptr; + } + + assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && + "unexpected type in getDestructorType"); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + // If we know the type of the object, check that the correct destructor + // type was named now; we can give better diagnostics this way. + QualType SearchType = GetTypeFromParser(ObjectType); + if (!SearchType.isNull() && !SearchType->isDependentType() && + !Context.hasSameUnqualifiedType(T, SearchType)) { Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch) << T << SearchType; return nullptr; + } + + return ParsedType::make(T); } bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, @@ -448,7 +459,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, if (E->getType()->isVariablyModifiedType()) return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << E->getType()); - else if (ActiveTemplateInstantiations.empty() && + else if (!inTemplateInstantiation() && E->HasSideEffects(Context, WasEvaluated)) { // The expression operand for typeid is in an unevaluated expression // context, so side effects could result in unintended consequences. @@ -968,7 +979,7 @@ QualType Sema::getCurrentThisType() { } if (ThisTy.isNull() && isLambdaCallOperator(CurContext) && - !ActiveTemplateInstantiations.empty()) { + inTemplateInstantiation()) { assert(isa<CXXRecordDecl>(DC) && "Trying to get 'this' type from static method?"); @@ -1106,6 +1117,7 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) { if (CSI->CXXThisCaptureIndex != 0) { // 'this' is already being captured; there isn't anything more to do. + CSI->Captures[CSI->CXXThisCaptureIndex - 1].markUsed(BuildAndDiagnose); break; } LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI); @@ -1216,17 +1228,6 @@ 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 @@ -1255,58 +1256,79 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, } bool ListInitialization = LParenLoc.isInvalid(); - assert((!ListInitialization || (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) - && "List initialization must have initializer list as expression."); + assert((!ListInitialization || + (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) && + "List initialization must have initializer list as expression."); SourceRange FullRange = SourceRange(TyBeginLoc, ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc); + InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); + InitializationKind Kind = + Exprs.size() + ? ListInitialization + ? InitializationKind::CreateDirectList(TyBeginLoc) + : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, + RParenLoc) + : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); + + // C++1z [expr.type.conv]p1: + // If the type is a placeholder for a deduced class type, [...perform class + // template argument deduction...] + DeducedType *Deduced = Ty->getContainedDeducedType(); + if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) { + Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity, + Kind, Exprs); + if (Ty.isNull()) + return ExprError(); + Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); + } + // C++ [expr.type.conv]p1: - // If the expression list is a single expression, the type conversion - // expression is equivalent (in definedness, and if defined in meaning) to the - // corresponding cast expression. - if (Exprs.size() == 1 && !ListInitialization) { + // If the expression list is a parenthesized single expression, the type + // conversion expression is equivalent (in definedness, and if defined in + // meaning) to the corresponding cast expression. + if (Exprs.size() == 1 && !ListInitialization && + !isa<InitListExpr>(Exprs[0])) { Expr *Arg = Exprs[0]; - return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc); + return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenLoc, Arg, RParenLoc); } - // C++14 [expr.type.conv]p2: The expression T(), where T is a - // simple-type-specifier or typename-specifier for a non-array complete - // object type or the (possibly cv-qualified) void type, creates a prvalue - // of the specified type, whose value is that produced by value-initializing - // an object of type T. + // For an expression of the form T(), T shall not be an array type. QualType ElemTy = Ty; if (Ty->isArrayType()) { if (!ListInitialization) - return ExprError(Diag(TyBeginLoc, - diag::err_value_init_for_array_type) << FullRange); + return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_array_type) + << FullRange); ElemTy = Context.getBaseElementType(Ty); } - if (!ListInitialization && Ty->isFunctionType()) - return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_function_type) - << FullRange); + // There doesn't seem to be an explicit rule against this but sanity demands + // we only construct objects with object types. + if (Ty->isFunctionType()) + return ExprError(Diag(TyBeginLoc, diag::err_init_for_function_type) + << Ty << FullRange); + // C++17 [expr.type.conv]p2: + // If the type is cv void and the initializer is (), the expression is a + // prvalue of the specified type that performs no initialization. if (!Ty->isVoidType() && RequireCompleteType(TyBeginLoc, ElemTy, diag::err_invalid_incomplete_type_use, FullRange)) return ExprError(); - InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); - InitializationKind Kind = - Exprs.size() ? ListInitialization - ? InitializationKind::CreateDirectList(TyBeginLoc) - : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, RParenLoc) - : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); + // Otherwise, the expression is a prvalue of the specified type whose + // result object is direct-initialized (11.6) with the initializer. InitializationSequence InitSeq(*this, Entity, Kind, Exprs); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs); - if (Result.isInvalid() || !ListInitialization) + if (Result.isInvalid()) return Result; Expr *Inner = Result.get(); if (CXXBindTemporaryExpr *BTE = dyn_cast_or_null<CXXBindTemporaryExpr>(Inner)) Inner = BTE->getSubExpr(); - if (!isa<CXXTemporaryObjectExpr>(Inner)) { + if (!isa<CXXTemporaryObjectExpr>(Inner) && + !isa<CXXScalarValueInitExpr>(Inner)) { // If we created a CXXTemporaryObjectExpr, that node also represents the // functional cast. Otherwise, create an explicit cast to represent // the syntactic form of a functional-style cast that was used here. @@ -1317,7 +1339,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, // is sometimes handled by initialization and sometimes not. QualType ResultType = Result.get()->getType(); Result = CXXFunctionalCastExpr::Create( - Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo, + Context, ResultType, Expr::getValueKindForType(Ty), TInfo, CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc); } @@ -1509,7 +1531,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { DeclaratorChunk &Chunk = D.getTypeObject(0); - if (D.getDeclSpec().containsPlaceholderType()) + if (D.getDeclSpec().hasAutoTypeSpec()) return ExprError(Diag(Chunk.Loc, diag::err_new_array_of_auto) << D.getSourceRange()); if (Chunk.Arr.hasStatic) @@ -1562,20 +1584,8 @@ 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, @@ -1643,8 +1653,38 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, NumInits = List->getNumExprs(); } + // C++11 [expr.new]p15: + // A new-expression that creates an object of type T initializes that + // object as follows: + InitializationKind Kind + // - If the new-initializer is omitted, the object is default- + // initialized (8.5); if no initialization is performed, + // the object has indeterminate value + = initStyle == CXXNewExpr::NoInit + ? InitializationKind::CreateDefault(TypeRange.getBegin()) + // - Otherwise, the new-initializer is interpreted according to the + // initialization rules of 8.5 for direct-initialization. + : initStyle == CXXNewExpr::ListInit + ? InitializationKind::CreateDirectList(TypeRange.getBegin()) + : InitializationKind::CreateDirect(TypeRange.getBegin(), + DirectInitRange.getBegin(), + DirectInitRange.getEnd()); + // C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for. - if (AllocType->isUndeducedType()) { + auto *Deduced = AllocType->getContainedDeducedType(); + if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) { + if (ArraySize) + return ExprError(Diag(ArraySize->getExprLoc(), + diag::err_deduced_class_template_compound_type) + << /*array*/ 2 << ArraySize->getSourceRange()); + + InitializedEntity Entity + = InitializedEntity::InitializeNew(StartLoc, AllocType); + AllocType = DeduceTemplateSpecializationFromInitializer( + AllocTypeInfo, Entity, Kind, MultiExprArg(Inits, NumInits)); + if (AllocType.isNull()) + return ExprError(); + } else if (Deduced) { if (initStyle == CXXNewExpr::NoInit || NumInits == 0) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) << AllocType << TypeRange); @@ -1931,23 +1971,6 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, else InitType = AllocType; - // C++11 [expr.new]p15: - // A new-expression that creates an object of type T initializes that - // object as follows: - InitializationKind Kind - // - If the new-initializer is omitted, the object is default- - // initialized (8.5); if no initialization is performed, - // the object has indeterminate value - = initStyle == CXXNewExpr::NoInit - ? InitializationKind::CreateDefault(TypeRange.getBegin()) - // - Otherwise, the new-initializer is interpreted according to the - // initialization rules of 8.5 for direct-initialization. - : initStyle == CXXNewExpr::ListInit - ? InitializationKind::CreateDirectList(TypeRange.getBegin()) - : InitializationKind::CreateDirect(TypeRange.getBegin(), - DirectInitRange.getBegin(), - DirectInitRange.getEnd()); - InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, InitType); InitializationSequence InitSeq(*this, Entity, Kind, @@ -2025,9 +2048,10 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, else if (AllocType->isVariablyModifiedType()) return Diag(Loc, diag::err_variably_modified_new_type) << AllocType; - else if (unsigned AddressSpace = AllocType.getAddressSpace()) + else if (AllocType.getAddressSpace()) return Diag(Loc, diag::err_address_space_qualified_new) - << AllocType.getUnqualifiedType() << AddressSpace; + << AllocType.getUnqualifiedType() + << AllocType.getQualifiers().getAddressSpaceAttributePrintValue(); else if (getLangOpts().ObjCAutoRefCount) { if (const ArrayType *AT = Context.getAsArrayType(AllocType)) { QualType BaseAllocType = Context.getBaseElementType(AT); @@ -3094,10 +3118,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); QualType PointeeElem = Context.getBaseElementType(Pointee); - if (unsigned AddressSpace = Pointee.getAddressSpace()) + if (Pointee.getAddressSpace()) return Diag(Ex.get()->getLocStart(), diag::err_address_space_qualified_delete) - << Pointee.getUnqualifiedType() << AddressSpace; + << Pointee.getUnqualifiedType() + << Pointee.getQualifiers().getAddressSpaceAttributePrintValue(); CXXRecordDecl *PointeeRD = nullptr; if (Pointee->isVoidType() && !isSFINAEContext()) { @@ -3703,10 +3728,9 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, if (From->getType()->isObjCObjectPointerType() && ToType->isObjCObjectPointerType()) EmitRelatedResultTypeNote(From); - } - else if (getLangOpts().ObjCAutoRefCount && - !CheckObjCARCUnavailableWeakConversion(ToType, - From->getType())) { + } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && + !CheckObjCARCUnavailableWeakConversion(ToType, + From->getType())) { if (Action == AA_Initializing) Diag(From->getLocStart(), diag::err_arc_weak_unavailable_assign); @@ -3729,8 +3753,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, (void) PrepareCastToObjCObjectPointer(E); From = E.get(); } - if (getLangOpts().ObjCAutoRefCount) - CheckObjCARCConversion(SourceRange(), ToType, From, CCK); + if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) + CheckObjCConversion(SourceRange(), ToType, From, CCK); From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .get(); break; @@ -4033,6 +4057,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, // C++0x [meta.unary.prop] Table 49 requires the following traits to be // applied to a complete type. + case UTT_IsAggregate: case UTT_IsTrivial: case UTT_IsTriviallyCopyable: case UTT_IsStandardLayout: @@ -4207,6 +4232,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isAbstract(); return false; + case UTT_IsAggregate: + // Report vector extensions and complex types as aggregates because they + // support aggregate initialization. GCC mirrors this behavior for vectors + // but not _Complex. + return T->isAggregateType() || T->isVectorType() || T->isExtVectorType() || + T->isAnyComplexType(); // __is_interface_class only returns true when CL is invoked in /CLR mode and // even then only when it is used with the 'interface struct ...' syntax // Clang doesn't support /CLR which makes this type trait moot. @@ -4495,25 +4526,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, } } -/// \brief Determine whether T has a non-trivial Objective-C lifetime in -/// ARC mode. -static bool hasNontrivialObjCLifetime(QualType T) { - switch (T.getObjCLifetime()) { - case Qualifiers::OCL_ExplicitNone: - return false; - - case Qualifiers::OCL_Strong: - case Qualifiers::OCL_Weak: - case Qualifiers::OCL_Autoreleasing: - return true; - - case Qualifiers::OCL_None: - return T->isObjCLifetimeType(); - } - - llvm_unreachable("Unknown ObjC lifetime qualifier"); -} - static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, QualType RhsT, SourceLocation KeyLoc); @@ -4586,7 +4598,8 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. - EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::Unevaluated); Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); InitializedEntity To(InitializedEntity::InitializeTemporary(Args[0])); @@ -4607,10 +4620,9 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, return S.canThrow(Result.get()) == CT_Cannot; if (Kind == clang::TT_IsTriviallyConstructible) { - // Under Objective-C ARC, if the destination has non-trivial Objective-C - // lifetime, this is a non-trivial construction. - if (S.getLangOpts().ObjCAutoRefCount && - hasNontrivialObjCLifetime(T.getNonReferenceType())) + // Under Objective-C ARC and Weak, if the destination has non-trivial + // Objective-C lifetime, this is a non-trivial construction. + if (T.getNonReferenceType().hasNonTrivialObjCLifetime()) return false; // The initialization succeeded; now make sure there are no non-trivial @@ -4763,7 +4775,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. - EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated( + Self, Sema::ExpressionEvaluationContext::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); InitializationSequence Init(Self, To, Kind, FromPtr); @@ -4814,7 +4827,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // Attempt the assignment in an unevaluated context within a SFINAE // trap at translation unit scope. - EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated( + Self, Sema::ExpressionEvaluationContext::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs, @@ -4829,10 +4843,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, return Self.canThrow(Result.get()) == CT_Cannot; if (BTT == BTT_IsTriviallyAssignable) { - // Under Objective-C ARC, if the destination has non-trivial Objective-C - // lifetime, this is a non-trivial assignment. - if (Self.getLangOpts().ObjCAutoRefCount && - hasNontrivialObjCLifetime(LhsT.getNonReferenceType())) + // Under Objective-C ARC and Weak, if the destination has non-trivial + // Objective-C lifetime, this is a non-trivial assignment. + if (LhsT.getNonReferenceType().hasNonTrivialObjCLifetime()) return false; return !Result.get()->hasNonTrivialCall(Self.Context); @@ -5967,9 +5980,21 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { } else if (ObjCBoxedExpr *BoxedExpr = dyn_cast<ObjCBoxedExpr>(E)) { D = BoxedExpr->getBoxingMethod(); } else if (ObjCArrayLiteral *ArrayLit = dyn_cast<ObjCArrayLiteral>(E)) { + // Don't do reclaims if we're using the zero-element array + // constant. + if (ArrayLit->getNumElements() == 0 && + Context.getLangOpts().ObjCRuntime.hasEmptyCollections()) + return E; + D = ArrayLit->getArrayWithObjectsMethod(); } else if (ObjCDictionaryLiteral *DictLit = dyn_cast<ObjCDictionaryLiteral>(E)) { + // Don't do reclaims if we're using the zero-element dictionary + // constant. + if (DictLit->getNumElements() == 0 && + Context.getLangOpts().ObjCRuntime.hasEmptyCollections()) + return E; + D = DictLit->getDictWithObjectsMethod(); } @@ -6136,7 +6161,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { return E; return new (Context) BinaryOperator( BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(), - BO->getObjectKind(), BO->getOperatorLoc(), BO->isFPContractable()); + BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures()); } } @@ -6402,6 +6427,23 @@ static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base, return false; } +/// \brief Check if it's ok to try and recover dot pseudo destructor calls on +/// pointer objects. +static bool +canRecoverDotPseudoDestructorCallsOnPointerObjects(Sema &SemaRef, + QualType DestructedType) { + // If this is a record type, check if its destructor is callable. + if (auto *RD = DestructedType->getAsCXXRecordDecl()) { + if (CXXDestructorDecl *D = SemaRef.LookupDestructor(RD)) + return SemaRef.CanUseDecl(D, /*TreatUnavailableAsInvalid=*/false); + return false; + } + + // Otherwise, check if it's a type for which it's valid to use a pseudo-dtor. + return DestructedType->isDependentType() || DestructedType->isScalarType() || + DestructedType->isVectorType(); +} + ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, @@ -6436,15 +6478,36 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) { if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { - Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) - << ObjectType << DestructedType << Base->getSourceRange() - << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); - - // Recover by setting the destructed type to the object type. - DestructedType = ObjectType; - DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, - DestructedTypeStart); - Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + // Detect dot pseudo destructor calls on pointer objects, e.g.: + // Foo *foo; + // foo.~Foo(); + if (OpKind == tok::period && ObjectType->isPointerType() && + Context.hasSameUnqualifiedType(DestructedType, + ObjectType->getPointeeType())) { + auto Diagnostic = + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << ObjectType << /*IsArrow=*/0 << Base->getSourceRange(); + + // Issue a fixit only when the destructor is valid. + if (canRecoverDotPseudoDestructorCallsOnPointerObjects( + *this, DestructedType)) + Diagnostic << FixItHint::CreateReplacement(OpLoc, "->"); + + // Recover by setting the object type to the destructed type and the + // operator to '->'. + ObjectType = DestructedType; + OpKind = tok::arrow; + } else { + Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) + << ObjectType << DestructedType << Base->getSourceRange() + << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); + + // Recover by setting the destructed type to the object type. + DestructedType = ObjectType; + DestructedTypeInfo = + Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); + Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + } } else if (DestructedType.getObjCLifetime() != ObjectType.getObjCLifetime()) { @@ -6537,7 +6600,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { ParsedType T = getTypeName(*SecondTypeName.Identifier, SecondTypeName.StartLocation, - S, &SS, true, false, ObjectTypePtrForLookup); + S, &SS, true, false, ObjectTypePtrForLookup, + /*IsCtorOrDtorName*/true); if (!T && ((SS.isSet() && !computeDeclContext(SS, false)) || (!SS.isSet() && ObjectType->isDependentType()))) { @@ -6566,10 +6630,12 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, TypeResult T = ActOnTemplateIdType(TemplateId->SS, TemplateId->TemplateKWLoc, TemplateId->Template, + TemplateId->Name, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->RAngleLoc); + TemplateId->RAngleLoc, + /*IsCtorOrDtorName*/true); if (T.isInvalid() || !T.get()) { // Recover by assuming we had the right type all along. DestructedType = ObjectType; @@ -6594,7 +6660,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { ParsedType T = getTypeName(*FirstTypeName.Identifier, FirstTypeName.StartLocation, - S, &SS, true, false, ObjectTypePtrForLookup); + S, &SS, true, false, ObjectTypePtrForLookup, + /*IsCtorOrDtorName*/true); if (!T) { Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) @@ -6615,10 +6682,12 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, TypeResult T = ActOnTemplateIdType(TemplateId->SS, TemplateId->TemplateKWLoc, TemplateId->Template, + TemplateId->Name, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->RAngleLoc); + TemplateId->RAngleLoc, + /*IsCtorOrDtorName*/true); if (T.isInvalid() || !T.get()) { // Recover by dropping this type. ScopeType = QualType(); @@ -6681,7 +6750,8 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, // follows the normal lifetime rules for block literals instead of being // autoreleased. DiagnosticErrorTrap Trap(Diags); - PushExpressionEvaluationContext(PotentiallyEvaluated); + PushExpressionEvaluationContext( + ExpressionEvaluationContext::PotentiallyEvaluated); ExprResult Exp = BuildBlockForLambdaConversion(E->getExprLoc(), E->getExprLoc(), Method, E); @@ -6732,8 +6802,7 @@ ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, // The operand may have been modified when checking the placeholder type. Operand = R.get(); - if (ActiveTemplateInstantiations.empty() && - Operand->HasSideEffects(Context, false)) { + if (!inTemplateInstantiation() && Operand->HasSideEffects(Context, false)) { // The expression operand for noexcept is in an unevaluated expression // context, so side effects could result in unintended consequences. Diag(Operand->getExprLoc(), diag::warn_side_effects_unevaluated_context); |