Sema: Parenthesized bound destructor member expressions can be called

We would wrongfully reject (a.~A)() in both the destructor and
pseudo-destructor cases.

This fixes PR22668.

llvm-svn: 230512
This commit is contained in:
David Majnemer 2015-02-25 17:36:15 +00:00
parent 6cd04ac963
commit ced8bdf74a
24 changed files with 96 additions and 117 deletions

View File

@ -2276,7 +2276,7 @@ public:
/// getCallReturnType - Get the return type of the call expr. This is not
/// always the type of the expr itself, if the return type is a reference
/// type.
QualType getCallReturnType() const;
QualType getCallReturnType(const ASTContext &Ctx) const;
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }

View File

@ -5645,8 +5645,8 @@ def err_pseudo_dtor_type_mismatch : Error<
def err_pseudo_dtor_call_with_args : Error<
"call to pseudo-destructor cannot have any arguments">;
def err_dtor_expr_without_call : Error<
"%select{destructor reference|pseudo-destructor expression}0 must be "
"called immediately with '()'">;
"reference to %select{destructor|pseudo-destructor}0 must be called"
"%select{|; did you mean to call it with no arguments?}1">;
def err_pseudo_dtor_destructor_non_type : Error<
"%0 does not refer to a type name in pseudo-destructor expression; expected "
"the name of type %1">;

View File

@ -3665,7 +3665,6 @@ public:
Scope *S;
UnqualifiedId &Id;
Decl *ObjCImpDecl;
bool HasTrailingLParen;
};
ExprResult BuildMemberReferenceExpr(
@ -3704,8 +3703,7 @@ public:
CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &Member,
Decl *ObjCImpDecl,
bool HasTrailingLParen);
Decl *ObjCImpDecl);
void ActOnDefaultCtorInitializers(Decl *CDtorDecl);
bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
@ -4563,8 +4561,6 @@ public:
ParsedType &ObjectType,
bool &MayBePseudoDestructor);
ExprResult DiagnoseDtorReference(SourceLocation NameLoc, Expr *MemExpr);
ExprResult BuildPseudoDestructorExpr(Expr *Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
@ -4572,8 +4568,7 @@ public:
TypeSourceInfo *ScopeType,
SourceLocation CCLoc,
SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType,
bool HasTrailingLParen);
PseudoDestructorTypeStorage DestroyedType);
ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
SourceLocation OpLoc,
@ -4582,15 +4577,13 @@ public:
UnqualifiedId &FirstTypeName,
SourceLocation CCLoc,
SourceLocation TildeLoc,
UnqualifiedId &SecondTypeName,
bool HasTrailingLParen);
UnqualifiedId &SecondTypeName);
ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation TildeLoc,
const DeclSpec& DS,
bool HasTrailingLParen);
const DeclSpec& DS);
/// MaybeCreateExprWithCleanups - If the current full-expression
/// requires any cleanups, surround it with a ExprWithCleanups node.

View File

@ -1271,16 +1271,21 @@ bool CallExpr::isUnevaluatedBuiltinCall(ASTContext &Ctx) const {
return false;
}
QualType CallExpr::getCallReturnType() const {
QualType CalleeType = getCallee()->getType();
if (const PointerType *FnTypePtr = CalleeType->getAs<PointerType>())
QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const {
const Expr *Callee = getCallee();
QualType CalleeType = Callee->getType();
if (const auto *FnTypePtr = CalleeType->getAs<PointerType>()) {
CalleeType = FnTypePtr->getPointeeType();
else if (const BlockPointerType *BPT = CalleeType->getAs<BlockPointerType>())
} else if (const auto *BPT = CalleeType->getAs<BlockPointerType>()) {
CalleeType = BPT->getPointeeType();
else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember))
} else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember)) {
if (isa<CXXPseudoDestructorExpr>(Callee->IgnoreParens()))
return Ctx.VoidTy;
// This should never be overloaded and so should never return null.
CalleeType = Expr::findBoundMemberType(getCallee());
CalleeType = Expr::findBoundMemberType(Callee);
}
const FunctionType *FnType = CalleeType->castAs<FunctionType>();
return FnType->getReturnType();
}
@ -2170,8 +2175,8 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case OO_Greater:
case OO_GreaterEqual:
case OO_LessEqual:
if (Op->getCallReturnType()->isReferenceType() ||
Op->getCallReturnType()->isVoidType())
if (Op->getCallReturnType(Ctx)->isReferenceType() ||
Op->getCallReturnType(Ctx)->isVoidType())
break;
WarnE = this;
Loc = Op->getOperatorLoc();
@ -2423,7 +2428,7 @@ QualType Expr::findBoundMemberType(const Expr *expr) {
return type;
}
assert(isa<UnresolvedMemberExpr>(expr));
assert(isa<UnresolvedMemberExpr>(expr) || isa<CXXPseudoDestructorExpr>(expr));
return QualType();
}

