aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExprCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r--lib/Sema/SemaExprCXX.cpp345
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);