87 changes: 56 additions & 31 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2183,20 +2183,17 @@ class Sema final {
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc);
bool handlerCanCatch(QualType HandlerType, QualType ExceptionType);
bool CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
const PartialDiagnostic &NestedDiagID,
const PartialDiagnostic &NoteID,
const PartialDiagnostic &NoThrowDiagID,
const FunctionProtoType *Superset,
SourceLocation SuperLoc,
const FunctionProtoType *Subset,
SourceLocation SubLoc);
bool CheckParamExceptionSpec(const PartialDiagnostic &NestedDiagID,
const PartialDiagnostic &NoteID,
const FunctionProtoType *Target,
SourceLocation TargetLoc,
const FunctionProtoType *Source,
SourceLocation SourceLoc);
bool CheckExceptionSpecSubset(
const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID,
const PartialDiagnostic &NoteID, const PartialDiagnostic &NoThrowDiagID,
const FunctionProtoType *Superset, bool SkipSupersetFirstParameter,
SourceLocation SuperLoc, const FunctionProtoType *Subset,
bool SkipSubsetFirstParameter, SourceLocation SubLoc);
bool CheckParamExceptionSpec(
const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID,
const FunctionProtoType *Target, bool SkipTargetFirstParameter,
SourceLocation TargetLoc, const FunctionProtoType *Source,
bool SkipSourceFirstParameter, SourceLocation SourceLoc);

TypeResult ActOnTypeName(Scope *S, Declarator &D);

Expand Down Expand Up @@ -3023,7 +3020,8 @@ class Sema final {
Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD,
bool IsDefinition);
void CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D);
Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
Decl *ActOnParamDeclarator(Scope *S, Declarator &D,
SourceLocation ExplicitThisLoc = {});
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
SourceLocation Loc,
QualType T);
Expand Down Expand Up @@ -3797,8 +3795,12 @@ class Sema final {
NamedDecl *&OldDecl,
bool UseMemberUsingDeclRules);
bool IsOverload(FunctionDecl *New, FunctionDecl *Old,
bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs = true,
bool ConsiderRequiresClauses = true);
bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs = true);

// Checks whether MD constitutes an override the base class method BaseMD.
// When checking for overrides, the object object members are ignored.
bool IsOverride(FunctionDecl *MD, FunctionDecl *BaseMD,
bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs = true);

// Calculates whether the expression Constraint depends on an enclosing
// template, for the purposes of [temp.friend] p9.
Expand Down Expand Up @@ -3856,6 +3858,12 @@ class Sema final {
QualType &ConvertedType);
bool IsBlockPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType);

bool FunctionParamTypesAreEqual(ArrayRef<QualType> Old,
ArrayRef<QualType> New,
unsigned *ArgPos = nullptr,
bool Reversed = false);

bool FunctionParamTypesAreEqual(const FunctionProtoType *OldType,
const FunctionProtoType *NewType,
unsigned *ArgPos = nullptr,
Expand Down Expand Up @@ -3896,10 +3904,11 @@ class Sema final {
ExprResult Init,
bool TopLevelOfInitList = false,
bool AllowExplicit = false);
ExprResult PerformObjectArgumentInitialization(Expr *From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
CXXMethodDecl *Method);
ExprResult InitializeExplicitObjectArgument(Sema &S, Expr *Obj,
FunctionDecl *Fun);
ExprResult PerformImplicitObjectArgumentInitialization(
Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl,
CXXMethodDecl *Method);

/// Check that the lifetime of the initializer (and its subobjects) is
/// sufficient for initializing the entity, and perform lifetime extension
Expand Down Expand Up @@ -4221,9 +4230,8 @@ class Sema final {
QualType DestTypeForComplaining = QualType(),
unsigned DiagIDForComplaining = 0);

Expr *FixOverloadedFunctionReference(Expr *E,
DeclAccessPair FoundDecl,
FunctionDecl *Fn);
ExprResult FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl,
FunctionDecl *Fn);
ExprResult FixOverloadedFunctionReference(ExprResult,
DeclAccessPair FoundDecl,
FunctionDecl *Fn);
Expand Down Expand Up @@ -4799,8 +4807,8 @@ class Sema final {
/// Adjust the calling convention of a method to be the ABI default if it
/// wasn't specified explicitly. This handles method types formed from
/// function type typedefs and typename template arguments.
void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor,
SourceLocation Loc);
void adjustMemberFunctionCC(QualType &T, bool HasThisPointer,
bool IsCtorOrDtor, SourceLocation Loc);

// Check if there is an explicit attribute, but only look through parens.
// The intent is to look for an attribute on the current declarator, but not
Expand Down Expand Up @@ -5796,6 +5804,10 @@ class Sema final {
Expr *Input, bool IsAfterAmp = false);

bool isQualifiedMemberAccess(Expr *E);
bool CheckUseOfCXXMethodAsAddressOfOperand(SourceLocation OpLoc,
const Expr *Op,
const CXXMethodDecl *MD);

QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc);

bool CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N);
Expand Down Expand Up @@ -7236,6 +7248,8 @@ class Sema final {
StorageClass SC, ArrayRef<ParmVarDecl *> Params,
bool HasExplicitResultType);

void DiagnoseInvalidExplicitObjectParameterInLambda(CXXMethodDecl *Method);

/// Perform initialization analysis of the init-capture and perform
/// any implicit conversions such as an lvalue-to-rvalue conversion if
/// not being used to initialize a reference.
Expand Down Expand Up @@ -7916,6 +7930,13 @@ class Sema final {
void DefineDefaultedComparison(SourceLocation Loc, FunctionDecl *FD,
DefaultedComparisonKind DCK);

void CheckExplicitObjectMemberFunction(Declarator &D, DeclarationName Name,
QualType R, bool IsLambda,
DeclContext *DC = nullptr);
void CheckExplicitObjectMemberFunction(DeclContext *DC, Declarator &D,
DeclarationName Name, QualType R);
void CheckExplicitObjectLambda(Declarator &D);

//===--------------------------------------------------------------------===//
// C++ Derived Classes
//
Expand Down Expand Up @@ -7967,6 +7988,10 @@ class Sema final {
bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old);

// Check that the overriding method has no explicit object parameter.
bool CheckExplicitObjectOverride(CXXMethodDecl *New,
const CXXMethodDecl *Old);

/// CheckOverridingFunctionExceptionSpec - Checks whether the exception
/// spec is a subset of base spec.
bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
Expand Down Expand Up @@ -9210,6 +9235,7 @@ class Sema final {
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info,
bool PartialOverloading, bool AggregateDeductionCandidate,
QualType ObjectType, Expr::Classification ObjectClassification,
llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent);

TemplateDeductionResult
Expand All @@ -9220,11 +9246,10 @@ class Sema final {
sema::TemplateDeductionInfo &Info,
bool IsAddressOfFunction = false);

TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType ToType,
CXXConversionDecl *&Specialization,
sema::TemplateDeductionInfo &Info);
TemplateDeductionResult DeduceTemplateArguments(
FunctionTemplateDecl *FunctionTemplate, QualType ObjectType,
Expr::Classification ObjectClassification, QualType ToType,
CXXConversionDecl *&Specialization, sema::TemplateDeductionInfo &Info);

TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4521,6 +4521,8 @@ ExpectedDecl ASTNodeImporter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
Error ASTNodeImporter::ImportDefaultArgOfParmVarDecl(
const ParmVarDecl *FromParam, ParmVarDecl *ToParam) {
ToParam->setHasInheritedDefaultArg(FromParam->hasInheritedDefaultArg());
ToParam->setExplicitObjectParameterLoc(
FromParam->getExplicitObjectParamThisLoc());
ToParam->setKNRPromoted(FromParam->isKNRPromoted());

if (FromParam->hasUninstantiatedDefaultArg()) {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Method1->getAccess() == Method2->getAccess() &&
Method1->getOverloadedOperator() == Method2->getOverloadedOperator() &&
Method1->isStatic() == Method2->isStatic() &&
Method1->isImplicitObjectMemberFunction() ==
Method2->isImplicitObjectMemberFunction() &&
Method1->isConst() == Method2->isConst() &&
Method1->isVolatile() == Method2->isVolatile() &&
Method1->isVirtual() == Method2->isVirtual() &&
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/ComputeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,10 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) {

// - an identifier associated by name lookup with one or more declarations
// declared with a dependent type
// - an identifier associated by name lookup with an entity captured by
// copy ([expr.prim.lambda.capture])
// in a lambda-expression that has an explicit object parameter whose
// type is dependent ([dcl.fct]),
//
// [The "or more" case is not modeled as a DeclRefExpr. There are a bunch
// more bullets here that we handle by treating the declaration as having a
Expand All @@ -493,6 +497,11 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) {
else if (Type->isInstantiationDependentType())
Deps |= ExprDependence::Instantiation;

// - an identifier associated by name lookup with an entity captured by
// copy ([expr.prim.lambda.capture])
if (E->isCapturedByCopyInLambdaWithExplicitObjectParameter())
Deps |= ExprDependence::Type;

// - a conversion-function-id that specifies a dependent type
if (Decl->getDeclName().getNameKind() ==
DeclarationName::CXXConversionFunctionName) {
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3652,6 +3652,20 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
return NumRequiredArgs;
}

bool FunctionDecl::hasCXXExplicitFunctionObjectParameter() const {
return getNumParams() != 0 && getParamDecl(0)->isExplicitObjectParameter();
}

unsigned FunctionDecl::getNumNonObjectParams() const {
return getNumParams() -
static_cast<unsigned>(hasCXXExplicitFunctionObjectParameter());
}

unsigned FunctionDecl::getMinRequiredExplicitArguments() const {
return getMinRequiredArguments() -
static_cast<unsigned>(hasCXXExplicitFunctionObjectParameter());
}

bool FunctionDecl::hasOneParamOrDefaultArgs() const {
return getNumParams() == 1 ||
(getNumParams() > 1 &&
Expand Down
46 changes: 29 additions & 17 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
SMKind |= SMF_CopyAssignment;

const auto *ParamTy =
Method->getParamDecl(0)->getType()->getAs<ReferenceType>();
Method->getNonObjectParameter(0)->getType()->getAs<ReferenceType>();
if (!ParamTy || ParamTy->getPointeeType().isConstQualified())
data().HasDeclaredCopyAssignmentWithConstParam = true;
}
Expand Down Expand Up @@ -2409,18 +2409,30 @@ bool CXXMethodDecl::isUsualDeallocationFunction(
return Result;
}

bool CXXMethodDecl::isExplicitObjectMemberFunction() const {
// C++2b [dcl.fct]p6:
// An explicit object member function is a non-static member
// function with an explicit object parameter
return !isStatic() && hasCXXExplicitFunctionObjectParameter();
}

bool CXXMethodDecl::isImplicitObjectMemberFunction() const {
return !isStatic() && !hasCXXExplicitFunctionObjectParameter();
}

bool CXXMethodDecl::isCopyAssignmentOperator() const {
// C++0x [class.copy]p17:
// A user-declared copy assignment operator X::operator= is a non-static
// non-template member function of class X with exactly one parameter of
// type X, X&, const X&, volatile X& or const volatile X&.
if (/*operator=*/getOverloadedOperator() != OO_Equal ||
/*non-static*/ isStatic() ||
/*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
getNumParams() != 1)

/*non-template*/ getPrimaryTemplate() || getDescribedFunctionTemplate() ||
getNumExplicitParams() != 1)
return false;

QualType ParamType = getParamDecl(0)->getType();
QualType ParamType = getNonObjectParameter(0)->getType();
if (const auto *Ref = ParamType->getAs<LValueReferenceType>())
ParamType = Ref->getPointeeType();

Expand All @@ -2437,10 +2449,10 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const {
// X&&, const X&&, volatile X&&, or const volatile X&&.
if (getOverloadedOperator() != OO_Equal || isStatic() ||
getPrimaryTemplate() || getDescribedFunctionTemplate() ||
getNumParams() != 1)
getNumExplicitParams() != 1)
return false;

QualType ParamType = getParamDecl(0)->getType();
QualType ParamType = getNonObjectParameter(0)->getType();
if (!ParamType->isRValueReferenceType())
return false;
ParamType = ParamType->getPointeeType();
Expand Down Expand Up @@ -2496,12 +2508,6 @@ QualType CXXMethodDecl::getThisType(const FunctionProtoType *FPT,
: C.getPointerType(ObjectTy);
}

QualType CXXMethodDecl::getThisObjectType(const FunctionProtoType *FPT,
const CXXRecordDecl *Decl) {
ASTContext &C = Decl->getASTContext();
return ::getThisObjectType(C, FPT, Decl);
}

QualType CXXMethodDecl::getThisType() const {
// C++ 9.3.2p1: The type of this in a member function of a class X is X*.
// If the member function is declared const, the type of this is const X*,
Expand All @@ -2513,11 +2519,17 @@ QualType CXXMethodDecl::getThisType() const {
getParent());
}

QualType CXXMethodDecl::getThisObjectType() const {
// Ditto getThisType.
assert(isInstance() && "No 'this' for static methods!");
return CXXMethodDecl::getThisObjectType(
getType()->castAs<FunctionProtoType>(), getParent());
QualType CXXMethodDecl::getFunctionObjectParameterReferenceType() const {
if (isExplicitObjectMemberFunction())
return parameters()[0]->getType();

ASTContext &C = getParentASTContext();
const FunctionProtoType *FPT = getType()->castAs<FunctionProtoType>();
QualType Type = ::getThisObjectType(C, FPT, getParent());
RefQualifierKind RK = FPT->getRefQualifier();
if (RK == RefQualifierKind::RQ_RValue)
return C.getRValueReferenceType(Type);
return C.getLValueReferenceType(Type);
}

bool CXXMethodDecl::hasInlineBody() const {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/DeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,10 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
void DeclPrinter::VisitVarDecl(VarDecl *D) {
prettyPrintPragmas(D);

if (const auto *Param = dyn_cast<ParmVarDecl>(D);
Param && Param->isExplicitObjectParameter())
Out << "this ";

std::string LeftSide;
llvm::raw_string_ostream LeftSideStream(LeftSide);

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
DeclRefExprBits.HadMultipleCandidates = false;
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
RefersToEnclosingVariableOrCapture;
DeclRefExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = false;
DeclRefExprBits.NonOdrUseReason = NOUR;
DeclRefExprBits.IsImmediateEscalating = false;
DeclRefExprBits.Loc = L;
Expand Down Expand Up @@ -518,6 +519,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
= (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0;
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
RefersToEnclosingVariableOrCapture;
DeclRefExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = false;
DeclRefExprBits.NonOdrUseReason = NOUR;
if (TemplateArgs) {
auto Deps = TemplateArgumentDependence::None;
Expand Down
18 changes: 14 additions & 4 deletions clang/lib/AST/ExprClassification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,8 +465,13 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) {
// lvalue unless it's a reference type (C++ [temp.param]p6), so we need to
// special-case this.

if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())
return Cl::CL_MemberFunction;
if (const auto *M = dyn_cast<CXXMethodDecl>(D)) {
if (M->isImplicitObjectMemberFunction())
return Cl::CL_MemberFunction;
if (M->isStatic())
return Cl::CL_LValue;
return Cl::CL_PRValue;
}

bool islvalue;
if (const auto *NTTParm = dyn_cast<NonTypeTemplateParmDecl>(D))
Expand Down Expand Up @@ -551,8 +556,13 @@ static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) {
// -- If it refers to a static member function [...], then E1.E2 is an
// lvalue; [...]
// -- Otherwise [...] E1.E2 is a prvalue.
if (const auto *Method = dyn_cast<CXXMethodDecl>(Member))
return Method->isStatic() ? Cl::CL_LValue : Cl::CL_MemberFunction;
if (const auto *Method = dyn_cast<CXXMethodDecl>(Member)) {
if (Method->isStatic())
return Cl::CL_LValue;
if (Method->isImplicitObjectMemberFunction())
return Cl::CL_MemberFunction;
return Cl::CL_PRValue;
}

// -- If E2 is a member enumerator [...], the expression E1.E2 is a prvalue.
// So is everything else we haven't handled yet.
Expand Down
30 changes: 19 additions & 11 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1945,9 +1945,9 @@ APValue *EvalInfo::createHeapAlloc(const Expr *E, QualType T, LValue &LV) {
/// Produce a string describing the given constexpr call.
void CallStackFrame::describe(raw_ostream &Out) const {
unsigned ArgIndex = 0;
bool IsMemberCall = isa<CXXMethodDecl>(Callee) &&
!isa<CXXConstructorDecl>(Callee) &&
cast<CXXMethodDecl>(Callee)->isInstance();
bool IsMemberCall =
isa<CXXMethodDecl>(Callee) && !isa<CXXConstructorDecl>(Callee) &&
cast<CXXMethodDecl>(Callee)->isImplicitObjectMemberFunction();

if (!IsMemberCall)
Callee->getNameForDiagnostic(Out, Info.Ctx.getPrintingPolicy(),
Expand Down Expand Up @@ -4711,6 +4711,9 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
if (Object->getType()->isLiteralType(Info.Ctx))
return EvaluateTemporary(Object, This, Info);

if (Object->getType()->isRecordType() && Object->isPRValue())
return EvaluateTemporary(Object, This, Info);

Info.FFDiag(Object, diag::note_constexpr_nonliteral) << Object->getType();
return false;
}
Expand Down Expand Up @@ -7789,15 +7792,18 @@ class ExprEvaluatorBase
if (OCE && OCE->isAssignmentOp()) {
assert(Args.size() == 2 && "wrong number of arguments in assignment");
Call = Info.CurrentCall->createCall(FD);
if (!EvaluateArgs(isa<CXXMethodDecl>(FD) ? Args.slice(1) : Args, Call,
Info, FD, /*RightToLeft=*/true))
bool HasThis = false;
if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
HasThis = MD->isImplicitObjectMemberFunction();
if (!EvaluateArgs(HasThis ? Args.slice(1) : Args, Call, Info, FD,
/*RightToLeft=*/true))
return false;
}

// Overloaded operator calls to member functions are represented as normal
// calls with '*this' as the first argument.
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
if (MD && !MD->isStatic()) {
if (MD && MD->isImplicitObjectMemberFunction()) {
// FIXME: When selecting an implicit conversion for an overloaded
// operator delete, we sometimes try to evaluate calls to conversion
// operators without a 'this' parameter!
Expand Down Expand Up @@ -7881,7 +7887,7 @@ class ExprEvaluatorBase
CovariantAdjustmentPath);
if (!FD)
return false;
} else {
} else if (NamedMember && NamedMember->isImplicitObjectMemberFunction()) {
// Check that the 'this' pointer points to an object of the right type.
// FIXME: If this is an assignment operator call, we may need to change
// the active union member before we check this.
Expand Down Expand Up @@ -16284,7 +16290,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
#ifndef NDEBUG
auto *MD = dyn_cast<CXXMethodDecl>(Callee);
assert(MD && "Don't provide `this` for non-methods.");
assert(!MD->isStatic() && "Don't provide `this` for static methods.");
assert(MD->isImplicitObjectMemberFunction() &&
"Don't provide `this` for methods without an implicit object.");
#endif
if (!This->isValueDependent() &&
EvaluateObjectArgument(Info, This, ThisVal) &&
Expand Down Expand Up @@ -16379,9 +16386,10 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
HandleConstructorCall(&VIE, This, Args, CD, Info, Scratch);
} else {
SourceLocation Loc = FD->getLocation();
HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr,
&VIE, Args, CallRef(), FD->getBody(), Info, Scratch,
/*ResultSlot=*/nullptr);
HandleFunctionCall(
Loc, FD, (MD && MD->isImplicitObjectMemberFunction()) ? &This : nullptr,
&VIE, Args, CallRef(), FD->getBody(), Info, Scratch,
/*ResultSlot=*/nullptr);
}

return Diags.empty();
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
// InterpStack when calling the function.
bool HasThisPointer = false;
if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) {
if (MD->isInstance()) {
if (MD->isImplicitObjectMemberFunction()) {
HasThisPointer = true;
ParamTypes.push_back(PT_Ptr);
ParamOffsets.push_back(ParamOffset);
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1721,7 +1721,7 @@ void CXXNameMangler::mangleUnqualifiedName(

// If we have a member function, we need to include the 'this' pointer.
if (const auto *MD = dyn_cast<CXXMethodDecl>(ND))
if (!MD->isStatic())
if (MD->isImplicitObjectMemberFunction())
Arity++;
}
[[fallthrough]];
Expand Down Expand Up @@ -1781,6 +1781,8 @@ void CXXNameMangler::mangleNestedName(GlobalDecl GD,
Qualifiers MethodQuals = Method->getMethodQualifiers();
// We do not consider restrict a distinguishing attribute for overloading
// purposes so we must not mangle it.
if (Method->isExplicitObjectMemberFunction())
Out << 'H';
MethodQuals.removeRestrict();
mangleQualifiers(MethodQuals);
mangleRefQualifier(Method->getRefQualifier());
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/JSONNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,9 @@ void JSONNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *USD) {
void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) {
VisitNamedDecl(VD);
JOS.attribute("type", createQualType(VD->getType()));
if (const auto *P = dyn_cast<ParmVarDecl>(VD))
attributeOnlyIfTrue("explicitObjectParameter",
P->isExplicitObjectParameter());

StorageClass SC = VD->getStorageClass();
if (SC != SC_None)
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
assert(!Proto->isVariadic());
unsigned ArgWords = 0;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (!MD->isStatic())
if (MD->isImplicitObjectMemberFunction())
++ArgWords;
uint64_t DefaultPtrWidth = TI.getPointerWidth(LangAS::Default);
for (const auto &AT : Proto->param_types()) {
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2636,7 +2636,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) {
if (MD->getParent()->isLambda())
IsInLambda = true;
if (MD->isInstance())
if (MD->isImplicitObjectMemberFunction())
HasThisQuals = true;
if (isa<CXXDestructorDecl>(MD)) {
IsStructor = true;
Expand Down Expand Up @@ -2745,6 +2745,10 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
} else {
// Happens for function pointer type arguments for example.
for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) {
// Explicit object parameters are prefixed by "_V".
if (I == 0 && D && D->getParamDecl(I)->isExplicitObjectParameter())
Out << "_V";

mangleFunctionArgumentType(Proto->getParamType(I), Range);
// Mangle each pass_object_size parameter as if it's a parameter of enum
// type passed directly after the parameter with the pass_object_size
Expand Down Expand Up @@ -2810,23 +2814,23 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
case AS_none:
llvm_unreachable("Unsupported access specifier");
case AS_private:
if (MD->isStatic())
if (!MD->isImplicitObjectMemberFunction())
Out << 'C';
else if (IsVirtual)
Out << 'E';
else
Out << 'A';
break;
case AS_protected:
if (MD->isStatic())
if (!MD->isImplicitObjectMemberFunction())
Out << 'K';
else if (IsVirtual)
Out << 'M';
else
Out << 'I';
break;
case AS_public:
if (MD->isStatic())
if (!MD->isImplicitObjectMemberFunction())
Out << 'S';
else if (IsVirtual)
Out << 'U';
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1949,6 +1949,10 @@ void TextNodeDumper::VisitFieldDecl(const FieldDecl *D) {
void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
dumpNestedNameSpecifier(D->getQualifier());
dumpName(D);
if (const auto *P = dyn_cast<ParmVarDecl>(D);
P && P->isExplicitObjectParameter())
OS << " this";

dumpType(D->getType());
dumpTemplateSpecializationKind(D->getTemplateSpecializationKind());
StorageClass SC = D->getStorageClass();
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Analysis/Consumed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@ void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
CXXConstructorDecl *Constructor = Call->getConstructor();

QualType ThisType = Constructor->getThisObjectType();
QualType ThisType = Constructor->getFunctionObjectParameterType();

if (!isConsumableType(ThisType))
return;
Expand Down Expand Up @@ -1199,7 +1199,7 @@ void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
const FunctionDecl *D) {
QualType ReturnType;
if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
ReturnType = Constructor->getThisObjectType();
ReturnType = Constructor->getFunctionObjectParameterType();
} else
ReturnType = D->getCallResultType();

Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,8 +452,8 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext());

// FIXME: Initialize the ThisPointeeLoc of lambdas too.
if (MethodDecl && !MethodDecl->isStatic()) {
QualType ThisPointeeType = MethodDecl->getThisObjectType();
if (MethodDecl && MethodDecl->isImplicitObjectMemberFunction()) {
QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
ThisPointeeLoc =
&cast<RecordValue>(createValue(ThisPointeeType))->getLoc();
}
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,9 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
// The assignment operators are different from the type of the destination
// in this model (i.e. in one of their base classes). This must be very
// rare and we just bail.
if (Method->getThisObjectType().getCanonicalType().getUnqualifiedType() !=
if (Method->getFunctionObjectParameterType()
.getCanonicalType()
.getUnqualifiedType() !=
LocDst->getType().getCanonicalType().getUnqualifiedType())
return;

Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Analysis/ThreadSafetyCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
// If the attribute has no arguments, then assume the argument is "this".
if (!AttrExp)
return CapabilityExpr(
Self, ClassifyDiagnostic(cast<CXXMethodDecl>(D)->getThisObjectType()),
Self,
ClassifyDiagnostic(
cast<CXXMethodDecl>(D)->getFunctionObjectParameterType()),
false);
else // For most attributes.
return translateAttrExpr(AttrExp, &Ctx);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) {
setCUDAKernelCallingConvention(FT, CGM, MD);
auto prototype = FT.getAs<FunctionProtoType>();

if (MD->isInstance()) {
if (MD->isImplicitObjectMemberFunction()) {
// The abstract case is perfectly fine.
const CXXRecordDecl *ThisType = TheCXXABI.getThisArgumentTypeForMethod(MD);
return arrangeCXXMethodType(ThisType, prototype.getTypePtr(), MD);
Expand Down Expand Up @@ -448,7 +448,7 @@ CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
const CGFunctionInfo &
CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (MD->isInstance())
if (MD->isImplicitObjectMemberFunction())
return arrangeCXXMethodDeclaration(MD);

CanQualType FTy = FD->getType()->getCanonicalTypeUnqualified();
Expand Down
12 changes: 6 additions & 6 deletions clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Address CodeGenFunction::LoadCXXThisAddress() {
CXXThisAlignment = CGM.getClassPointerAlignment(MD->getParent());
}

llvm::Type *Ty = ConvertType(MD->getThisObjectType());
llvm::Type *Ty = ConvertType(MD->getFunctionObjectParameterType());
return Address(LoadCXXThis(), Ty, CXXThisAlignment, KnownNonNull);
}

Expand Down Expand Up @@ -510,7 +510,7 @@ namespace {
const CXXDestructorDecl *D = BaseClass->getDestructor();
// We are already inside a destructor, so presumably the object being
// destroyed should have the expected type.
QualType ThisTy = D->getThisObjectType();
QualType ThisTy = D->getFunctionObjectParameterType();
Address Addr =
CGF.GetAddressOfDirectBaseInCompleteClass(CGF.LoadCXXThisAddress(),
DerivedClass, BaseClass,
Expand Down Expand Up @@ -1456,7 +1456,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
RunCleanupsScope DtorEpilogue(*this);
EnterDtorCleanups(Dtor, Dtor_Deleting);
if (HaveInsertPoint()) {
QualType ThisTy = Dtor->getThisObjectType();
QualType ThisTy = Dtor->getFunctionObjectParameterType();
EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
/*Delegating=*/false, LoadCXXThisAddress(), ThisTy);
}
Expand Down Expand Up @@ -1490,7 +1490,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
EnterDtorCleanups(Dtor, Dtor_Complete);

if (!isTryBody) {
QualType ThisTy = Dtor->getThisObjectType();
QualType ThisTy = Dtor->getFunctionObjectParameterType();
EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
/*Delegating=*/false, LoadCXXThisAddress(), ThisTy);
break;
Expand Down Expand Up @@ -2114,7 +2114,7 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
CallArgList Args;
Address This = ThisAVS.getAddress();
LangAS SlotAS = ThisAVS.getQualifiers().getAddressSpace();
LangAS ThisAS = D->getThisObjectType().getAddressSpace();
LangAS ThisAS = D->getFunctionObjectParameterType().getAddressSpace();
llvm::Value *ThisPtr = This.getPointer();

if (SlotAS != ThisAS) {
Expand Down Expand Up @@ -2453,7 +2453,7 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) override {
// We are calling the destructor from within the constructor.
// Therefore, "this" should have the expected type.
QualType ThisTy = Dtor->getThisObjectType();
QualType ThisTy = Dtor->getFunctionObjectParameterType();
CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
/*Delegating=*/true, Addr, ThisTy);
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2130,14 +2130,14 @@ CGDebugInfo::CollectTemplateParams(std::optional<TemplateArgs> OArgs,
// attribute, i.e. that value is not available at the host side.
if (!CGM.getLangOpts().CUDA || CGM.getLangOpts().CUDAIsDevice ||
!D->hasAttr<CUDADeviceAttr>()) {
const CXXMethodDecl *MD;
// Variable pointer template parameters have a value that is the address
// of the variable.
if (const auto *VD = dyn_cast<VarDecl>(D))
V = CGM.GetAddrOfGlobalVar(VD);
// Member function pointers have special support for building them,
// though this is currently unsupported in LLVM CodeGen.
else if ((MD = dyn_cast<CXXMethodDecl>(D)) && MD->isInstance())
else if (const auto *MD = dyn_cast<CXXMethodDecl>(D);
MD && MD->isImplicitObjectMemberFunction())
V = CGM.getCXXABI().EmitMemberFunctionPointer(MD);
else if (const auto *FD = dyn_cast<FunctionDecl>(D))
V = CGM.GetAddrOfFunction(FD);
Expand Down
47 changes: 35 additions & 12 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2647,9 +2647,8 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF, const Expr *E,

static LValue EmitCapturedFieldLValue(CodeGenFunction &CGF, const FieldDecl *FD,
llvm::Value *ThisValue) {
QualType TagType = CGF.getContext().getTagDeclType(FD->getParent());
LValue LV = CGF.MakeNaturalAlignAddrLValue(ThisValue, TagType);
return CGF.EmitLValueForField(LV, FD);

return CGF.EmitLValueForLambdaField(FD, ThisValue);
}

/// Named Registers are named metadata pointing to the register name
Expand Down Expand Up @@ -4262,17 +4261,38 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {

/// Given that we are currently emitting a lambda, emit an l-value for
/// one of its members.
LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field) {
if (CurCodeDecl) {
assert(cast<CXXMethodDecl>(CurCodeDecl)->getParent()->isLambda());
assert(cast<CXXMethodDecl>(CurCodeDecl)->getParent() == Field->getParent());
///
LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field,
llvm::Value *ThisValue) {
bool HasExplicitObjectParameter = false;
if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(CurCodeDecl)) {
HasExplicitObjectParameter = MD->isExplicitObjectMemberFunction();
assert(MD->getParent()->isLambda());
assert(MD->getParent() == Field->getParent());
}
LValue LambdaLV;
if (HasExplicitObjectParameter) {
const VarDecl *D = cast<CXXMethodDecl>(CurCodeDecl)->getParamDecl(0);
auto It = LocalDeclMap.find(D);
assert(It != LocalDeclMap.end() && "explicit parameter not loaded?");
Address AddrOfExplicitObject = It->getSecond();
if (D->getType()->isReferenceType())
LambdaLV = EmitLoadOfReferenceLValue(AddrOfExplicitObject, D->getType(),
AlignmentSource::Decl);
else
LambdaLV = MakeNaturalAlignAddrLValue(AddrOfExplicitObject.getPointer(),
D->getType().getNonReferenceType());
} else {
QualType LambdaTagType = getContext().getTagDeclType(Field->getParent());
LambdaLV = MakeNaturalAlignAddrLValue(ThisValue, LambdaTagType);
}
QualType LambdaTagType =
getContext().getTagDeclType(Field->getParent());
LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, LambdaTagType);
return EmitLValueForField(LambdaLV, Field);
}

LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field) {
return EmitLValueForLambdaField(Field, CXXABIThisValue);
}

/// Get the field index in the debug info. The debug info structure/union
/// will ignore the unnamed bitfields.
unsigned CodeGenFunction::getDebugInfoFIndex(const RecordDecl *Rec,
Expand Down Expand Up @@ -4987,9 +5007,12 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
if (const auto *CE = dyn_cast<CUDAKernelCallExpr>(E))
return EmitCUDAKernelCallExpr(CE, ReturnValue);

// A CXXOperatorCallExpr is created even for explicit object methods, but
// these should be treated like static function call.
if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(E))
if (const CXXMethodDecl *MD =
dyn_cast_or_null<CXXMethodDecl>(CE->getCalleeDecl()))
if (const auto *MD =
dyn_cast_if_present<CXXMethodDecl>(CE->getCalleeDecl());
MD && MD->isImplicitObjectMemberFunction())
return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);

CGCallee callee = EmitCallee(E->getCallee());
Expand Down
11 changes: 8 additions & 3 deletions clang/lib/CodeGen/CGExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, GlobalDecl GD,

assert(CE == nullptr || isa<CXXMemberCallExpr>(CE) ||
isa<CXXOperatorCallExpr>(CE));
assert(MD->isInstance() &&
assert(MD->isImplicitObjectMemberFunction() &&
"Trying to emit a member or operator call expr on a static method!");

// Push the this ptr.
Expand All @@ -66,7 +66,12 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, GlobalDecl GD,
Args.addFrom(*RtlArgs);
} else if (CE) {
// Special case: skip first argument of CXXOperatorCall (it is "this").
unsigned ArgsToSkip = isa<CXXOperatorCallExpr>(CE) ? 1 : 0;
unsigned ArgsToSkip = 0;
if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(CE)) {
if (const auto *M = dyn_cast<CXXMethodDecl>(Op->getCalleeDecl()))
ArgsToSkip =
static_cast<unsigned>(!M->isExplicitObjectMemberFunction());
}
CGF.EmitCallArgs(Args, FPT, drop_begin(CE->arguments(), ArgsToSkip),
CE->getDirectCallee());
} else {
Expand Down Expand Up @@ -484,7 +489,7 @@ RValue
CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
const CXXMethodDecl *MD,
ReturnValueSlot ReturnValue) {
assert(MD->isInstance() &&
assert(MD->isImplicitObjectMemberFunction() &&
"Trying to emit a member call expr on a static method!");
return EmitCXXMemberOrOperatorMemberCallExpr(
E, MD, ReturnValue, /*HasQualifier=*/false, /*Qualifier=*/nullptr,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8260,7 +8260,7 @@ class MappableExprsHandler {
// of tofrom.
// Emit this[:1]
CombinedInfo.Pointers.push_back(PartialStruct.Base.getPointer());
QualType Ty = MD->getThisObjectType();
QualType Ty = MD->getFunctionObjectParameterType();
llvm::Value *Size =
CGF.Builder.CreateIntCast(CGF.getTypeSize(Ty), CGF.Int64Ty,
/*isSigned=*/true);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGVTables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn,
// Find the first store of "this", which will be to the alloca associated
// with "this".
Address ThisPtr =
Address(&*AI, ConvertTypeForMem(MD->getThisObjectType()),
Address(&*AI, ConvertTypeForMem(MD->getFunctionObjectParameterType()),
CGM.getClassPointerAlignment(MD->getParent()));
llvm::BasicBlock *EntryBB = &Fn->front();
llvm::BasicBlock::iterator ThisStore =
Expand Down
17 changes: 9 additions & 8 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1167,12 +1167,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,

EmitFunctionProlog(*CurFnInfo, CurFn, Args);

if (isa_and_nonnull<CXXMethodDecl>(D) &&
cast<CXXMethodDecl>(D)->isInstance()) {
CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
if (MD->getParent()->isLambda() &&
MD->getOverloadedOperator() == OO_Call) {
if (const CXXMethodDecl *MD = dyn_cast_if_present<CXXMethodDecl>(D);
MD && !MD->isStatic()) {
bool IsInLambda =
MD->getParent()->isLambda() && MD->getOverloadedOperator() == OO_Call;
if (MD->isImplicitObjectMemberFunction())
CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
if (IsInLambda) {
// We're in a lambda; figure out the captures.
MD->getParent()->getCaptureFields(LambdaCaptureFields,
LambdaThisCaptureField);
Expand Down Expand Up @@ -1202,7 +1203,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
VLASizeMap[VAT->getSizeExpr()] = ExprArg;
}
}
} else {
} else if (MD->isImplicitObjectMemberFunction()) {
// Not in a lambda; just use 'this' from the method.
// FIXME: Should we generate a new load for each use of 'this'? The
// fast register allocator would be happier...
Expand Down Expand Up @@ -1313,7 +1314,7 @@ QualType CodeGenFunction::BuildFunctionArgList(GlobalDecl GD,
QualType ResTy = FD->getReturnType();

const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
if (MD && MD->isInstance()) {
if (MD && MD->isImplicitObjectMemberFunction()) {
if (CGM.getCXXABI().HasThisReturn(GD))
ResTy = MD->getThisType();
else if (CGM.getCXXABI().hasMostDerivedReturn(GD))
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -4017,6 +4017,8 @@ class CodeGenFunction : public CodeGenTypeCache {
const ObjCIvarDecl *Ivar);
LValue EmitLValueForField(LValue Base, const FieldDecl* Field);
LValue EmitLValueForLambdaField(const FieldDecl *Field);
LValue EmitLValueForLambdaField(const FieldDecl *Field,
llvm::Value *ThisValue);

/// EmitLValueForFieldInitialization - Like EmitLValueForField, except that
/// if the Field is a reference, this will return the address of the reference
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2246,8 +2246,8 @@ static bool requiresMemberFunctionPointerTypeMetadata(CodeGenModule &CGM,

// Only functions whose address can be taken with a member function pointer
// need this sort of type metadata.
return !MD->isStatic() && !MD->isVirtual() && !isa<CXXConstructorDecl>(MD) &&
!isa<CXXDestructorDecl>(MD);
return MD->isImplicitObjectMemberFunction() && !MD->isVirtual() &&
!isa<CXXConstructorDecl, CXXDestructorDecl>(MD);
}

SmallVector<const CXXRecordDecl *, 0>
Expand Down
38 changes: 25 additions & 13 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5835,8 +5835,7 @@ bool Parser::isDeclarationSpecifier(
bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide,
DeclSpec::FriendSpecified IsFriend,
const ParsedTemplateInfo *TemplateInfo) {
TentativeParsingAction TPA(*this);

RevertingTentativeParsingAction TPA(*this);
// Parse the C++ scope specifier.
CXXScopeSpec SS;
if (TemplateInfo && TemplateInfo->TemplateParams)
Expand All @@ -5845,7 +5844,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide,
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
/*ObjectHasErrors=*/false,
/*EnteringContext=*/true)) {
TPA.Revert();
return false;
}

Expand All @@ -5857,7 +5855,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide,
} else if (Tok.is(tok::annot_template_id)) {
ConsumeAnnotationToken();
} else {
TPA.Revert();
return false;
}

Expand All @@ -5867,7 +5864,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide,

// Current class name must be followed by a left parenthesis.
if (Tok.isNot(tok::l_paren)) {
TPA.Revert();
return false;
}
ConsumeParen();
Expand All @@ -5876,7 +5872,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide,
// that we have a constructor.
if (Tok.is(tok::r_paren) ||
(Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren))) {
TPA.Revert();
return true;
}

Expand All @@ -5885,7 +5880,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide,
if (getLangOpts().CPlusPlus11 &&
isCXX11AttributeSpecifier(/*Disambiguate*/ false,
/*OuterMightBeMessageSend*/ true)) {
TPA.Revert();
return true;
}

Expand All @@ -5906,9 +5900,17 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide,
// If we parsed a scope specifier as well as friend,
// we might be parsing a friend constructor.
bool IsConstructor = false;
if (isDeclarationSpecifier(IsFriend && !SS.isSet()
? ImplicitTypenameContext::No
: ImplicitTypenameContext::Yes))
ImplicitTypenameContext ITC = IsFriend && !SS.isSet()
? ImplicitTypenameContext::No
: ImplicitTypenameContext::Yes;
// Constructors cannot have this parameters, but we support that scenario here
// to improve diagnostic.
if (Tok.is(tok::kw_this)) {
ConsumeToken();
return isDeclarationSpecifier(ITC);
}

if (isDeclarationSpecifier(ITC))
IsConstructor = true;
else if (Tok.is(tok::identifier) ||
(Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) {
Expand Down Expand Up @@ -5977,8 +5979,6 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide,
break;
}
}

TPA.Revert();
return IsConstructor;
}

Expand Down Expand Up @@ -7356,6 +7356,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
/// '=' assignment-expression
/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
/// [C++11] attribute-specifier-seq parameter-declaration
/// [C++2b] attribute-specifier-seq 'this' parameter-declaration
///
void Parser::ParseParameterDeclarationClause(
DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs,
Expand Down Expand Up @@ -7420,9 +7421,16 @@ void Parser::ParseParameterDeclarationClause(

SourceLocation DSStart = Tok.getLocation();

// Parse a C++23 Explicit Object Parameter
// We do that in all language modes to produce a better diagnostic.
SourceLocation ThisLoc;
if (getLangOpts().CPlusPlus && Tok.is(tok::kw_this))
ThisLoc = ConsumeToken();

ParseDeclarationSpecifiers(DS, /*TemplateInfo=*/ParsedTemplateInfo(),
AS_none, DeclSpecContext::DSC_normal,
/*LateAttrs=*/nullptr, AllowImplicitTypename);

DS.takeAttributesFrom(ArgDeclSpecAttrs);

// Parse the declarator. This is "PrototypeContext" or
Expand All @@ -7436,6 +7444,9 @@ void Parser::ParseParameterDeclarationClause(
: DeclaratorContext::Prototype);
ParseDeclarator(ParmDeclarator);

if (ThisLoc.isValid())
ParmDeclarator.SetRangeBegin(ThisLoc);

// Parse GNU attributes, if present.
MaybeParseGNUAttributes(ParmDeclarator);
if (getLangOpts().HLSL)
Expand Down Expand Up @@ -7505,7 +7516,8 @@ void Parser::ParseParameterDeclarationClause(
}
// Inform the actions module about the parameter declarator, so it gets
// added to the current scope.
Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator);
Decl *Param =
Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator, ThisLoc);
// Parse the default argument, if any. We parse the default
// arguments in all dialects; the semantic analysis in
// ActOnParamDefaultArgument will reject the default argument in
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Parse/ParseTentative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,17 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
case tok::kw___vector:
return TPResult::True;

case tok::kw_this: {
// Try to parse a C++23 Explicit Object Parameter
// We do that in all language modes to produce a better diagnostic.
if (getLangOpts().CPlusPlus) {
RevertingTentativeParsingAction PA(*this);
ConsumeToken();
return isCXXDeclarationSpecifier(AllowImplicitTypename, BracedCastResult,
InvalidAsDeclSpec);
}
return TPResult::False;
}
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
// If lookup for the template-name found nothing, don't assume we have a
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Sema/DeclSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,18 @@ bool Declarator::isStaticMember() {
getName().OperatorFunctionId.Operator));
}

bool Declarator::isExplicitObjectMemberFunction() {
if (!isFunctionDeclarator())
return false;
DeclaratorChunk::FunctionTypeInfo &Fun = getFunctionTypeInfo();
if (Fun.NumParams) {
auto *P = dyn_cast_or_null<ParmVarDecl>(Fun.Params[0].Param);
if (P && P->isExplicitObjectParameter())
return true;
}
return false;
}

bool Declarator::isCtorOrDtor() {
return (getName().getKind() == UnqualifiedIdKind::IK_ConstructorName) ||
(getName().getKind() == UnqualifiedIdKind::IK_DestructorName);
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ struct BuiltinTypeDeclBuilder {
SourceLocation(), FPOptionsOverride());

CXXThisExpr *This = CXXThisExpr::Create(
AST, SourceLocation(),
Constructor->getThisObjectType(), true);
AST, SourceLocation(), Constructor->getFunctionObjectParameterType(),
true);
Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"],
Fields["h"]->getType(), VK_LValue,
OK_Ordinary);
Expand Down Expand Up @@ -260,9 +260,9 @@ struct BuiltinTypeDeclBuilder {
auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
FnProtoLoc.setParam(0, IdxParam);

auto *This = CXXThisExpr::Create(
AST, SourceLocation(),
MethodDecl->getThisObjectType(), true);
auto *This =
CXXThisExpr::Create(AST, SourceLocation(),
MethodDecl->getFunctionObjectParameterType(), true);
auto *HandleAccess = MemberExpr::CreateImplicit(
AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary);

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Sema/ScopeInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,14 @@ void LambdaScopeInfo::visitPotentialCaptures(
}
}

bool LambdaScopeInfo::lambdaCaptureShouldBeConst() const {
if (ExplicitObjectParameter)
return ExplicitObjectParameter->getType()
.getNonReferenceType()
.isConstQualified();
return !Mutable;
}

FunctionScopeInfo::~FunctionScopeInfo() { }
BlockScopeInfo::~BlockScopeInfo() { }
CapturedRegionScopeInfo::~CapturedRegionScopeInfo() { }
49 changes: 28 additions & 21 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ static bool checkArgCountAtLeast(Sema &S, CallExpr *Call,

return S.Diag(Call->getEndLoc(), diag::err_typecheck_call_too_few_args)
<< 0 /*function call*/ << MinArgCount << ArgCount
<< Call->getSourceRange();
<< /*is non object*/ 0 << Call->getSourceRange();
}

/// Checks that a call expression's argument count is at most the desired
Expand All @@ -139,7 +139,7 @@ static bool checkArgCountAtMost(Sema &S, CallExpr *Call, unsigned MaxArgCount) {
return S.Diag(Call->getEndLoc(),
diag::err_typecheck_call_too_many_args_at_most)
<< 0 /*function call*/ << MaxArgCount << ArgCount
<< Call->getSourceRange();
<< /*is non object*/ 0 << Call->getSourceRange();
}

/// Checks that a call expression's argument count is in the desired range. This
Expand Down Expand Up @@ -168,7 +168,7 @@ static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) {

return S.Diag(Range.getBegin(), diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/ << DesiredArgCount << ArgCount
<< Call->getArg(1)->getSourceRange();
<< /*is non object*/ 0 << Call->getArg(1)->getSourceRange();
}

static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) {
Expand Down Expand Up @@ -217,7 +217,7 @@ static bool SemaBuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) {
// We need at least one argument.
if (TheCall->getNumArgs() < 1) {
S.Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
<< 0 << 1 << TheCall->getNumArgs()
<< 0 << 1 << TheCall->getNumArgs() << /*is non object*/ 0
<< TheCall->getCallee()->getSourceRange();
return true;
}
Expand Down Expand Up @@ -1578,7 +1578,7 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
if (NumArgs < 4) {
S.Diag(TheCall->getBeginLoc(),
diag::err_typecheck_call_too_few_args_at_least)
<< 0 << 4 << NumArgs;
<< 0 << 4 << NumArgs << /*is non object*/ 0;
return true;
}

Expand Down Expand Up @@ -6924,8 +6924,9 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl, QualType ThisType,
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;

auto *Ctor = cast<CXXConstructorDecl>(FDecl);
CheckArgAlignment(Loc, FDecl, "'this'", Context.getPointerType(ThisType),
Context.getPointerType(Ctor->getThisObjectType()));
CheckArgAlignment(
Loc, FDecl, "'this'", Context.getPointerType(ThisType),
Context.getPointerType(Ctor->getFunctionObjectParameterType()));

checkCall(FDecl, Proto, /*ThisArg=*/nullptr, Args, /*IsMemberFunction=*/true,
Loc, SourceRange(), CallType);
Expand All @@ -6945,14 +6946,16 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
unsigned NumArgs = TheCall->getNumArgs();

Expr *ImplicitThis = nullptr;
if (IsMemberOperatorCall && !FDecl->isStatic()) {
if (IsMemberOperatorCall && !FDecl->isStatic() &&
!FDecl->hasCXXExplicitFunctionObjectParameter()) {
// If this is a call to a non-static member operator, hide the first
// argument from checkCall.
// FIXME: Our choice of AST representation here is less than ideal.
ImplicitThis = Args[0];
++Args;
--NumArgs;
} else if (IsMemberFunction && !FDecl->isStatic())
} else if (IsMemberFunction && !FDecl->isStatic() &&
!FDecl->hasCXXExplicitFunctionObjectParameter())
ImplicitThis =
cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument();

Expand All @@ -6965,8 +6968,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
ThisType = Context.getPointerType(ThisType);
}

QualType ThisTypeFromDecl =
Context.getPointerType(cast<CXXMethodDecl>(FDecl)->getThisObjectType());
QualType ThisTypeFromDecl = Context.getPointerType(
cast<CXXMethodDecl>(FDecl)->getFunctionObjectParameterType());

CheckArgAlignment(TheCall->getRParenLoc(), FDecl, "'this'", ThisType,
ThisTypeFromDecl);
Expand Down Expand Up @@ -7293,13 +7296,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
if (Args.size() < AdjustedNumArgs) {
Diag(CallRange.getEnd(), diag::err_typecheck_call_too_few_args)
<< 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size())
<< ExprRange;
<< /*is non object*/ 0 << ExprRange;
return ExprError();
} else if (Args.size() > AdjustedNumArgs) {
Diag(Args[AdjustedNumArgs]->getBeginLoc(),
diag::err_typecheck_call_too_many_args)
<< 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size())
<< ExprRange;
<< /*is non object*/ 0 << ExprRange;
return ExprError();
}

Expand Down Expand Up @@ -7662,7 +7665,8 @@ bool Sema::BuiltinWasmRefNullExtern(CallExpr *TheCall) {
bool Sema::BuiltinWasmRefNullFunc(CallExpr *TheCall) {
if (TheCall->getNumArgs() != 0) {
Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/ << 0 << TheCall->getNumArgs();
<< 0 /*function call*/ << /*expected*/ 0 << TheCall->getNumArgs()
<< /*is non object*/ 0;
return true;
}

Expand Down Expand Up @@ -7695,7 +7699,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// Ensure that we have at least one argument to do type inference from.
if (TheCall->getNumArgs() < 1) {
Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
<< 0 << 1 << TheCall->getNumArgs() << Callee->getSourceRange();
<< 0 << 1 << TheCall->getNumArgs() << /*is non object*/ 0
<< Callee->getSourceRange();
return ExprError();
}

Expand Down Expand Up @@ -7971,7 +7976,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// have at least that many.
if (TheCall->getNumArgs() < 1+NumFixed) {
Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
<< 0 << 1 + NumFixed << TheCall->getNumArgs()
<< 0 << 1 + NumFixed << TheCall->getNumArgs() << /*is non object*/ 0
<< Callee->getSourceRange();
return ExprError();
}
Expand Down Expand Up @@ -8361,7 +8366,8 @@ bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) {
if (Call->getNumArgs() < 3)
return Diag(Call->getEndLoc(),
diag::err_typecheck_call_too_few_args_at_least)
<< 0 /*function call*/ << 3 << Call->getNumArgs();
<< 0 /*function call*/ << 3 << Call->getNumArgs()
<< /*is non object*/ 0;

// Type-check the first argument normally.
if (checkBuiltinArgument(*this, Call, 0))
Expand Down Expand Up @@ -8622,7 +8628,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
return ExprError(Diag(TheCall->getEndLoc(),
diag::err_typecheck_call_too_few_args_at_least)
<< 0 /*function call*/ << 2 << TheCall->getNumArgs()
<< TheCall->getSourceRange());
<< /*is non object*/ 0 << TheCall->getSourceRange());

// Determine which of the following types of shufflevector we're checking:
// 1) unary, vector mask: (lhs, mask)
Expand Down Expand Up @@ -8742,7 +8748,8 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
if (NumArgs > 3)
return Diag(TheCall->getEndLoc(),
diag::err_typecheck_call_too_many_args_at_most)
<< 0 /*function call*/ << 3 << NumArgs << TheCall->getSourceRange();
<< 0 /*function call*/ << 3 << NumArgs << /*is non object*/ 0
<< TheCall->getSourceRange();

// Argument 0 is checked for us and the remaining arguments must be
// constant integers.
Expand Down Expand Up @@ -8881,13 +8888,13 @@ bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) {
if (NumArgs < NumRequiredArgs) {
return Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args)
<< 0 /* function call */ << NumRequiredArgs << NumArgs
<< TheCall->getSourceRange();
<< /*is non object*/ 0 << TheCall->getSourceRange();
}
if (NumArgs >= NumRequiredArgs + 0x100) {
return Diag(TheCall->getEndLoc(),
diag::err_typecheck_call_too_many_args_at_most)
<< 0 /* function call */ << (NumRequiredArgs + 0xff) << NumArgs
<< TheCall->getSourceRange();
<< /*is non object*/ 0 << TheCall->getSourceRange();
}
unsigned i = 0;

Expand Down
16 changes: 8 additions & 8 deletions clang/lib/Sema/SemaCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
// If the function is a non-static member function, add the type
// of the implicit object parameter before the formal parameters.
if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
if (MD->isInstance()) {
if (MD->isImplicitObjectMemberFunction()) {
// [over.match.funcs]4
// For non-static member functions, the type of the implicit object
// parameter is
// -- "lvalue reference to cv X" for functions declared without a
// ref-qualifier or with the & ref-qualifier
// -- "rvalue reference to cv X" for functions declared with the &&
// ref-qualifier
QualType T = MD->getThisObjectType();
QualType T = MD->getFunctionObjectParameterType();
T = FnType->getRefQualifier() == RQ_RValue
? S.Context.getRValueReferenceType(T)
: S.Context.getLValueReferenceType(T, /*SpelledAsLValue*/ true);
Expand Down Expand Up @@ -564,10 +564,10 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
assert(isa<FunctionDecl>(CurContext) && "not in a function scope");
auto *FD = cast<FunctionDecl>(CurContext);
bool IsThisDependentType = [&] {
if (auto *MD = dyn_cast_or_null<CXXMethodDecl>(FD))
return MD->isInstance() && MD->getThisObjectType()->isDependentType();
else
return false;
if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(FD))
return MD->isImplicitObjectMemberFunction() &&
MD->getThisType()->isDependentType();
return false;
}();

QualType T = FD->getType()->isDependentType() || IsThisDependentType
Expand All @@ -592,7 +592,7 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {

// Add implicit object parameter.
if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
if (MD->isInstance() && !isLambdaCallOperator(MD)) {
if (MD->isImplicitObjectMemberFunction() && !isLambdaCallOperator(MD)) {
ExprResult ThisExpr = ActOnCXXThis(Loc);
if (ThisExpr.isInvalid())
return nullptr;
Expand Down Expand Up @@ -1367,7 +1367,7 @@ bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {
static bool collectPlacementArgs(Sema &S, FunctionDecl &FD, SourceLocation Loc,
SmallVectorImpl<Expr *> &PlacementArgs) {
if (auto *MD = dyn_cast<CXXMethodDecl>(&FD)) {
if (MD->isInstance() && !isLambdaCallOperator(MD)) {
if (MD->isImplicitObjectMemberFunction() && !isLambdaCallOperator(MD)) {
ExprResult ThisExpr = S.ActOnCXXThis(Loc);
if (ThisExpr.isInvalid())
return false;
Expand Down
57 changes: 44 additions & 13 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8924,13 +8924,11 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
CXXMethodDecl *BaseMD =
dyn_cast<CXXMethodDecl>(BaseND->getCanonicalDecl());
if (!BaseMD || !BaseMD->isVirtual() ||
IsOverload(MD, BaseMD, /*UseMemberUsingDeclRules=*/false,
/*ConsiderCudaAttrs=*/true,
// C++2a [class.virtual]p2 does not consider requires
// clauses when overriding.
/*ConsiderRequiresClauses=*/false))
IsOverride(MD, BaseMD, /*UseMemberUsingDeclRules=*/false,
/*ConsiderCudaAttrs=*/true))
continue;
if (!CheckExplicitObjectOverride(MD, BaseMD))
continue;

if (Overridden.insert(BaseMD).second) {
MD->addOverriddenMethod(BaseMD);
CheckOverridingFunctionReturnType(MD, BaseMD);
Expand Down Expand Up @@ -9265,6 +9263,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
}
Expr *TrailingRequiresClause = D.getTrailingRequiresClause();

SemaRef.CheckExplicitObjectMemberFunction(DC, D, Name, R);

if (Name.getNameKind() == DeclarationName::CXXConstructorName) {
// This is a C++ constructor declaration.
assert(DC->isRecord() &&
Expand Down Expand Up @@ -9766,8 +9766,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< DeclSpec::getSpecifierName(TSCS);

if (D.isFirstDeclarationOfMember())
adjustMemberFunctionCC(R, D.isStaticMember(), D.isCtorOrDtor(),
D.getIdentifierLoc());
adjustMemberFunctionCC(
R, !(D.isStaticMember() || D.isExplicitObjectMemberFunction()),
D.isCtorOrDtor(), D.getIdentifierLoc());

bool isFriend = false;
FunctionTemplateDecl *FunctionTemplate = nullptr;
Expand Down Expand Up @@ -11971,7 +11972,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// struct B { struct Y { ~Y(); }; using X = Y; };
// template struct A<B>;
if (NewFD->getFriendObjectKind() == Decl::FriendObjectKind::FOK_None ||
!Destructor->getThisObjectType()->isDependentType()) {
!Destructor->getFunctionObjectParameterType()->isDependentType()) {
CXXRecordDecl *Record = Destructor->getParent();
QualType ClassType = Context.getTypeDeclType(Record);

Expand Down Expand Up @@ -14918,9 +14919,32 @@ void Sema::CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D) {
}
}

static void CheckExplicitObjectParameter(Sema &S, ParmVarDecl *P,
SourceLocation ExplicitThisLoc) {
if (!ExplicitThisLoc.isValid())
return;
assert(S.getLangOpts().CPlusPlus &&
"explicit parameter in non-cplusplus mode");
if (!S.getLangOpts().CPlusPlus23)
S.Diag(ExplicitThisLoc, diag::err_cxx20_deducing_this)
<< P->getSourceRange();

// C++2b [dcl.fct/7] An explicit object parameter shall not be a function
// parameter pack.
if (P->isParameterPack()) {
S.Diag(P->getBeginLoc(), diag::err_explicit_object_parameter_pack)
<< P->getSourceRange();
return;
}
P->setExplicitObjectParameterLoc(ExplicitThisLoc);
if (LambdaScopeInfo *LSI = S.getCurLambda())
LSI->ExplicitObjectParameter = P;
}

/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
/// to introduce parameters into function prototype scope.
Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D,
SourceLocation ExplicitThisLoc) {
const DeclSpec &DS = D.getDeclSpec();

// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
Expand Down Expand Up @@ -14998,6 +15022,8 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
if (D.isInvalidType())
New->setInvalidDecl();

CheckExplicitObjectParameter(*this, New, ExplicitThisLoc);

assert(S->isFunctionPrototypeScope());
assert(S->getFunctionPrototypeDepth() >= 1);
New->setScopeInfo(S->getFunctionPrototypeDepth() - 1,
Expand Down Expand Up @@ -15395,6 +15421,8 @@ LambdaScopeInfo *Sema::RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator) {

LSI->IntroducerRange = DNI.getCXXOperatorNameRange();
LSI->Mutable = !CallOperator->isConst();
if (CallOperator->isExplicitObjectMemberFunction())
LSI->ExplicitObjectParameter = CallOperator->getParamDecl(0);

// Add the captures to the LSI so they can be noted as already
// captured within tryCaptureVar.
Expand Down Expand Up @@ -18781,10 +18809,13 @@ static bool AreSpecialMemberFunctionsSameKind(ASTContext &Context,
if (CSM == Sema::CXXDefaultConstructor)
return bool(M1->getDescribedFunctionTemplate()) ==
bool(M2->getDescribedFunctionTemplate());
if (!Context.hasSameType(M1->getParamDecl(0)->getType(),
M2->getParamDecl(0)->getType()))
// FIXME: better resolve CWG
// https://cplusplus.github.io/CWG/issues/2787.html
if (!Context.hasSameType(M1->getNonObjectParameter(0)->getType(),
M2->getNonObjectParameter(0)->getType()))
return false;
if (!Context.hasSameType(M1->getThisType(), M2->getThisType()))
if (!Context.hasSameType(M1->getFunctionObjectParameterReferenceType(),
M2->getFunctionObjectParameterReferenceType()))
return false;

return true;
Expand Down
12 changes: 6 additions & 6 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1234,7 +1234,7 @@ static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) {

static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD,
const ParsedAttr &AL) {
QualType ThisType = MD->getThisObjectType();
QualType ThisType = MD->getFunctionObjectParameterType();

if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) {
if (!RD->hasAttr<ConsumableAttr>()) {
Expand Down Expand Up @@ -1336,23 +1336,23 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// FIXME: This check is currently being done in the analysis. It can be
// enabled here only after the parser propagates attributes at
// template specialization definition, not declaration.
//QualType ReturnType;
// QualType ReturnType;
//
//if (const ParmVarDecl *Param = dyn_cast<ParmVarDecl>(D)) {
// if (const ParmVarDecl *Param = dyn_cast<ParmVarDecl>(D)) {
// ReturnType = Param->getType();
//
//} else if (const CXXConstructorDecl *Constructor =
// dyn_cast<CXXConstructorDecl>(D)) {
// ReturnType = Constructor->getThisObjectType();
// ReturnType = Constructor->getFunctionObjectParameterType();
//
//} else {
//
// ReturnType = cast<FunctionDecl>(D)->getCallResultType();
//}
//
//const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
// const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
//
//if (!RD || !RD->hasAttr<ConsumableAttr>()) {
// if (!RD || !RD->hasAttr<ConsumableAttr>()) {
// S.Diag(Attr.getLoc(), diag::warn_return_state_for_unconsumable_type) <<
// ReturnType.getAsString();
// return;
Expand Down
283 changes: 218 additions & 65 deletions clang/lib/Sema/SemaDeclCXX.cpp

Large diffs are not rendered by default.

64 changes: 33 additions & 31 deletions clang/lib/Sema/SemaExceptionSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -769,14 +769,12 @@ bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
/// CheckExceptionSpecSubset - Check whether the second function type's
/// exception specification is a subset (or equivalent) of the first function
/// type. This is used by override and pointer assignment checks.
bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
const PartialDiagnostic &NestedDiagID,
const PartialDiagnostic &NoteID,
const PartialDiagnostic &NoThrowDiagID,
const FunctionProtoType *Superset,
SourceLocation SuperLoc,
const FunctionProtoType *Subset,
SourceLocation SubLoc) {
bool Sema::CheckExceptionSpecSubset(
const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID,
const PartialDiagnostic &NoteID, const PartialDiagnostic &NoThrowDiagID,
const FunctionProtoType *Superset, bool SkipSupersetFirstParameter,
SourceLocation SuperLoc, const FunctionProtoType *Subset,
bool SkipSubsetFirstParameter, SourceLocation SubLoc) {

// Just auto-succeed under -fno-exceptions.
if (!getLangOpts().CXXExceptions)
Expand Down Expand Up @@ -816,8 +814,9 @@ bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
// done.
if ((SuperCanThrow == CT_Can && SuperEST != EST_Dynamic) ||
SubCanThrow == CT_Cannot)
return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc,
Subset, SubLoc);
return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset,
SkipSupersetFirstParameter, SuperLoc, Subset,
SkipSubsetFirstParameter, SubLoc);

// Allow __declspec(nothrow) to be missing on redeclaration as an extension in
// some cases.
Expand Down Expand Up @@ -869,8 +868,9 @@ bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
}
}
// We've run half the gauntlet.
return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc,
Subset, SubLoc);
return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset,
SkipSupersetFirstParameter, SuperLoc, Subset,
SkipSupersetFirstParameter, SubLoc);
}

static bool
Expand All @@ -894,12 +894,11 @@ CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID,
/// assignment and override compatibility check. We do not check the parameters
/// of parameter function pointers recursively, as no sane programmer would
/// even be able to write such a function type.
bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &DiagID,
const PartialDiagnostic &NoteID,
const FunctionProtoType *Target,
SourceLocation TargetLoc,
const FunctionProtoType *Source,
SourceLocation SourceLoc) {
bool Sema::CheckParamExceptionSpec(
const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,
const FunctionProtoType *Target, bool SkipTargetFirstParameter,
SourceLocation TargetLoc, const FunctionProtoType *Source,
bool SkipSourceFirstParameter, SourceLocation SourceLoc) {
auto RetDiag = DiagID;
RetDiag << 0;
if (CheckSpecForTypesEquivalent(
Expand All @@ -910,14 +909,16 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &DiagID,

// We shouldn't even be testing this unless the arguments are otherwise
// compatible.
assert(Target->getNumParams() == Source->getNumParams() &&
assert((Target->getNumParams() - (unsigned)SkipTargetFirstParameter) ==
(Source->getNumParams() - (unsigned)SkipSourceFirstParameter) &&
"Functions have different argument counts.");
for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) {
auto ParamDiag = DiagID;
ParamDiag << 1;
if (CheckSpecForTypesEquivalent(
*this, ParamDiag, PDiag(),
Target->getParamType(i), TargetLoc, Source->getParamType(i),
Target->getParamType(i + (SkipTargetFirstParameter ? 1 : 0)),
TargetLoc, Source->getParamType(SkipSourceFirstParameter ? 1 : 0),
SourceLoc))
return true;
}
Expand Down Expand Up @@ -958,9 +959,10 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
// void (*q)(void (*) throw(int)) = p;
// }
// ... because it might be instantiated with T=int.
return CheckExceptionSpecSubset(
PDiag(DiagID), PDiag(NestedDiagID), PDiag(), PDiag(), ToFunc,
From->getSourceRange().getBegin(), FromFunc, SourceLocation()) &&
return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(NestedDiagID), PDiag(),
PDiag(), ToFunc, 0,
From->getSourceRange().getBegin(), FromFunc,
0, SourceLocation()) &&
!getLangOpts().CPlusPlus17;
}

Expand Down Expand Up @@ -989,14 +991,14 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
unsigned DiagID = diag::err_override_exception_spec;
if (getLangOpts().MSVCCompat)
DiagID = diag::ext_override_exception_spec;
return CheckExceptionSpecSubset(PDiag(DiagID),
PDiag(diag::err_deep_exception_specs_differ),
PDiag(diag::note_overridden_virtual_function),
PDiag(diag::ext_override_exception_spec),
Old->getType()->castAs<FunctionProtoType>(),
Old->getLocation(),
New->getType()->castAs<FunctionProtoType>(),
New->getLocation());
return CheckExceptionSpecSubset(
PDiag(DiagID), PDiag(diag::err_deep_exception_specs_differ),
PDiag(diag::note_overridden_virtual_function),
PDiag(diag::ext_override_exception_spec),
Old->getType()->castAs<FunctionProtoType>(),
Old->hasCXXExplicitFunctionObjectParameter(), Old->getLocation(),
New->getType()->castAs<FunctionProtoType>(),
New->hasCXXExplicitFunctionObjectParameter(), New->getLocation());
}

static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) {
Expand Down
161 changes: 113 additions & 48 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2444,7 +2444,7 @@ bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) {
// FIXME: Is this special case necessary? We could allow the caller to
// diagnose this.
if (isDefaultArgument && ((*R.begin())->isCXXInstanceMember())) {
Diag(R.getNameLoc(), diag::err_member_call_without_object);
Diag(R.getNameLoc(), diag::err_member_call_without_object) << 0;
return true;
}

Expand Down Expand Up @@ -3217,11 +3217,11 @@ Sema::PerformObjectMemberConversion(Expr *From,
FromRecordType = FromType;
}
} else if (const auto *Method = dyn_cast<CXXMethodDecl>(Member)) {
if (Method->isStatic())
if (!Method->isImplicitObjectMemberFunction())
return From;

DestType = Method->getThisType().getNonReferenceType();
DestRecordType = Method->getThisObjectType();
DestRecordType = Method->getFunctionObjectParameterType();

if (FromType->getAs<PointerType>()) {
FromRecordType = FromType->getPointeeType();
Expand Down Expand Up @@ -6503,6 +6503,9 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,

// C99 6.5.2.2p7 - the arguments are implicitly converted, as if by
// assignment, to the types of the corresponding parameter, ...
bool HasExplicitObjectParameter =
FDecl && FDecl->hasCXXExplicitFunctionObjectParameter();
unsigned ExplicitObjectParameterOffset = HasExplicitObjectParameter ? 1 : 0;
unsigned NumParams = Proto->getNumParams();
bool Invalid = false;
unsigned MinArgs = FDecl ? FDecl->getMinRequiredArguments() : NumParams;
Expand All @@ -6521,21 +6524,29 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
MinArgs == NumParams && !Proto->isVariadic()
? diag::err_typecheck_call_too_few_args_suggest
: diag::err_typecheck_call_too_few_args_at_least_suggest;
diagnoseTypo(TC, PDiag(diag_id) << FnKind << MinArgs
<< static_cast<unsigned>(Args.size())
<< TC.getCorrectionRange());
} else if (MinArgs == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName())
diagnoseTypo(
TC, PDiag(diag_id)
<< FnKind << MinArgs - ExplicitObjectParameterOffset
<< static_cast<unsigned>(Args.size()) -
ExplicitObjectParameterOffset
<< HasExplicitObjectParameter << TC.getCorrectionRange());
} else if (MinArgs - ExplicitObjectParameterOffset == 1 && FDecl &&
FDecl->getParamDecl(ExplicitObjectParameterOffset)
->getDeclName())
Diag(RParenLoc,
MinArgs == NumParams && !Proto->isVariadic()
? diag::err_typecheck_call_too_few_args_one
: diag::err_typecheck_call_too_few_args_at_least_one)
<< FnKind << FDecl->getParamDecl(0) << Fn->getSourceRange();
<< FnKind << FDecl->getParamDecl(ExplicitObjectParameterOffset)
<< HasExplicitObjectParameter << Fn->getSourceRange();
else
Diag(RParenLoc, MinArgs == NumParams && !Proto->isVariadic()
? diag::err_typecheck_call_too_few_args
: diag::err_typecheck_call_too_few_args_at_least)
<< FnKind << MinArgs << static_cast<unsigned>(Args.size())
<< Fn->getSourceRange();
<< FnKind << MinArgs - ExplicitObjectParameterOffset
<< static_cast<unsigned>(Args.size()) -
ExplicitObjectParameterOffset
<< HasExplicitObjectParameter << Fn->getSourceRange();

// Emit the location of the prototype.
if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
Expand All @@ -6560,26 +6571,34 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
MinArgs == NumParams && !Proto->isVariadic()
? diag::err_typecheck_call_too_many_args_suggest
: diag::err_typecheck_call_too_many_args_at_most_suggest;
diagnoseTypo(TC, PDiag(diag_id) << FnKind << NumParams
<< static_cast<unsigned>(Args.size())
<< TC.getCorrectionRange());
} else if (NumParams == 1 && FDecl &&
FDecl->getParamDecl(0)->getDeclName())
diagnoseTypo(
TC, PDiag(diag_id)
<< FnKind << NumParams - ExplicitObjectParameterOffset
<< static_cast<unsigned>(Args.size()) -
ExplicitObjectParameterOffset
<< HasExplicitObjectParameter << TC.getCorrectionRange());
} else if (NumParams - ExplicitObjectParameterOffset == 1 && FDecl &&
FDecl->getParamDecl(ExplicitObjectParameterOffset)
->getDeclName())
Diag(Args[NumParams]->getBeginLoc(),
MinArgs == NumParams
? diag::err_typecheck_call_too_many_args_one
: diag::err_typecheck_call_too_many_args_at_most_one)
<< FnKind << FDecl->getParamDecl(0)
<< static_cast<unsigned>(Args.size()) << Fn->getSourceRange()
<< FnKind << FDecl->getParamDecl(ExplicitObjectParameterOffset)
<< static_cast<unsigned>(Args.size()) -
ExplicitObjectParameterOffset
<< HasExplicitObjectParameter << Fn->getSourceRange()
<< SourceRange(Args[NumParams]->getBeginLoc(),
Args.back()->getEndLoc());
else
Diag(Args[NumParams]->getBeginLoc(),
MinArgs == NumParams
? diag::err_typecheck_call_too_many_args
: diag::err_typecheck_call_too_many_args_at_most)
<< FnKind << NumParams << static_cast<unsigned>(Args.size())
<< Fn->getSourceRange()
<< FnKind << NumParams - ExplicitObjectParameterOffset
<< static_cast<unsigned>(Args.size()) -
ExplicitObjectParameterOffset
<< HasExplicitObjectParameter << Fn->getSourceRange()
<< SourceRange(Args[NumParams]->getBeginLoc(),
Args.back()->getEndLoc());

Expand Down Expand Up @@ -7661,9 +7680,9 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
}

if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl))
if (!Method->isStatic())
if (Method->isImplicitObjectMemberFunction())
return ExprError(Diag(LParenLoc, diag::err_member_call_without_object)
<< Fn->getSourceRange());
<< Fn->getSourceRange() << 0);

// Check for sentinels
if (NDecl)
Expand Down Expand Up @@ -14955,6 +14974,34 @@ static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc,
S.Diag(Loc, diag::err_typecheck_address_of) << Type << E->getSourceRange();
}

bool Sema::CheckUseOfCXXMethodAsAddressOfOperand(SourceLocation OpLoc,
const Expr *Op,
const CXXMethodDecl *MD) {
const auto *DRE = cast<DeclRefExpr>(Op->IgnoreParens());

if (Op != DRE)
return Diag(OpLoc, diag::err_parens_pointer_member_function)
<< Op->getSourceRange();

// Taking the address of a dtor is illegal per C++ [class.dtor]p2.
if (isa<CXXDestructorDecl>(MD))
return Diag(OpLoc, diag::err_typecheck_addrof_dtor)
<< DRE->getSourceRange();

if (DRE->getQualifier())
return false;

if (MD->getParent()->getName().empty())
return Diag(OpLoc, diag::err_unqualified_pointer_member_function)
<< DRE->getSourceRange();

SmallString<32> Str;
StringRef Qual = (MD->getParent()->getName() + "::").toStringRef(Str);
return Diag(OpLoc, diag::err_unqualified_pointer_member_function)
<< DRE->getSourceRange()
<< FixItHint::CreateInsertion(DRE->getSourceRange().getBegin(), Qual);
}

/// CheckAddressOfOperand - The operand of & must be either a function
/// designator or an lvalue designating an object. If it is an lvalue, the
/// object cannot be declared with storage class register or be a bit field.
Expand Down Expand Up @@ -15064,28 +15111,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
DeclRefExpr *DRE = cast<DeclRefExpr>(op);
CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());

// The id-expression was parenthesized.
if (OrigOp.get() != DRE) {
Diag(OpLoc, diag::err_parens_pointer_member_function)
<< OrigOp.get()->getSourceRange();

// The method was named without a qualifier.
} else if (!DRE->getQualifier()) {
if (MD->getParent()->getName().empty())
Diag(OpLoc, diag::err_unqualified_pointer_member_function)
<< op->getSourceRange();
else {
SmallString<32> Str;
StringRef Qual = (MD->getParent()->getName() + "::").toStringRef(Str);
Diag(OpLoc, diag::err_unqualified_pointer_member_function)
<< op->getSourceRange()
<< FixItHint::CreateInsertion(op->getSourceRange().getBegin(), Qual);
}
}

// Taking the address of a dtor is illegal per C++ [class.dtor]p2.
if (isa<CXXDestructorDecl>(MD))
Diag(OpLoc, diag::err_typecheck_addrof_dtor) << op->getSourceRange();
CheckUseOfCXXMethodAsAddressOfOperand(OpLoc, OrigOp.get(), MD);

QualType MPTy = Context.getMemberPointerType(
op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr());
Expand All @@ -15105,7 +15131,11 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
<< op->getType() << op->getSourceRange();
return QualType();
}
} else if (const auto *DRE = dyn_cast<DeclRefExpr>(op)) {
if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->getDecl()))
CheckUseOfCXXMethodAsAddressOfOperand(OpLoc, OrigOp.get(), MD);
}

} else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1
// The operand cannot be a bit-field
AddressOfError = AO_Bit_Field;
Expand Down Expand Up @@ -16496,7 +16526,7 @@ bool Sema::isQualifiedMemberAccess(Expr *E) {
if (isa<FieldDecl>(VD) || isa<IndirectFieldDecl>(VD))
return true;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(VD))
return Method->isInstance();
return Method->isImplicitObjectMemberFunction();

return false;
}
Expand All @@ -16507,7 +16537,7 @@ bool Sema::isQualifiedMemberAccess(Expr *E) {

for (NamedDecl *D : ULE->decls()) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (Method->isInstance())
if (Method->isImplicitObjectMemberFunction())
return true;
} else {
// Overload set does not contain methods.
Expand Down Expand Up @@ -19227,7 +19257,8 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI,
// private instances of the captured declarations.
const Capture &Cap = CSI->getCapture(Var);
if (Cap.isCopyCapture() &&
!(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable) &&
!(isa<LambdaScopeInfo>(CSI) &&
!cast<LambdaScopeInfo>(CSI)->lambdaCaptureShouldBeConst()) &&
!(isa<CapturedRegionScopeInfo>(CSI) &&
cast<CapturedRegionScopeInfo>(CSI)->CapRegionKind == CR_OpenMP))
DeclRefType.addConst();
Expand Down Expand Up @@ -19544,7 +19575,8 @@ static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var,
// declared const (9.3.1) if and only if the lambda-expression's
// parameter-declaration-clause is not followed by mutable.
DeclRefType = CaptureType.getNonReferenceType();
if (!LSI->Mutable && !CaptureType->isReferenceType())
bool Const = LSI->lambdaCaptureShouldBeConst();
if (Const && !CaptureType->isReferenceType())
DeclRefType.addConst();
}

Expand Down Expand Up @@ -20612,6 +20644,34 @@ void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
DoMarkVarDeclReferenced(*this, Loc, Var, nullptr, RefsMinusAssignments);
}

// C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
// - an identifier associated by name lookup with an entity captured by copy
// in a lambda-expression that has an explicit object parameter whose type
// is dependent ([dcl.fct]),
static void FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter(
Sema &SemaRef, ValueDecl *D, Expr *E) {
auto *ID = dyn_cast<DeclRefExpr>(E);
if (!ID || ID->isTypeDependent())
return;

auto IsDependent = [&]() {
const LambdaScopeInfo *LSI = SemaRef.getCurLambda();
if (!LSI)
return false;
if (!LSI->ExplicitObjectParameter ||
!LSI->ExplicitObjectParameter->getType()->isDependentType())
return false;
if (!LSI->CaptureMap.count(D))
return false;
const Capture &Cap = LSI->getCapture(D);
return !Cap.isCopyCapture();
}();

ID->setCapturedByCopyInLambdaWithExplicitObjectParameter(
IsDependent, SemaRef.getASTContext());
}

static void
MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E,
bool MightBeOdrUse,
Expand All @@ -20621,14 +20681,19 @@ MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E,

if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
DoMarkVarDeclReferenced(SemaRef, Loc, Var, E, RefsMinusAssignments);
if (SemaRef.getLangOpts().CPlusPlus)
FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter(SemaRef,
Var, E);
return;
}

if (BindingDecl *Decl = dyn_cast<BindingDecl>(D)) {
DoMarkBindingDeclReferenced(SemaRef, Loc, Decl, E);
if (SemaRef.getLangOpts().CPlusPlus)
FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter(SemaRef,
Decl, E);
return;
}

SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse);

// If this is a call to a method via a cast, also mark the method in the
Expand Down
98 changes: 25 additions & 73 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1160,7 +1160,7 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda(
auto C = CurLSI->getCXXThisCapture();

if (C.isCopyCapture()) {
if (!CurLSI->Mutable)
if (CurLSI->lambdaCaptureShouldBeConst())
ClassType.addConst();
return ASTCtx.getPointerType(ClassType);
}
Expand Down Expand Up @@ -1216,11 +1216,11 @@ QualType Sema::getCurrentThisType() {
QualType ThisTy = CXXThisTypeOverride;

if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) {
if (method && method->isInstance())
if (method && method->isImplicitObjectMemberFunction())
ThisTy = method->getThisType().getNonReferenceType();
}

if (ThisTy.isNull() && isLambdaCallOperator(CurContext) &&
if (ThisTy.isNull() && isLambdaCallWithImplicitObjectParameter(CurContext) &&
inTemplateInstantiation() && isa<CXXRecordDecl>(DC)) {

// This is a lambda call operator that is being instantiated as a default
Expand Down Expand Up @@ -1398,10 +1398,22 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
/// is a non-lvalue expression whose value is the address of the object for
/// which the function is called.

QualType ThisTy = getCurrentThisType();
if (ThisTy.isNull())
return Diag(Loc, diag::err_invalid_this_use);

if (ThisTy.isNull()) {
DeclContext *DC = getFunctionLevelDeclContext();

if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
Method && Method->isExplicitObjectMemberFunction()) {
return Diag(Loc, diag::err_invalid_this_use) << 1;
}

if (isLambdaCallWithExplicitObjectParameter(CurContext))
return Diag(Loc, diag::err_invalid_this_use) << 1;

return Diag(Loc, diag::err_invalid_this_use) << 0;
}

return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
}

Expand Down Expand Up @@ -3960,7 +3972,7 @@ void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc,
if (getSourceManager().isInSystemHeader(PointeeRD->getLocation()))
return;

QualType ClassType = dtor->getThisObjectType();
QualType ClassType = dtor->getFunctionObjectParameterType();
if (PointeeRD->isAbstract()) {
// If the class is abstract, we warn by default, because we're
// sure the code has undefined behavior.
Expand Down Expand Up @@ -4319,15 +4331,17 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (DiagnoseUseOfDecl(Fn, From->getBeginLoc()))
return ExprError();

From = FixOverloadedFunctionReference(From, Found, Fn);
ExprResult Res = FixOverloadedFunctionReference(From, Found, Fn);
if (Res.isInvalid())
return ExprError();

// We might get back another placeholder expression if we resolved to a
// builtin.
ExprResult Checked = CheckPlaceholderExpr(From);
if (Checked.isInvalid())
Res = CheckPlaceholderExpr(Res.get());
if (Res.isInvalid())
return ExprError();

From = Checked.get();
From = Res.get();
FromType = From->getType();
}

Expand Down Expand Up @@ -8052,68 +8066,6 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
Destructed);
}

ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
CXXConversionDecl *Method,
bool HadMultipleCandidates) {
// Convert the expression to match the conversion function's implicit object
// parameter.
ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/nullptr,
FoundDecl, Method);
if (Exp.isInvalid())
return true;

if (Method->getParent()->isLambda() &&
Method->getConversionType()->isBlockPointerType()) {
// This is a lambda conversion to block pointer; check if the argument
// was a LambdaExpr.
Expr *SubE = E;
CastExpr *CE = dyn_cast<CastExpr>(SubE);
if (CE && CE->getCastKind() == CK_NoOp)
SubE = CE->getSubExpr();
SubE = SubE->IgnoreParens();
if (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(SubE))
SubE = BE->getSubExpr();
if (isa<LambdaExpr>(SubE)) {
// For the conversion to block pointer on a lambda expression, we
// construct a special BlockLiteral instead; this doesn't really make
// a difference in ARC, but outside of ARC the resulting block literal
// follows the normal lifetime rules for block literals instead of being
// autoreleased.
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated);
ExprResult BlockExp = BuildBlockForLambdaConversion(
Exp.get()->getExprLoc(), Exp.get()->getExprLoc(), Method, Exp.get());
PopExpressionEvaluationContext();

// FIXME: This note should be produced by a CodeSynthesisContext.
if (BlockExp.isInvalid())
Diag(Exp.get()->getExprLoc(), diag::note_lambda_to_block_conv);
return BlockExp;
}
}

MemberExpr *ME =
BuildMemberExpr(Exp.get(), /*IsArrow=*/false, SourceLocation(),
NestedNameSpecifierLoc(), SourceLocation(), Method,
DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()),
HadMultipleCandidates, DeclarationNameInfo(),
Context.BoundMemberTy, VK_PRValue, OK_Ordinary);

QualType ResultType = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);

CXXMemberCallExpr *CE = CXXMemberCallExpr::Create(
Context, ME, /*Args=*/{}, ResultType, VK, Exp.get()->getEndLoc(),
CurFPFeatureOverrides());

if (CheckFunctionCall(Method, CE,
Method->getType()->castAs<FunctionProtoType>()))
return ExprError();

return CheckForImmediateInvocation(CE, CE->getMethodDecl());
}

ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand,
SourceLocation RParen) {
// If the operand is an unresolved lookup expression, the expression is ill-
Expand Down
Loading