View File

@ -238,10 +238,7 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context,
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
Context.getPointerType(Context.getFunctionType(
Context.VoidTy, None,
FunctionProtoType::ExtProtoInfo(
Context.getDefaultCallingConvention(false, true)))),
Context.BoundMemberTy,
VK_RValue, OK_Ordinary,
/*isTypeDependent=*/(Base->isTypeDependent() ||
(DestroyedType.getTypeSourceInfo() &&

View File

@ -283,7 +283,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXMemberCallExprClass:
case Expr::UserDefinedLiteralClass:
case Expr::CUDAKernelCallExprClass:
return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType());
return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType(Ctx));
// __builtin_choose_expr is equivalent to the chosen expression.
case Expr::ChooseExprClass:

View File

@ -2608,7 +2608,7 @@ Function *CodeGenFunction::LookupNeonLLVMIntrinsic(unsigned IntrinsicID,
// Return type.
SmallVector<llvm::Type *, 3> Tys;
if (Modifier & AddRetType) {
llvm::Type *Ty = ConvertType(E->getCallReturnType());
llvm::Type *Ty = ConvertType(E->getCallReturnType(getContext()));
if (Modifier & VectorizeRetType)
Ty = llvm::VectorType::get(
Ty, VectorSize ? VectorSize / Ty->getPrimitiveSizeInBits() : 1);
@ -4322,36 +4322,36 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vceqzs_f32:
Ops.push_back(EmitScalarExpr(E->getArg(0)));
return EmitAArch64CompareBuiltinExpr(
Ops[0], ConvertType(E->getCallReturnType()), ICmpInst::FCMP_OEQ,
ICmpInst::ICMP_EQ, "vceqz");
Ops[0], ConvertType(E->getCallReturnType(getContext())),
ICmpInst::FCMP_OEQ, ICmpInst::ICMP_EQ, "vceqz");
case NEON::BI__builtin_neon_vcgezd_s64:
case NEON::BI__builtin_neon_vcgezd_f64:
case NEON::BI__builtin_neon_vcgezs_f32:
Ops.push_back(EmitScalarExpr(E->getArg(0)));
return EmitAArch64CompareBuiltinExpr(
Ops[0], ConvertType(E->getCallReturnType()), ICmpInst::FCMP_OGE,
ICmpInst::ICMP_SGE, "vcgez");
Ops[0], ConvertType(E->getCallReturnType(getContext())),
ICmpInst::FCMP_OGE, ICmpInst::ICMP_SGE, "vcgez");
case NEON::BI__builtin_neon_vclezd_s64:
case NEON::BI__builtin_neon_vclezd_f64:
case NEON::BI__builtin_neon_vclezs_f32:
Ops.push_back(EmitScalarExpr(E->getArg(0)));
return EmitAArch64CompareBuiltinExpr(
Ops[0], ConvertType(E->getCallReturnType()), ICmpInst::FCMP_OLE,
ICmpInst::ICMP_SLE, "vclez");
Ops[0], ConvertType(E->getCallReturnType(getContext())),
ICmpInst::FCMP_OLE, ICmpInst::ICMP_SLE, "vclez");
case NEON::BI__builtin_neon_vcgtzd_s64:
case NEON::BI__builtin_neon_vcgtzd_f64:
case NEON::BI__builtin_neon_vcgtzs_f32:
Ops.push_back(EmitScalarExpr(E->getArg(0)));
return EmitAArch64CompareBuiltinExpr(
Ops[0], ConvertType(E->getCallReturnType()), ICmpInst::FCMP_OGT,
ICmpInst::ICMP_SGT, "vcgtz");
Ops[0], ConvertType(E->getCallReturnType(getContext())),
ICmpInst::FCMP_OGT, ICmpInst::ICMP_SGT, "vcgtz");
case NEON::BI__builtin_neon_vcltzd_s64:
case NEON::BI__builtin_neon_vcltzd_f64:
case NEON::BI__builtin_neon_vcltzs_f32:
Ops.push_back(EmitScalarExpr(E->getArg(0)));
return EmitAArch64CompareBuiltinExpr(
Ops[0], ConvertType(E->getCallReturnType()), ICmpInst::FCMP_OLT,
ICmpInst::ICMP_SLT, "vcltz");
Ops[0], ConvertType(E->getCallReturnType(getContext())),
ICmpInst::FCMP_OLT, ICmpInst::ICMP_SLT, "vcltz");
case NEON::BI__builtin_neon_vceqzd_u64: {
llvm::Type *Ty = llvm::Type::getInt64Ty(getLLVMContext());
@ -4803,7 +4803,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vfmad_lane_f64:
case NEON::BI__builtin_neon_vfmad_laneq_f64: {
Ops.push_back(EmitScalarExpr(E->getArg(3)));
llvm::Type *Ty = ConvertType(E->getCallReturnType());
llvm::Type *Ty = ConvertType(E->getCallReturnType(getContext()));
Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
Ops[2] = Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
return Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);

View File

@ -2205,7 +2205,7 @@ CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base,
// Check if this is a call expr that returns a record type.
if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
return CE->getCallReturnType()->isRecordType();
return CE->getCallReturnType(getContext())->isRecordType();
// We can't devirtualize the call.
return false;

View File

@ -3198,7 +3198,7 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
if (!RV.isScalar())
return MakeAddrLValue(RV.getAggregateAddr(), E->getType());
assert(E->getCallReturnType()->isReferenceType() &&
assert(E->getCallReturnType(getContext())->isReferenceType() &&
"Can't have a scalar return unless the return type is a "
"reference type!");

View File

@ -741,7 +741,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
}
void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
if (E->getCallReturnType()->isReferenceType()) {
if (E->getCallReturnType(CGF.getContext())->isReferenceType()) {
EmitAggLoadOfLValue(E);
return;
}

View File

@ -377,7 +377,7 @@ VisitImaginaryLiteral(const ImaginaryLiteral *IL) {
ComplexPairTy ComplexExprEmitter::VisitCallExpr(const CallExpr *E) {
if (E->getCallReturnType()->isReferenceType())
if (E->getCallReturnType(CGF.getContext())->isReferenceType())
return EmitLoadOfLValue(E);
return CGF.EmitCallExpr(E).getComplexVal();

View File

@ -320,7 +320,7 @@ public:
Value *VisitCastExpr(CastExpr *E);
Value *VisitCallExpr(const CallExpr *E) {
if (E->getCallReturnType()->isReferenceType())
if (E->getCallReturnType(CGF.getContext())->isReferenceType())
return EmitLoadOfLValue(E);
Value *V = CGF.EmitCallExpr(E).getScalarVal();

View File

@ -1566,8 +1566,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc,
OpKind, SS, TemplateKWLoc, Name,
CurParsedObjCImpl ? CurParsedObjCImpl->Dcl
: nullptr,
Tok.is(tok::l_paren));
: nullptr);
break;
}
case tok::plusplus: // postfix-expression: postfix-expression '++'

View File

@ -1493,9 +1493,8 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
ParseDecltypeSpecifier(DS);
if (DS.getTypeSpecType() == TST_error)
return ExprError();
return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc,
OpKind, TildeLoc, DS,
Tok.is(tok::l_paren));
return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind,
TildeLoc, DS);
}
if (!Tok.is(tok::identifier)) {
@ -1518,11 +1517,9 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
/*AssumeTemplateName=*/true))
return ExprError();
return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base,
OpLoc, OpKind,
SS, FirstTypeName, CCLoc,
TildeLoc, SecondTypeName,
Tok.is(tok::l_paren));
return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind,
SS, FirstTypeName, CCLoc, TildeLoc,
SecondTypeName);
}
/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.

View File

@ -184,7 +184,7 @@ static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) {
return true;
}
QualType ReturnTy = CE->getCallReturnType();
QualType ReturnTy = CE->getCallReturnType(S.Context);
QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() };
QualType BuiltinTy = S.Context.getFunctionType(
ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo());
@ -6860,7 +6860,7 @@ static bool CheckForReference(Sema &SemaRef, const Expr *E,
if (!M->getMemberDecl()->getType()->isReferenceType())
return false;
} else if (const CallExpr *Call = dyn_cast<CallExpr>(E)) {
if (!Call->getCallReturnType()->isReferenceType())
if (!Call->getCallReturnType(SemaRef.Context)->isReferenceType())
return false;
FD = Call->getDirectCallee();
} else {

View File

@ -13966,7 +13966,17 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
// Bound member functions.
case BuiltinType::BoundMember: {
ExprResult result = E;
tryToRecoverWithCall(result, PDiag(diag::err_bound_member_function),
const Expr *BME = E->IgnoreParens();
PartialDiagnostic PD = PDiag(diag::err_bound_member_function);
// Try to give a nicer diagnostic if it is a bound member that we recognize.
if (isa<CXXPseudoDestructorExpr>(BME)) {
PD = PDiag(diag::err_dtor_expr_without_call) << /*pseudo-destructor*/ 1;
} else if (const auto *ME = dyn_cast<MemberExpr>(BME)) {
if (ME->getMemberNameInfo().getName().getNameKind() ==
DeclarationName::CXXDestructorName)
PD = PDiag(diag::err_dtor_expr_without_call) << /*destructor*/ 0;
}
tryToRecoverWithCall(result, PD,
/*complain*/ true);
return result;
}

View File

@ -5164,7 +5164,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
if (Call == TopCall)
continue;
if (CheckCallReturnType(Call->getCallReturnType(),
if (CheckCallReturnType(Call->getCallReturnType(Context),
Call->getLocStart(),
Call, Call->getDirectCallee()))
return ExprError();
@ -5365,20 +5365,6 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
return Base;
}
ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
Expr *MemExpr) {
SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc);
Diag(MemExpr->getLocStart(), diag::err_dtor_expr_without_call)
<< isa<CXXPseudoDestructorExpr>(MemExpr)
<< FixItHint::CreateInsertion(ExpectedLParenLoc, "()");
return ActOnCallExpr(/*Scope*/ nullptr,
MemExpr,
/*LPLoc*/ ExpectedLParenLoc,
None,
/*RPLoc*/ ExpectedLParenLoc);
}
static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base,
tok::TokenKind& OpKind, SourceLocation OpLoc) {
if (Base->hasPlaceholderType()) {
@ -5419,8 +5405,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
TypeSourceInfo *ScopeTypeInfo,
SourceLocation CCLoc,
SourceLocation TildeLoc,
PseudoDestructorTypeStorage Destructed,
bool HasTrailingLParen) {
PseudoDestructorTypeStorage Destructed) {
TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
QualType ObjectType;
@ -5508,10 +5493,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
TildeLoc,
Destructed);
if (HasTrailingLParen)
return Result;
return DiagnoseDtorReference(Destructed.getLocation(), Result);
return Result;
}
ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
@ -5521,8 +5503,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
UnqualifiedId &FirstTypeName,
SourceLocation CCLoc,
SourceLocation TildeLoc,
UnqualifiedId &SecondTypeName,
bool HasTrailingLParen) {
UnqualifiedId &SecondTypeName) {
assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
"Invalid first type name in pseudo-destructor");
@ -5649,15 +5630,14 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, SS,
ScopeTypeInfo, CCLoc, TildeLoc,
Destructed, HasTrailingLParen);
Destructed);
}
ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation TildeLoc,
const DeclSpec& DS,
bool HasTrailingLParen) {
const DeclSpec& DS) {
QualType ObjectType;
if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
return ExprError();
@ -5673,7 +5653,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, CXXScopeSpec(),
nullptr, SourceLocation(), TildeLoc,
Destructed, HasTrailingLParen);
Destructed);
}
ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,

View File

@ -969,8 +969,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
CXXScopeSpec TempSS(SS);
RetryExpr = ActOnMemberAccessExpr(
ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS,
TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl,
ExtraArgs->HasTrailingLParen);
TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl);
}
if (Trap.hasErrorOccurred())
RetryExpr = ExprError();
@ -1591,9 +1590,6 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
/// possibilities, including destructor and operator references.
///
/// \param OpKind either tok::arrow or tok::period
/// \param HasTrailingLParen whether the next token is '(', which
/// is used to diagnose mis-uses of special members that can
/// only be called
/// \param ObjCImpDecl the current Objective-C \@implementation
/// decl; this is an ugly hack around the fact that Objective-C
/// \@implementations aren't properly put in the context chain
@ -1603,24 +1599,10 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
Decl *ObjCImpDecl,
bool HasTrailingLParen) {
Decl *ObjCImpDecl) {
if (SS.isSet() && SS.isInvalid())
return ExprError();
// The only way a reference to a destructor can be used is to
// immediately call it. If the next token is not a '(', produce
// a diagnostic and build the call now.
if (!HasTrailingLParen &&
Id.getKind() == UnqualifiedId::IK_DestructorName) {
ExprResult DtorAccess =
ActOnMemberAccessExpr(S, Base, OpLoc, OpKind, SS, TemplateKWLoc, Id,
ObjCImpDecl, /*HasTrailingLParen*/true);
if (DtorAccess.isInvalid())
return DtorAccess;
return DiagnoseDtorReference(Id.getLocStart(), DtorAccess.get());
}
// Warn about the explicit constructor calls Microsoft extension.
if (getLangOpts().MicrosoftExt &&
Id.getKind() == UnqualifiedId::IK_ConstructorName)
@ -1653,8 +1635,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
NameInfo, TemplateArgs);
}
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl,
HasTrailingLParen};
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
return BuildMemberReferenceExpr(Base, Base->getType(), OpLoc, IsArrow, SS,
TemplateKWLoc, FirstQualifierInScope,
NameInfo, TemplateArgs, &ExtraArgs);

View File

@ -11595,6 +11595,10 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
return MaybeBindToTemporary(call);
}
if (isa<CXXPseudoDestructorExpr>(NakedMemExpr))
return new (Context)
CallExpr(Context, MemExprE, Args, Context.VoidTy, VK_RValue, RParenLoc);
UnbridgedCastsSet UnbridgedCasts;
if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts))
return ExprError();

View File

@ -1442,7 +1442,7 @@ ExprResult MSPropertyOpBuilder::buildGet() {
ExprResult GetterExpr = S.ActOnMemberAccessExpr(
S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(),
RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(),
GetterName, nullptr, true);
GetterName, nullptr);
if (GetterExpr.isInvalid()) {
S.Diag(RefExpr->getMemberLoc(),
diag::error_cannot_find_suitable_accessor) << 0 /* getter */
@ -1472,7 +1472,7 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl,
ExprResult SetterExpr = S.ActOnMemberAccessExpr(
S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(),
RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(),
SetterName, nullptr, true);
SetterName, nullptr);
if (SetterExpr.isInvalid()) {
S.Diag(RefExpr->getMemberLoc(),
diag::error_cannot_find_suitable_accessor) << 1 /* setter */

View File

@ -10727,11 +10727,9 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
!BaseType->getAs<PointerType>()->getPointeeType()
->template getAs<RecordType>())){
// This pseudo-destructor expression is still a pseudo-destructor.
return SemaRef.BuildPseudoDestructorExpr(Base, OperatorLoc,
isArrow? tok::arrow : tok::period,
SS, ScopeType, CCLoc, TildeLoc,
Destroyed,
/*FIXME?*/true);
return SemaRef.BuildPseudoDestructorExpr(
Base, OperatorLoc, isArrow ? tok::arrow : tok::period, SS, ScopeType,
CCLoc, TildeLoc, Destroyed);
}
TypeSourceInfo *DestroyedType = Destroyed.getTypeSourceInfo();

View File

@ -3340,7 +3340,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// See if it's one of the specific functions we know how to eval.
bool canEval = false;
QualType ResultTy = CE->getCallReturnType();
QualType ResultTy = CE->getCallReturnType(C.getASTContext());
if (ResultTy->isObjCIdType()) {
// Handle: id NSMakeCollectable(CFTypeRef)
canEval = II->isStr("NSMakeCollectable");

View File

@ -392,3 +392,14 @@ struct S {
volatile ~S() { } // expected-error{{destructor cannot have a return type}}
};
}
namespace PR22668 {
struct S {
};
void f(S s) {
(s.~S)();
}
void g(S s) {
(s.~S); // expected-error{{reference to destructor must be called}}
}
}

View File

@ -59,7 +59,11 @@ void f(A* a, Foo *f, int *i, double *d, int ii) {
typedef int Integer;
void destroy_without_call(int *ip) {
ip->~Integer; // expected-error{{called immediately}}
ip->~Integer; // expected-error{{reference to pseudo-destructor must be called}}
}
void paren_destroy_with_call(int *ip) {
(ip->~Integer)();
}
// PR5530