#include "CheckExprLifetime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DependenceFlags.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include <algorithm>
#include <cstddef>
#include <cstdlib>
#include <optional>
using namespace clang;
using namespace sema;
using AllowedExplicit = Sema::AllowedExplicit;
static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) {
return llvm::any_of(FD->parameters(), [](const ParmVarDecl *P) {
return P->hasAttr<PassObjectSizeAttr>();
});
}
static ExprResult CreateFunctionRefExpr(
Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, const Expr *Base,
bool HadMultipleCandidates, SourceLocation Loc = SourceLocation(),
const DeclarationNameLoc &LocInfo = DeclarationNameLoc()) {
if (S.DiagnoseUseOfDecl(FoundDecl, Loc))
return ExprError();
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
return ExprError();
DeclRefExpr *DRE = new (S.Context)
DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
S.MarkDeclRefReferenced(DRE, Base);
if (auto *FPT = DRE->getType()->getAs<FunctionProtoType>()) {
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
S.ResolveExceptionSpec(Loc, FPT);
DRE->setType(Fn->getType());
}
}
return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
CK_FunctionToPointerDecay);
}
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle,
bool AllowObjCWritebackConversion);
static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From,
QualType &ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle);
static OverloadingResult
IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
OverloadCandidateSet& Conversions,
AllowedExplicit AllowExplicit,
bool AllowObjCConversionOnExplicit);
static ImplicitConversionSequence::CompareKind
CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
static ImplicitConversionSequence::CompareKind
CompareQualificationConversions(Sema &S,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
static ImplicitConversionSequence::CompareKind
CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
static const ImplicitConversionRank Rank[] = {
ICR_Exact_Match,
ICR_Exact_Match,
ICR_Exact_Match,
ICR_Exact_Match,
ICR_Exact_Match,
ICR_Exact_Match,
ICR_Promotion,
ICR_Promotion,
ICR_Promotion,
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_OCL_Scalar_Widening,
ICR_Complex_Real_Conversion,
ICR_Conversion,
ICR_Conversion,
ICR_Writeback_Conversion,
ICR_Exact_Match,
ICR_Exact_Match,
ICR_C_Conversion,
ICR_C_Conversion_Extension,
ICR_Conversion,
ICR_HLSL_Dimension_Reduction,
ICR_Conversion,
ICR_HLSL_Scalar_Widening,
};
static_assert(std::size(Rank) == (int)ICK_Num_Conversion_Kinds);
return Rank[(int)Kind];
}
ImplicitConversionRank
clang::GetDimensionConversionRank(ImplicitConversionRank Base,
ImplicitConversionKind Dimension) {
ImplicitConversionRank Rank = GetConversionRank(Dimension);
if (Rank == ICR_HLSL_Scalar_Widening) {
if (Base == ICR_Promotion)
return ICR_HLSL_Scalar_Widening_Promotion;
if (Base == ICR_Conversion)
return ICR_HLSL_Scalar_Widening_Conversion;
}
if (Rank == ICR_HLSL_Dimension_Reduction) {
if (Base == ICR_Promotion)
return ICR_HLSL_Dimension_Reduction_Promotion;
if (Base == ICR_Conversion)
return ICR_HLSL_Dimension_Reduction_Conversion;
}
return Rank;
}
static const char *GetImplicitConversionName(ImplicitConversionKind Kind) {
static const char *const Name[] = {
"No conversion",
"Lvalue-to-rvalue",
"Array-to-pointer",
"Function-to-pointer",
"Function pointer conversion",
"Qualification",
"Integral promotion",
"Floating point promotion",
"Complex promotion",
"Integral conversion",
"Floating conversion",
"Complex conversion",
"Floating-integral conversion",
"Pointer conversion",
"Pointer-to-member conversion",
"Boolean conversion",
"Compatible-types conversion",
"Derived-to-base conversion",
"Vector conversion",
"SVE Vector conversion",
"RVV Vector conversion",
"Vector splat",
"Complex-real conversion",
"Block Pointer conversion",
"Transparent Union Conversion",
"Writeback conversion",
"OpenCL Zero Event Conversion",
"OpenCL Zero Queue Conversion",
"C specific type conversion",
"Incompatible pointer conversion",
"Fixed point conversion",
"HLSL vector truncation",
"Non-decaying array conversion",
"HLSL vector splat",
};
static_assert(std::size(Name) == (int)ICK_Num_Conversion_Kinds);
return Name[Kind];
}
void StandardConversionSequence::setAsIdentityConversion() {
First = ICK_Identity;
Second = ICK_Identity;
Dimension = ICK_Identity;
Third = ICK_Identity;
DeprecatedStringLiteralToCharPtr = false;
QualificationIncludesObjCLifetime = false;
ReferenceBinding = false;
DirectBinding = false;
IsLvalueReference = true;
BindsToFunctionLvalue = false;
BindsToRvalue = false;
BindsImplicitObjectArgumentWithoutRefQualifier = false;
ObjCLifetimeConversionBinding = false;
CopyConstructor = nullptr;
}
ImplicitConversionRank StandardConversionSequence::getRank() const {
ImplicitConversionRank Rank = ICR_Exact_Match;
if (GetConversionRank(First) > Rank)
Rank = GetConversionRank(First);
if (GetConversionRank(Second) > Rank)
Rank = GetConversionRank(Second);
if (GetDimensionConversionRank(Rank, Dimension) > Rank)
Rank = GetDimensionConversionRank(Rank, Dimension);
if (GetConversionRank(Third) > Rank)
Rank = GetConversionRank(Third);
return Rank;
}
bool StandardConversionSequence::isPointerConversionToBool() const {
if (getToType(1)->isBooleanType() &&
(getFromType()->isPointerType() ||
getFromType()->isMemberPointerType() ||
getFromType()->isObjCObjectPointerType() ||
getFromType()->isBlockPointerType() ||
First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer))
return true;
return false;
}
bool
StandardConversionSequence::
isPointerConversionToVoidPointer(ASTContext& Context) const {
QualType FromType = getFromType();
QualType ToType = getToType(1);
if (First == ICK_Array_To_Pointer)
FromType = Context.getArrayDecayedType(FromType);
if (Second == ICK_Pointer_Conversion && FromType->isAnyPointerType())
if (const PointerType* ToPtrType = ToType->getAs<PointerType>())
return ToPtrType->getPointeeType()->isVoidType();
return false;
}
static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx,
const Expr *Converted) {
if (auto *EWC = dyn_cast<ExprWithCleanups>(Converted)) {
Expr *Inner =
const_cast<Expr *>(IgnoreNarrowingConversion(Ctx, EWC->getSubExpr()));
return ExprWithCleanups::Create(Ctx, Inner, EWC->cleanupsHaveSideEffects(),
EWC->getObjects());
}
while (auto *ICE = dyn_cast<ImplicitCastExpr>(Converted)) {
switch (ICE->getCastKind()) {
case CK_NoOp:
case CK_IntegralCast:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_BooleanToSignedIntegral:
case CK_FloatingToIntegral:
case CK_FloatingToBoolean:
case CK_FloatingCast:
Converted = ICE->getSubExpr();
continue;
default:
return Converted;
}
}
return Converted;
}
NarrowingKind StandardConversionSequence::getNarrowingKind(
ASTContext &Ctx, const Expr *Converted, APValue &ConstantValue,
QualType &ConstantType, bool IgnoreFloatToIntegralConversion) const {
assert((Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23) &&
"narrowing check outside C++");
QualType FromType = getToType(0);
QualType ToType = getToType(1);
if (auto *ET = ToType->getAs<EnumType>())
ToType = ET->getDecl()->getIntegerType();
switch (Second) {
case ICK_Boolean_Conversion:
if (FromType->isRealFloatingType())
goto FloatingIntegralConversion;
if (FromType->isIntegralOrUnscopedEnumerationType())
goto IntegralConversion;
return NK_Type_Narrowing;
case ICK_Floating_Integral:
FloatingIntegralConversion:
if (FromType->isRealFloatingType() && ToType->isIntegralType(Ctx)) {
return NK_Type_Narrowing;
} else if (FromType->isIntegralOrUnscopedEnumerationType() &&
ToType->isRealFloatingType()) {
if (IgnoreFloatToIntegralConversion)
return NK_Not_Narrowing;
const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
assert(Initializer && "Unknown conversion expression");
if (Initializer->isValueDependent())
return NK_Dependent_Narrowing;
if (std::optional<llvm::APSInt> IntConstantValue =
Initializer->getIntegerConstantExpr(Ctx)) {
llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType));
Result.convertFromAPInt(*IntConstantValue, IntConstantValue->isSigned(),
llvm::APFloat::rmNearestTiesToEven);
llvm::APSInt ConvertedValue = *IntConstantValue;
bool ignored;
Result.convertToInteger(ConvertedValue,
llvm::APFloat::rmTowardZero, &ignored);
if (*IntConstantValue != ConvertedValue) {
ConstantValue = APValue(*IntConstantValue);
ConstantType = Initializer->getType();
return NK_Constant_Narrowing;
}
} else {
return NK_Variable_Narrowing;
}
}
return NK_Not_Narrowing;
case ICK_Floating_Conversion:
if (FromType->isRealFloatingType() && ToType->isRealFloatingType() &&
Ctx.getFloatingTypeOrder(FromType, ToType) == 1) {
const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
if (Initializer->isValueDependent())
return NK_Dependent_Narrowing;
Expr::EvalResult R;
if ((Ctx.getLangOpts().C23 && Initializer->EvaluateAsRValue(R, Ctx)) ||
Initializer->isCXX11ConstantExpr(Ctx, &ConstantValue)) {
if (Ctx.getLangOpts().C23)
ConstantValue = R.Val;
assert(ConstantValue.isFloat());
llvm::APFloat FloatVal = ConstantValue.getFloat();
bool ignored;
llvm::APFloat Converted = FloatVal;
llvm::APFloat::opStatus ConvertStatus =
Converted.convert(Ctx.getFloatTypeSemantics(ToType),
llvm::APFloat::rmNearestTiesToEven, &ignored);
Converted.convert(Ctx.getFloatTypeSemantics(FromType),
llvm::APFloat::rmNearestTiesToEven, &ignored);
if (Ctx.getLangOpts().C23) {
if (FloatVal.isNaN() && Converted.isNaN() &&
!FloatVal.isSignaling() && !Converted.isSignaling()) {
return NK_Not_Narrowing;
}
if (!Converted.bitwiseIsEqual(FloatVal)) {
ConstantType = Initializer->getType();
return NK_Constant_Narrowing;
}
} else {
if (ConvertStatus & llvm::APFloat::opOverflow) {
ConstantType = Initializer->getType();
return NK_Constant_Narrowing;
}
}
} else {
return NK_Variable_Narrowing;
}
}
return NK_Not_Narrowing;
case ICK_Integral_Conversion:
IntegralConversion: {
assert(FromType->isIntegralOrUnscopedEnumerationType());
assert(ToType->isIntegralOrUnscopedEnumerationType());
const bool FromSigned = FromType->isSignedIntegerOrEnumerationType();
const unsigned FromWidth = Ctx.getIntWidth(FromType);
const bool ToSigned = ToType->isSignedIntegerOrEnumerationType();
const unsigned ToWidth = Ctx.getIntWidth(ToType);
if (FromWidth > ToWidth ||
(FromWidth == ToWidth && FromSigned != ToSigned) ||
(FromSigned && !ToSigned)) {
const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
if (Initializer->isValueDependent())
return NK_Dependent_Narrowing;
std::optional<llvm::APSInt> OptInitializerValue;
if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) {
return NK_Variable_Narrowing;
}
llvm::APSInt &InitializerValue = *OptInitializerValue;
bool Narrowing = false;
if (FromWidth < ToWidth) {
if (InitializerValue.isSigned() && InitializerValue.isNegative())
Narrowing = true;
} else {
InitializerValue = InitializerValue.extend(
InitializerValue.getBitWidth() + 1);
llvm::APSInt ConvertedValue = InitializerValue;
ConvertedValue = ConvertedValue.trunc(ToWidth);
ConvertedValue.setIsSigned(ToSigned);
ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
ConvertedValue.setIsSigned(InitializerValue.isSigned());
if (ConvertedValue != InitializerValue)
Narrowing = true;
}
if (Narrowing) {
ConstantType = Initializer->getType();
ConstantValue = APValue(InitializerValue);
return NK_Constant_Narrowing;
}
}
return NK_Not_Narrowing;
}
case ICK_Complex_Real:
if (FromType->isComplexType() && !ToType->isComplexType())
return NK_Type_Narrowing;
return NK_Not_Narrowing;
case ICK_Floating_Promotion:
if (Ctx.getLangOpts().C23) {
const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
Expr::EvalResult R;
if (Initializer->EvaluateAsRValue(R, Ctx)) {
ConstantValue = R.Val;
assert(ConstantValue.isFloat());
llvm::APFloat FloatVal = ConstantValue.getFloat();
if (FloatVal.isNaN() && FloatVal.isSignaling()) {
ConstantType = Initializer->getType();
return NK_Constant_Narrowing;
}
}
}
return NK_Not_Narrowing;
default:
return NK_Not_Narrowing;
}
}
LLVM_DUMP_METHOD void StandardConversionSequence::dump() const {
raw_ostream &OS = llvm::errs();
bool PrintedSomething = false;
if (First != ICK_Identity) {
OS << GetImplicitConversionName(First);
PrintedSomething = true;
}
if (Second != ICK_Identity) {
if (PrintedSomething) {
OS << " -> ";
}
OS << GetImplicitConversionName(Second);
if (CopyConstructor) {
OS << " (by copy constructor)";
} else if (DirectBinding) {
OS << " (direct reference binding)";
} else if (ReferenceBinding) {
OS << " (reference binding)";
}
PrintedSomething = true;
}
if (Third != ICK_Identity) {
if (PrintedSomething) {
OS << " -> ";
}
OS << GetImplicitConversionName(Third);
PrintedSomething = true;
}
if (!PrintedSomething) {
OS << "No conversions required";
}
}
void UserDefinedConversionSequence::dump() const {
raw_ostream &OS = llvm::errs();
if (Before.First || Before.Second || Before.Third) {
Before.dump();
OS << " -> ";
}
if (ConversionFunction)
OS << '\'' << *ConversionFunction << '\'';
else
OS << "aggregate initialization";
if (After.First || After.Second || After.Third) {
OS << " -> ";
After.dump();
}
}
void ImplicitConversionSequence::dump() const {
raw_ostream &OS = llvm::errs();
if (hasInitializerListContainerType())
OS << "Worst list element conversion: ";
switch (ConversionKind) {
case StandardConversion:
OS << "Standard conversion: ";
Standard.dump();
break;
case UserDefinedConversion:
OS << "User-defined conversion: ";
UserDefined.dump();
break;
case EllipsisConversion:
OS << "Ellipsis conversion";
break;
case AmbiguousConversion:
OS << "Ambiguous conversion";
break;
case BadConversion:
OS << "Bad conversion";
break;
}
OS << "\n";
}
void AmbiguousConversionSequence::construct() {
new (&conversions()) ConversionSet();
}
void AmbiguousConversionSequence::destruct() {
conversions().~ConversionSet();
}
void
AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) {
FromTypePtr = O.FromTypePtr;
ToTypePtr = O.ToTypePtr;
new (&conversions()) ConversionSet(O.conversions());
}
namespace {
struct DFIArguments {
TemplateArgument FirstArg;
TemplateArgument SecondArg;
};
struct DFIParamWithArguments : DFIArguments {
TemplateParameter Param;
};
struct DFIDeducedMismatchArgs : DFIArguments {
TemplateArgumentList *TemplateArgs;
unsigned CallArgIndex;
};
struct CNSInfo {
TemplateArgumentList *TemplateArgs;
ConstraintSatisfaction Satisfaction;
};
}
DeductionFailureInfo
clang::MakeDeductionFailureInfo(ASTContext &Context,
TemplateDeductionResult TDK,
TemplateDeductionInfo &Info) {
DeductionFailureInfo Result;
Result.Result = static_cast<unsigned>(TDK);
Result.HasDiagnostic = false;
switch (TDK) {
case TemplateDeductionResult::Invalid:
case TemplateDeductionResult::InstantiationDepth:
case TemplateDeductionResult::TooManyArguments:
case TemplateDeductionResult::TooFewArguments:
case TemplateDeductionResult::MiscellaneousDeductionFailure:
case TemplateDeductionResult::CUDATargetMismatch:
Result.Data = nullptr;
break;
case TemplateDeductionResult::Incomplete:
case TemplateDeductionResult::InvalidExplicitArguments:
Result.Data = Info.Param.getOpaqueValue();
break;
case TemplateDeductionResult::DeducedMismatch:
case TemplateDeductionResult::DeducedMismatchNested: {
auto *Saved = new (Context) DFIDeducedMismatchArgs;
Saved->FirstArg = Info.FirstArg;
Saved->SecondArg = Info.SecondArg;
Saved->TemplateArgs = Info.takeSugared();
Saved->CallArgIndex = Info.CallArgIndex;
Result.Data = Saved;
break;
}
case TemplateDeductionResult::NonDeducedMismatch: {
DFIArguments *Saved = new (Context) DFIArguments;
Saved->FirstArg = Info.FirstArg;
Saved->SecondArg = Info.SecondArg;
Result.Data = Saved;
break;
}
case TemplateDeductionResult::IncompletePack:
case TemplateDeductionResult::Inconsistent:
case TemplateDeductionResult::Underqualified: {
DFIParamWithArguments *Saved = new (Context) DFIParamWithArguments;
Saved->Param = Info.Param;
Saved->FirstArg = Info.FirstArg;
Saved->SecondArg = Info.SecondArg;
Result.Data = Saved;
break;
}
case TemplateDeductionResult::SubstitutionFailure:
Result.Data = Info.takeSugared();
if (Info.hasSFINAEDiagnostic()) {
PartialDiagnosticAt *Diag = new (Result.Diagnostic) PartialDiagnosticAt(
SourceLocation(), PartialDiagnostic::NullDiagnostic());
Info.takeSFINAEDiagnostic(*Diag);
Result.HasDiagnostic = true;
}
break;
case TemplateDeductionResult::ConstraintsNotSatisfied: {
CNSInfo *Saved = new (Context) CNSInfo;
Saved->TemplateArgs = Info.takeSugared();
Saved->Satisfaction = Info.AssociatedConstraintsSatisfaction;
Result.Data = Saved;
break;
}
case TemplateDeductionResult::Success:
case TemplateDeductionResult::NonDependentConversionFailure:
case TemplateDeductionResult::AlreadyDiagnosed:
llvm_unreachable("not a deduction failure");
}
return Result;
}
void DeductionFailureInfo::Destroy() {
switch (static_cast<TemplateDeductionResult>(Result)) {
case TemplateDeductionResult::Success:
case TemplateDeductionResult::Invalid:
case TemplateDeductionResult::InstantiationDepth:
case TemplateDeductionResult::Incomplete:
case TemplateDeductionResult::TooManyArguments:
case TemplateDeductionResult::TooFewArguments:
case TemplateDeductionResult::InvalidExplicitArguments:
case TemplateDeductionResult::CUDATargetMismatch:
case TemplateDeductionResult::NonDependentConversionFailure:
break;
case TemplateDeductionResult::IncompletePack:
case TemplateDeductionResult::Inconsistent:
case TemplateDeductionResult::Underqualified:
case TemplateDeductionResult::DeducedMismatch:
case TemplateDeductionResult::DeducedMismatchNested:
case TemplateDeductionResult::NonDeducedMismatch:
Data = nullptr;
break;
case TemplateDeductionResult::SubstitutionFailure:
Data = nullptr;
if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) {
Diag->~PartialDiagnosticAt();
HasDiagnostic = false;
}
break;
case TemplateDeductionResult::ConstraintsNotSatisfied:
Data = nullptr;
if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) {
Diag->~PartialDiagnosticAt();
HasDiagnostic = false;
}
break;
case TemplateDeductionResult::MiscellaneousDeductionFailure:
case TemplateDeductionResult::AlreadyDiagnosed:
break;
}
}
PartialDiagnosticAt *DeductionFailureInfo::getSFINAEDiagnostic() {
if (HasDiagnostic)
return static_cast<PartialDiagnosticAt*>(static_cast<void*>(Diagnostic));
return nullptr;
}
TemplateParameter DeductionFailureInfo::getTemplateParameter() {
switch (static_cast<TemplateDeductionResult>(Result)) {
case TemplateDeductionResult::Success:
case TemplateDeductionResult::Invalid:
case TemplateDeductionResult::InstantiationDepth:
case TemplateDeductionResult::TooManyArguments:
case TemplateDeductionResult::TooFewArguments:
case TemplateDeductionResult::SubstitutionFailure:
case TemplateDeductionResult::DeducedMismatch:
case TemplateDeductionResult::DeducedMismatchNested:
case TemplateDeductionResult::NonDeducedMismatch:
case TemplateDeductionResult::CUDATargetMismatch:
case TemplateDeductionResult::NonDependentConversionFailure:
case TemplateDeductionResult::ConstraintsNotSatisfied:
return TemplateParameter();
case TemplateDeductionResult::Incomplete:
case TemplateDeductionResult::InvalidExplicitArguments:
return TemplateParameter::getFromOpaqueValue(Data);
case TemplateDeductionResult::IncompletePack:
case TemplateDeductionResult::Inconsistent:
case TemplateDeductionResult::Underqualified:
return static_cast<DFIParamWithArguments*>(Data)->Param;
case TemplateDeductionResult::MiscellaneousDeductionFailure:
case TemplateDeductionResult::AlreadyDiagnosed:
break;
}
return TemplateParameter();
}
TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
switch (static_cast<TemplateDeductionResult>(Result)) {
case TemplateDeductionResult::Success:
case TemplateDeductionResult::Invalid:
case TemplateDeductionResult::InstantiationDepth:
case TemplateDeductionResult::TooManyArguments:
case TemplateDeductionResult::TooFewArguments:
case TemplateDeductionResult::Incomplete:
case TemplateDeductionResult::IncompletePack:
case TemplateDeductionResult::InvalidExplicitArguments:
case TemplateDeductionResult::Inconsistent:
case TemplateDeductionResult::Underqualified:
case TemplateDeductionResult::NonDeducedMismatch:
case TemplateDeductionResult::CUDATargetMismatch:
case TemplateDeductionResult::NonDependentConversionFailure:
return nullptr;
case TemplateDeductionResult::DeducedMismatch:
case TemplateDeductionResult::DeducedMismatchNested:
return static_cast<DFIDeducedMismatchArgs*>(Data)->TemplateArgs;
case TemplateDeductionResult::SubstitutionFailure:
return static_cast<TemplateArgumentList*>(Data);
case TemplateDeductionResult::ConstraintsNotSatisfied:
return static_cast<CNSInfo*>(Data)->TemplateArgs;
case TemplateDeductionResult::MiscellaneousDeductionFailure:
case TemplateDeductionResult::AlreadyDiagnosed:
break;
}
return nullptr;
}
const TemplateArgument *DeductionFailureInfo::getFirstArg() {
switch (static_cast<TemplateDeductionResult>(Result)) {
case TemplateDeductionResult::Success:
case TemplateDeductionResult::Invalid:
case TemplateDeductionResult::InstantiationDepth:
case TemplateDeductionResult::Incomplete:
case TemplateDeductionResult::TooManyArguments:
case TemplateDeductionResult::TooFewArguments:
case TemplateDeductionResult::InvalidExplicitArguments:
case TemplateDeductionResult::SubstitutionFailure:
case TemplateDeductionResult::CUDATargetMismatch:
case TemplateDeductionResult::NonDependentConversionFailure:
case TemplateDeductionResult::ConstraintsNotSatisfied:
return nullptr;
case TemplateDeductionResult::IncompletePack:
case TemplateDeductionResult::Inconsistent:
case TemplateDeductionResult::Underqualified:
case TemplateDeductionResult::DeducedMismatch:
case TemplateDeductionResult::DeducedMismatchNested:
case TemplateDeductionResult::NonDeducedMismatch:
return &static_cast<DFIArguments*>(Data)->FirstArg;
case TemplateDeductionResult::MiscellaneousDeductionFailure:
case TemplateDeductionResult::AlreadyDiagnosed:
break;
}
return nullptr;
}
const TemplateArgument *DeductionFailureInfo::getSecondArg() {
switch (static_cast<TemplateDeductionResult>(Result)) {
case TemplateDeductionResult::Success:
case TemplateDeductionResult::Invalid:
case TemplateDeductionResult::InstantiationDepth:
case TemplateDeductionResult::Incomplete:
case TemplateDeductionResult::IncompletePack:
case TemplateDeductionResult::TooManyArguments:
case TemplateDeductionResult::TooFewArguments:
case TemplateDeductionResult::InvalidExplicitArguments:
case TemplateDeductionResult::SubstitutionFailure:
case TemplateDeductionResult::CUDATargetMismatch:
case TemplateDeductionResult::NonDependentConversionFailure:
case TemplateDeductionResult::ConstraintsNotSatisfied:
return nullptr;
case TemplateDeductionResult::Inconsistent:
case TemplateDeductionResult::Underqualified:
case TemplateDeductionResult::DeducedMismatch:
case TemplateDeductionResult::DeducedMismatchNested:
case TemplateDeductionResult::NonDeducedMismatch:
return &static_cast<DFIArguments*>(Data)->SecondArg;
case TemplateDeductionResult::MiscellaneousDeductionFailure:
case TemplateDeductionResult::AlreadyDiagnosed:
break;
}
return nullptr;
}
std::optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
switch (static_cast<TemplateDeductionResult>(Result)) {
case TemplateDeductionResult::DeducedMismatch:
case TemplateDeductionResult::DeducedMismatchNested:
return static_cast<DFIDeducedMismatchArgs*>(Data)->CallArgIndex;
default:
return std::nullopt;
}
}
static bool FunctionsCorrespond(ASTContext &Ctx, const FunctionDecl *X,
const FunctionDecl *Y) {
if (!X || !Y)
return false;
if (X->getNumParams() != Y->getNumParams())
return false;
for (unsigned I = 0; I < X->getNumParams(); ++I)
if (!Ctx.hasSameUnqualifiedType(X->getParamDecl(I)->getType(),
Y->getParamDecl(I)->getType()))
return false;
if (auto *FTX = X->getDescribedFunctionTemplate()) {
auto *FTY = Y->getDescribedFunctionTemplate();
if (!FTY)
return false;
if (!Ctx.isSameTemplateParameterList(FTX->getTemplateParameters(),
FTY->getTemplateParameters()))
return false;
}
return true;
}
static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc,
Expr *FirstOperand, FunctionDecl *EqFD) {
assert(EqFD->getOverloadedOperator() ==
OverloadedOperatorKind::OO_EqualEqual);
DeclarationName NotEqOp = S.Context.DeclarationNames.getCXXOperatorName(
OverloadedOperatorKind::OO_ExclaimEqual);
if (isa<CXXMethodDecl>(EqFD)) {
QualType RHS = FirstOperand->getType();
auto *RHSRec = RHS->getAs<RecordType>();
if (!RHSRec)
return true;
LookupResult Members(S, NotEqOp, OpLoc,
Sema::LookupNameKind::LookupMemberName);
S.LookupQualifiedName(Members, RHSRec->getDecl());
Members.suppressAccessDiagnostics();
for (NamedDecl *Op : Members)
if (FunctionsCorrespond(S.Context, EqFD, Op->getAsFunction()))
return false;
return true;
}
for (NamedDecl *Op : EqFD->getEnclosingNamespaceContext()->lookup(NotEqOp)) {
auto *NotEqFD = Op->getAsFunction();
if (auto *UD = dyn_cast<UsingShadowDecl>(Op))
NotEqFD = UD->getUnderlyingDecl()->getAsFunction();
if (FunctionsCorrespond(S.Context, EqFD, NotEqFD) && S.isVisible(NotEqFD) &&
declaresSameEntity(cast<Decl>(EqFD->getEnclosingNamespaceContext()),
cast<Decl>(Op->getLexicalDeclContext())))
return false;
}
return true;
}
bool OverloadCandidateSet::OperatorRewriteInfo::allowsReversed(
OverloadedOperatorKind Op) {
if (!AllowRewrittenCandidates)
return false;
return Op == OO_EqualEqual || Op == OO_Spaceship;
}
bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
Sema &S, ArrayRef<Expr *> OriginalArgs, FunctionDecl *FD) {
auto Op = FD->getOverloadedOperator();
if (!allowsReversed(Op))
return false;
if (Op == OverloadedOperatorKind::OO_EqualEqual) {
assert(OriginalArgs.size() == 2);
if (!shouldAddReversedEqEq(
S, OpLoc, OriginalArgs[1], FD))
return false;
}
return FD->getNumNonObjectParams() != 2 ||
!S.Context.hasSameUnqualifiedType(FD->getParamDecl(0)->getType(),
FD->getParamDecl(1)->getType()) ||
FD->hasAttr<EnableIfAttr>();
}
void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
for (auto &C : i->Conversions)
C.~ImplicitConversionSequence();
if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction)
i->DeductionFailure.Destroy();
}
}
void OverloadCandidateSet::clear(CandidateSetKind CSK) {
destroyCandidates();
SlabAllocator.Reset();
NumInlineBytesUsed = 0;
Candidates.clear();
Functions.clear();
Kind = CSK;
}
namespace {
class UnbridgedCastsSet {
struct Entry {
Expr **Addr;
Expr *Saved;
};
SmallVector<Entry, 2> Entries;
public:
void save(Sema &S, Expr *&E) {
assert(E->hasPlaceholderType(BuiltinType::ARCUnbridgedCast));
Entry entry = { &E, E };
Entries.push_back(entry);
E = S.ObjC().stripARCUnbridgedCast(E);
}
void restore() {
for (SmallVectorImpl<Entry>::iterator
i = Entries.begin(), e = Entries.end(); i != e; ++i)
*i->Addr = i->Saved;
}
};
}
static bool
checkPlaceholderForOverload(Sema &S, Expr *&E,
UnbridgedCastsSet *unbridgedCasts = nullptr) {
if (const BuiltinType *placeholder = E->getType()->getAsPlaceholderType()) {
if (placeholder->getKind() == BuiltinType::Overload) return false;
if (placeholder->getKind() == BuiltinType::ARCUnbridgedCast &&
unbridgedCasts) {
unbridgedCasts->save(S, E);
return false;
}
ExprResult result = S.CheckPlaceholderExpr(E);
if (result.isInvalid())
return true;
E = result.get();
return false;
}
return false;
}
static bool checkArgPlaceholdersForOverload(Sema &S, MultiExprArg Args,
UnbridgedCastsSet &unbridged) {
for (unsigned i = 0, e = Args.size(); i != e; ++i)
if (checkPlaceholderForOverload(S, Args[i], &unbridged))
return true;
return false;
}
Sema::OverloadKind
Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
NamedDecl *&Match, bool NewIsUsingDecl) {
for (LookupResult::iterator I = Old.begin(), E = Old.end();
I != E; ++I) {
NamedDecl *OldD = *I;
bool OldIsUsingDecl = false;
if (isa<UsingShadowDecl>(OldD)) {
OldIsUsingDecl = true;
if (NewIsUsingDecl) continue;
OldD = cast<UsingShadowDecl>(OldD)->getTargetDecl();
}
if ((OldIsUsingDecl || NewIsUsingDecl) && !isVisible(*I))
continue;
bool UseMemberUsingDeclRules =
(OldIsUsingDecl || NewIsUsingDecl) && CurContext->isRecord() &&
!New->getFriendObjectKind();
if (FunctionDecl *OldF = OldD->getAsFunction()) {
if (!IsOverload(New, OldF, UseMemberUsingDeclRules)) {
if (UseMemberUsingDeclRules && OldIsUsingDecl) {
HideUsingShadowDecl(S, cast<UsingShadowDecl>(*I));
continue;
}
if (!isa<FunctionTemplateDecl>(OldD) &&
!shouldLinkPossiblyHiddenDecl(*I, New))
continue;
Match = *I;
return Ovl_Match;
}
if (!getASTContext().canBuiltinBeRedeclared(OldF)) {
Match = *I;
return Ovl_NonFunction;
}
} else if (isa<UsingDecl>(OldD) || isa<UsingPackDecl>(OldD)) {
assert(Old.getLookupKind() == LookupUsingDeclName);
} else if (isa<TagDecl>(OldD)) {
} else if (auto *UUD = dyn_cast<UnresolvedUsingValueDecl>(OldD)) {
if (UUD->getQualifier()->isDependent() && !UUD->isCXXClassMember()) {
Match = *I;
return Ovl_NonFunction;
}
} else {
Match = *I;
return Ovl_NonFunction;
}
}
if (New->getFriendObjectKind() && New->getQualifier() &&
!New->getDescribedFunctionTemplate() &&
!New->getDependentSpecializationInfo() &&
!New->getType()->isDependentType()) {
LookupResult TemplateSpecResult(LookupResult::Temporary, Old);
TemplateSpecResult.addAllDecls(Old);
if (CheckFunctionTemplateSpecialization(New, nullptr, TemplateSpecResult,
true)) {
New->setInvalidDecl();
return Ovl_Overload;
}
Match = TemplateSpecResult.getAsSingle<FunctionDecl>();
return Ovl_Match;
}
return Ovl_Overload;
}
static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
FunctionDecl *Old,
bool UseMemberUsingDeclRules,
bool ConsiderCudaAttrs,
bool UseOverrideRules = false) {
if (New->isMain())
return false;
if (New->isMSVCRTEntryPoint())
return false;
NamedDecl *OldDecl = Old;
NamedDecl *NewDecl = New;
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
if ((OldTemplate == nullptr) != (NewTemplate == nullptr))
return true;
QualType OldQType = SemaRef.Context.getCanonicalType(Old->getType());
QualType NewQType = SemaRef.Context.getCanonicalType(New->getType());
if (isa<FunctionNoProtoType>(OldQType.getTypePtr()) ||
isa<FunctionNoProtoType>(NewQType.getTypePtr()))
return false;
const auto *OldType = cast<FunctionProtoType>(OldQType);
const auto *NewType = cast<FunctionProtoType>(NewQType);
if (OldQType != NewQType && OldType->isVariadic() != NewType->isVariadic())
return true;
if ((New->isMemberLikeConstrainedFriend() ||
Old->isMemberLikeConstrainedFriend()) &&
!New->getLexicalDeclContext()->Equals(Old->getLexicalDeclContext()))
return true;
if (NewTemplate) {
OldDecl = OldTemplate;
NewDecl = NewTemplate;
bool SameTemplateParameterList = SemaRef.TemplateParameterListsAreEqual(
NewTemplate, NewTemplate->getTemplateParameters(), OldTemplate,
OldTemplate->getTemplateParameters(), false, Sema::TPL_TemplateMatch);
bool SameReturnType = SemaRef.Context.hasSameType(
Old->getDeclaredReturnType(), New->getDeclaredReturnType());
bool ConstraintsInTemplateHead =
NewTemplate->getTemplateParameters()->hasAssociatedConstraints() ||
OldTemplate->getTemplateParameters()->hasAssociatedConstraints();
if (UseMemberUsingDeclRules && ConstraintsInTemplateHead &&
!SameTemplateParameterList)
return true;
if (!UseMemberUsingDeclRules &&
(!SameTemplateParameterList || !SameReturnType))
return true;
}
const auto *OldMethod = dyn_cast<CXXMethodDecl>(Old);
const auto *NewMethod = dyn_cast<CXXMethodDecl>(New);
int OldParamsOffset = 0;
int NewParamsOffset = 0;
auto NormalizeQualifiers = [&](const CXXMethodDecl *M, Qualifiers Q) {
if (M->isExplicitObjectMemberFunction())
return Q;
Q.removeRestrict();
if (!SemaRef.getLangOpts().CPlusPlus14 &&
(M->isConstexpr() || M->isConsteval()) &&
!isa<CXXConstructorDecl>(NewMethod))
Q.addConst();
return Q;
};
auto CompareType = [&](QualType Base, QualType D) {
auto BS = Base.getNonReferenceType().getCanonicalType().split();
BS.Quals = NormalizeQualifiers(OldMethod, BS.Quals);
auto DS = D.getNonReferenceType().getCanonicalType().split();
DS.Quals = NormalizeQualifiers(NewMethod, DS.Quals);
if (BS.Quals != DS.Quals)
return false;
if (OldMethod->isImplicitObjectMemberFunction() &&
OldMethod->getParent() != NewMethod->getParent()) {
QualType ParentType =
SemaRef.Context.getTypeDeclType(OldMethod->getParent())
.getCanonicalType();
if (ParentType.getTypePtr() != BS.Ty)
return false;
BS.Ty = DS.Ty;
}
if (BS.Ty != DS.Ty)
return false;
if (Base->isLValueReferenceType())
return D->isLValueReferenceType();
return Base->isRValueReferenceType() == D->isRValueReferenceType();
};
auto DiagnoseInconsistentRefQualifiers = [&]() {
if (SemaRef.LangOpts.CPlusPlus23)
return false;
if (OldMethod->getRefQualifier() == NewMethod->getRefQualifier())
return false;
if (OldMethod->isExplicitObjectMemberFunction() ||
NewMethod->isExplicitObjectMemberFunction())
return false;
if (!UseMemberUsingDeclRules && (OldMethod->getRefQualifier() == RQ_None ||
NewMethod->getRefQualifier() == RQ_None)) {
SemaRef.Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
<< NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
SemaRef.Diag(OldMethod->getLocation(), diag::note_previous_declaration);
return true;
}
return false;
};
if (OldMethod && OldMethod->isExplicitObjectMemberFunction())
OldParamsOffset++;
if (NewMethod && NewMethod->isExplicitObjectMemberFunction())
NewParamsOffset++;
if (OldType->getNumParams() - OldParamsOffset !=
NewType->getNumParams() - NewParamsOffset ||
!SemaRef.FunctionParamTypesAreEqual(
{OldType->param_type_begin() + OldParamsOffset,
OldType->param_type_end()},
{NewType->param_type_begin() + NewParamsOffset,
NewType->param_type_end()},
nullptr)) {
return true;
}
if (OldMethod && NewMethod && !OldMethod->isStatic() &&
!NewMethod->isStatic()) {
bool HaveCorrespondingObjectParameters = [&](const CXXMethodDecl *Old,
const CXXMethodDecl *New) {
auto NewObjectType = New->getFunctionObjectParameterReferenceType();
auto OldObjectType = Old->getFunctionObjectParameterReferenceType();
auto IsImplicitWithNoRefQual = [](const CXXMethodDecl *F) {
return F->getRefQualifier() == RQ_None &&
!F->isExplicitObjectMemberFunction();
};
if (IsImplicitWithNoRefQual(Old) != IsImplicitWithNoRefQual(New) &&
CompareType(OldObjectType.getNonReferenceType(),
NewObjectType.getNonReferenceType()))
return true;
return CompareType(OldObjectType, NewObjectType);
}(OldMethod, NewMethod);
if (!HaveCorrespondingObjectParameters) {
if (DiagnoseInconsistentRefQualifiers())
return true;
if (!UseOverrideRules || (!NewMethod->isExplicitObjectMemberFunction() &&
!OldMethod->isExplicitObjectMemberFunction()))
return true;
}
}
if (!UseOverrideRules &&
New->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) {
Expr *NewRC = New->getTrailingRequiresClause(),
*OldRC = Old->getTrailingRequiresClause();
if ((NewRC != nullptr) != (OldRC != nullptr))
return true;
if (NewRC &&
!SemaRef.AreConstraintExpressionsEqual(OldDecl, OldRC, NewDecl, NewRC))
return true;
}
if (NewMethod && OldMethod && OldMethod->isImplicitObjectMemberFunction() &&
NewMethod->isImplicitObjectMemberFunction()) {
if (DiagnoseInconsistentRefQualifiers())
return true;
}
if (functionHasPassObjectSizeParams(New) !=
functionHasPassObjectSizeParams(Old))
return true;
for (specific_attr_iterator<EnableIfAttr>
NewI = New->specific_attr_begin<EnableIfAttr>(),
NewE = New->specific_attr_end<EnableIfAttr>(),
OldI = Old->specific_attr_begin<EnableIfAttr>(),
OldE = Old->specific_attr_end<EnableIfAttr>();
NewI != NewE || OldI != OldE; ++NewI, ++OldI) {
if (NewI == NewE || OldI == OldE)
return true;
llvm::FoldingSetNodeID NewID, OldID;
NewI->getCond()->Profile(NewID, SemaRef.Context, true);
OldI->getCond()->Profile(OldID, SemaRef.Context, true);
if (NewID != OldID)
return true;
}
if (SemaRef.getLangOpts().CUDA && ConsiderCudaAttrs) {
if (!isa<CXXDestructorDecl>(New)) {
CUDAFunctionTarget NewTarget = SemaRef.CUDA().IdentifyTarget(New),
OldTarget = SemaRef.CUDA().IdentifyTarget(Old);
if (NewTarget != CUDAFunctionTarget::InvalidTarget) {
assert((OldTarget != CUDAFunctionTarget::InvalidTarget) &&
"Unexpected invalid target.");
if (NewTarget != OldTarget)
return true;
}
}
}
return false;
}
bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs) {
return IsOverloadOrOverrideImpl(*this, New, Old, UseMemberUsingDeclRules,
ConsiderCudaAttrs);
}
bool Sema::IsOverride(FunctionDecl *MD, FunctionDecl *BaseMD,
bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs) {
return IsOverloadOrOverrideImpl(*this, MD, BaseMD,
false,
true,
true);
}
static ImplicitConversionSequence
TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
AllowedExplicit AllowExplicit,
bool InOverloadResolution,
bool CStyle,
bool AllowObjCWritebackConversion,
bool AllowObjCConversionOnExplicit) {
ImplicitConversionSequence ICS;
if (SuppressUserConversions) {
ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
return ICS;
}
OverloadCandidateSet Conversions(From->getExprLoc(),
OverloadCandidateSet::CSK_Normal);
switch (IsUserDefinedConversion(S, From, ToType, ICS.UserDefined,
Conversions, AllowExplicit,
AllowObjCConversionOnExplicit)) {
case OR_Success:
case OR_Deleted:
ICS.setUserDefined();
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
QualType FromCanon
= S.Context.getCanonicalType(From->getType().getUnqualifiedType());
QualType ToCanon
= S.Context.getCanonicalType(ToType).getUnqualifiedType();
if (Constructor->isCopyConstructor() &&
(FromCanon == ToCanon ||
S.IsDerivedFrom(From->getBeginLoc(), FromCanon, ToCanon))) {
DeclAccessPair Found = ICS.UserDefined.FoundConversionFunction;
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(From->getType());
ICS.Standard.setAllToTypes(ToType);
ICS.Standard.CopyConstructor = Constructor;
ICS.Standard.FoundCopyConstructor = Found;
if (ToCanon != FromCanon)
ICS.Standard.Second = ICK_Derived_To_Base;
}
}
break;
case OR_Ambiguous:
ICS.setAmbiguous();
ICS.Ambiguous.setFromType(From->getType());
ICS.Ambiguous.setToType(ToType);
for (OverloadCandidateSet::iterator Cand = Conversions.begin();
Cand != Conversions.end(); ++Cand)
if (Cand->Best)
ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function);
break;
case OR_No_Viable_Function:
ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
break;
}
return ICS;
}
static ImplicitConversionSequence
TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
AllowedExplicit AllowExplicit,
bool InOverloadResolution,
bool CStyle,
bool AllowObjCWritebackConversion,
bool AllowObjCConversionOnExplicit) {
ImplicitConversionSequence ICS;
if (IsStandardConversion(S, From, ToType, InOverloadResolution,
ICS.Standard, CStyle, AllowObjCWritebackConversion)){
ICS.setStandard();
return ICS;
}
if (!S.getLangOpts().CPlusPlus) {
ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
return ICS;
}
QualType FromType = From->getType();
if (ToType->getAs<RecordType>() && FromType->getAs<RecordType>() &&
(S.Context.hasSameUnqualifiedType(FromType, ToType) ||
S.IsDerivedFrom(From->getBeginLoc(), FromType, ToType))) {
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(FromType);
ICS.Standard.setAllToTypes(ToType);
ICS.Standard.CopyConstructor = nullptr;
if (!S.Context.hasSameUnqualifiedType(FromType, ToType))
ICS.Standard.Second = ICK_Derived_To_Base;
return ICS;
}
return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
AllowExplicit, InOverloadResolution, CStyle,
AllowObjCWritebackConversion,
AllowObjCConversionOnExplicit);
}
ImplicitConversionSequence
Sema::TryImplicitConversion(Expr *From, QualType ToType,
bool SuppressUserConversions,
AllowedExplicit AllowExplicit,
bool InOverloadResolution,
bool CStyle,
bool AllowObjCWritebackConversion) {
return ::TryImplicitConversion(*this, From, ToType, SuppressUserConversions,
AllowExplicit, InOverloadResolution, CStyle,
AllowObjCWritebackConversion,
false);
}
ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action,
bool AllowExplicit) {
if (checkPlaceholderForOverload(*this, From))
return ExprError();
bool AllowObjCWritebackConversion
= getLangOpts().ObjCAutoRefCount &&
(Action == AA_Passing || Action == AA_Sending);
if (getLangOpts().ObjC)
ObjC().CheckObjCBridgeRelatedConversions(From->getBeginLoc(), ToType,
From->getType(), From);
ImplicitConversionSequence ICS = ::TryImplicitConversion(
*this, From, ToType,
false,
AllowExplicit ? AllowedExplicit::All : AllowedExplicit::None,
false,
false, AllowObjCWritebackConversion,
false);
return PerformImplicitConversion(From, ToType, ICS, Action);
}
bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
QualType &ResultTy) {
if (Context.hasSameUnqualifiedType(FromType, ToType))
return false;
CanQualType CanTo = Context.getCanonicalType(ToType);
CanQualType CanFrom = Context.getCanonicalType(FromType);
Type::TypeClass TyClass = CanTo->getTypeClass();
if (TyClass != CanFrom->getTypeClass()) return false;
if (TyClass != Type::FunctionProto && TyClass != Type::FunctionNoProto) {
if (TyClass == Type::Pointer) {
CanTo = CanTo.castAs<PointerType>()->getPointeeType();
CanFrom = CanFrom.castAs<PointerType>()->getPointeeType();
} else if (TyClass == Type::BlockPointer) {
CanTo = CanTo.castAs<BlockPointerType>()->getPointeeType();
CanFrom = CanFrom.castAs<BlockPointerType>()->getPointeeType();
} else if (TyClass == Type::MemberPointer) {
auto ToMPT = CanTo.castAs<MemberPointerType>();
auto FromMPT = CanFrom.castAs<MemberPointerType>();
if (ToMPT->getClass() != FromMPT->getClass())
return false;
CanTo = ToMPT->getPointeeType();
CanFrom = FromMPT->getPointeeType();
} else {
return false;
}
TyClass = CanTo->getTypeClass();
if (TyClass != CanFrom->getTypeClass()) return false;
if (TyClass != Type::FunctionProto && TyClass != Type::FunctionNoProto)
return false;
}
const auto *FromFn = cast<FunctionType>(CanFrom);
FunctionType::ExtInfo FromEInfo = FromFn->getExtInfo();
const auto *ToFn = cast<FunctionType>(CanTo);
FunctionType::ExtInfo ToEInfo = ToFn->getExtInfo();
bool Changed = false;
if (FromEInfo.getNoReturn() && !ToEInfo.getNoReturn()) {
FromFn = Context.adjustFunctionType(FromFn, FromEInfo.withNoReturn(false));
Changed = true;
}
if (const auto *FromFPT = dyn_cast<FunctionProtoType>(FromFn)) {
const auto *ToFPT = cast<FunctionProtoType>(ToFn);
if (FromFPT->isNothrow() && !ToFPT->isNothrow()) {
FromFn = cast<FunctionType>(
Context.getFunctionTypeWithExceptionSpec(QualType(FromFPT, 0),
EST_None)
.getTypePtr());
Changed = true;
}
SmallVector<FunctionProtoType::ExtParameterInfo, 4> NewParamInfos;
bool CanUseToFPT, CanUseFromFPT;
if (Context.mergeExtParameterInfo(ToFPT, FromFPT, CanUseToFPT,
CanUseFromFPT, NewParamInfos) &&
CanUseToFPT && !CanUseFromFPT) {
FunctionProtoType::ExtProtoInfo ExtInfo = FromFPT->getExtProtoInfo();
ExtInfo.ExtParameterInfos =
NewParamInfos.empty() ? nullptr : NewParamInfos.data();
QualType QT = Context.getFunctionType(FromFPT->getReturnType(),
FromFPT->getParamTypes(), ExtInfo);
FromFn = QT->getAs<FunctionType>();
Changed = true;
}
if (Context.hasAnyFunctionEffects() && getLangOpts().CPlusPlus) {
FromFPT = cast<FunctionProtoType>(FromFn);
const auto FromFX = FromFPT->getFunctionEffects();
const auto ToFX = ToFPT->getFunctionEffects();
if (FromFX != ToFX) {
FunctionProtoType::ExtProtoInfo ExtInfo = FromFPT->getExtProtoInfo();
ExtInfo.FunctionEffects = ToFX;
QualType QT = Context.getFunctionType(
FromFPT->getReturnType(), FromFPT->getParamTypes(), ExtInfo);
FromFn = QT->getAs<FunctionType>();
Changed = true;
}
}
}
if (!Changed)
return false;
assert(QualType(FromFn, 0).isCanonical());
if (QualType(FromFn, 0) != CanTo) return false;
ResultTy = ToType;
return true;
}
static bool IsFloatingPointConversion(Sema &S, QualType FromType,
QualType ToType) {
if (!FromType->isRealFloatingType() || !ToType->isRealFloatingType())
return false;
if ((FromType->isBFloat16Type() &&
(ToType->isFloat16Type() || ToType->isHalfType())) ||
(ToType->isBFloat16Type() &&
(FromType->isFloat16Type() || FromType->isHalfType())))
return false;
const llvm::fltSemantics &FromSem = S.Context.getFloatTypeSemantics(FromType);
const llvm::fltSemantics &ToSem = S.Context.getFloatTypeSemantics(ToType);
if ((&FromSem == &llvm::APFloat::PPCDoubleDouble() &&
&ToSem == &llvm::APFloat::IEEEquad()) ||
(&FromSem == &llvm::APFloat::IEEEquad() &&
&ToSem == &llvm::APFloat::PPCDoubleDouble()))
return false;
return true;
}
static bool IsVectorElementConversion(Sema &S, QualType FromType,
QualType ToType,
ImplicitConversionKind &ICK, Expr *From) {
if (S.Context.hasSameUnqualifiedType(FromType, ToType))
return true;
if (S.IsFloatingPointPromotion(FromType, ToType)) {
ICK = ICK_Floating_Promotion;
return true;
}
if (IsFloatingPointConversion(S, FromType, ToType)) {
ICK = ICK_Floating_Conversion;
return true;
}
if (ToType->isBooleanType() && FromType->isArithmeticType()) {
ICK = ICK_Boolean_Conversion;
return true;
}
if ((FromType->isRealFloatingType() && ToType->isIntegralType(S.Context)) ||
(FromType->isIntegralOrUnscopedEnumerationType() &&
ToType->isRealFloatingType())) {
ICK = ICK_Floating_Integral;
return true;
}
if (S.IsIntegralPromotion(From, FromType, ToType)) {
ICK = ICK_Integral_Promotion;
return true;
}
if (FromType->isIntegralOrUnscopedEnumerationType() &&
ToType->isIntegralType(S.Context)) {
ICK = ICK_Integral_Conversion;
return true;
}
return false;
}
static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
ImplicitConversionKind &ICK,
ImplicitConversionKind &ElConv, Expr *From,
bool InOverloadResolution, bool CStyle) {
if (!ToType->isVectorType() && !FromType->isVectorType())
return false;
if (S.Context.hasSameUnqualifiedType(FromType, ToType))
return false;
if (auto *ToExtType = ToType->getAs<ExtVectorType>()) {
if (auto *FromExtType = FromType->getAs<ExtVectorType>()) {
if (S.getLangOpts().HLSL) {
unsigned FromElts = FromExtType->getNumElements();
unsigned ToElts = ToExtType->getNumElements();
if (FromElts < ToElts)
return false;
if (FromElts == ToElts)
ElConv = ICK_Identity;
else
ElConv = ICK_HLSL_Vector_Truncation;
QualType FromElTy = FromExtType->getElementType();
QualType ToElTy = ToExtType->getElementType();
if (S.Context.hasSameUnqualifiedType(FromElTy, ToElTy))
return true;
return IsVectorElementConversion(S, FromElTy, ToElTy, ICK, From);
}
return false;
}
if (FromType->isArithmeticType()) {
if (S.getLangOpts().HLSL) {
ElConv = ICK_HLSL_Vector_Splat;
QualType ToElTy = ToExtType->getElementType();
return IsVectorElementConversion(S, FromType, ToElTy, ICK, From);
}
ICK = ICK_Vector_Splat;
return true;
}
}
if (ToType->isSVESizelessBuiltinType() ||
FromType->isSVESizelessBuiltinType())
if (S.Context.areCompatibleSveTypes(FromType, ToType) ||
S.Context.areLaxCompatibleSveTypes(FromType, ToType)) {
ICK = ICK_SVE_Vector_Conversion;
return true;
}
if (ToType->isRVVSizelessBuiltinType() ||
FromType->isRVVSizelessBuiltinType())
if (S.Context.areCompatibleRVVTypes(FromType, ToType) ||
S.Context.areLaxCompatibleRVVTypes(FromType, ToType)) {
ICK = ICK_RVV_Vector_Conversion;
return true;
}
if (ToType->isVectorType() && FromType->isVectorType()) {
if (S.Context.areCompatibleVectorTypes(FromType, ToType) ||
(S.isLaxVectorConversion(FromType, ToType) &&
!ToType->hasAttr(attr::ArmMveStrictPolymorphism))) {
if (S.getASTContext().getTargetInfo().getTriple().isPPC() &&
S.isLaxVectorConversion(FromType, ToType) &&
S.anyAltivecTypes(FromType, ToType) &&
!S.Context.areCompatibleVectorTypes(FromType, ToType) &&
!InOverloadResolution && !CStyle) {
S.Diag(From->getBeginLoc(), diag::warn_deprecated_lax_vec_conv_all)
<< FromType << ToType;
}
ICK = ICK_Vector_Conversion;
return true;
}
}
return false;
}
static bool tryAtomicConversion(Sema &S, Expr *From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle);
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle,
bool AllowObjCWritebackConversion) {
QualType FromType = From->getType();
SCS.setAsIdentityConversion();
SCS.IncompatibleObjC = false;
SCS.setFromType(FromType);
SCS.CopyConstructor = nullptr;
if (S.getLangOpts().CPlusPlus &&
(FromType->isRecordType() || ToType->isRecordType()))
return false;
if (FromType == S.Context.OverloadTy) {
DeclAccessPair AccessPair;
if (FunctionDecl *Fn
= S.ResolveAddressOfOverloadedFunction(From, ToType, false,
AccessPair)) {
FromType = Fn->getType();
SCS.setFromType(FromType);
if (!S.Context.hasSameUnqualifiedType(
S.ExtractUnqualifiedFunctionType(ToType), FromType)) {
QualType resultTy;
if (!S.IsFunctionConversion(FromType,
S.ExtractUnqualifiedFunctionType(ToType), resultTy))
if (!ToType->isBooleanType())
return false;
}
CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn);
if (Method && !Method->isStatic() &&
!Method->isExplicitObjectMemberFunction()) {
assert(isa<UnaryOperator>(From->IgnoreParens()) &&
"Non-unary operator on non-static member address");
assert(cast<UnaryOperator>(From->IgnoreParens())->getOpcode()
== UO_AddrOf &&
"Non-address-of operator on non-static member address");
const Type *ClassType
= S.Context.getTypeDeclType(Method->getParent()).getTypePtr();
FromType = S.Context.getMemberPointerType(FromType, ClassType);
} else if (isa<UnaryOperator>(From->IgnoreParens())) {
assert(cast<UnaryOperator>(From->IgnoreParens())->getOpcode() ==
UO_AddrOf &&
"Non-address-of operator for overloaded function expression");
FromType = S.Context.getPointerType(FromType);
}
} else {
return false;
}
}
bool argIsLValue = From->isGLValue();
if (argIsLValue && !FromType->canDecayToPointerType() &&
S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) {
SCS.First = ICK_Lvalue_To_Rvalue;
if (const AtomicType *Atomic = FromType->getAs<AtomicType>())
FromType = Atomic->getValueType();
FromType = FromType.getUnqualifiedType();
} else if (S.getLangOpts().HLSL && FromType->isConstantArrayType() &&
ToType->isArrayParameterType()) {
FromType = S.Context.getArrayParameterType(FromType);
if (S.Context.getCanonicalType(FromType) !=
S.Context.getCanonicalType(ToType))
return false;
SCS.First = ICK_HLSL_Array_RValue;
SCS.setAllToTypes(ToType);
return true;
} else if (FromType->isArrayType()) {
SCS.First = ICK_Array_To_Pointer;
FromType = S.Context.getArrayDecayedType(FromType);
if (S.IsStringLiteralToNonConstPointerConversion(From, ToType)) {
SCS.DeprecatedStringLiteralToCharPtr = true;
SCS.Second = ICK_Identity;
SCS.Third = ICK_Qualification;
SCS.QualificationIncludesObjCLifetime = false;
SCS.setAllToTypes(FromType);
return true;
}
} else if (FromType->isFunctionType() && argIsLValue) {
SCS.First = ICK_Function_To_Pointer;
if (auto *DRE = dyn_cast<DeclRefExpr>(From->IgnoreParenCasts()))
if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()))
if (!S.checkAddressOfFunctionIsAvailable(FD))
return false;
FromType = S.Context.getPointerType(FromType);
} else {
SCS.First = ICK_Identity;
}
SCS.setToType(0, FromType);
bool IncompatibleObjC = false;
ImplicitConversionKind SecondICK = ICK_Identity;
ImplicitConversionKind DimensionICK = ICK_Identity;
if (S.Context.hasSameUnqualifiedType(FromType, ToType)) {
SCS.Second = ICK_Identity;
} else if (S.IsIntegralPromotion(From, FromType, ToType)) {
SCS.Second = ICK_Integral_Promotion;
FromType = ToType.getUnqualifiedType();
} else if (S.IsFloatingPointPromotion(FromType, ToType)) {
SCS.Second = ICK_Floating_Promotion;
FromType = ToType.getUnqualifiedType();
} else if (S.IsComplexPromotion(FromType, ToType)) {
SCS.Second = ICK_Complex_Promotion;
FromType = ToType.getUnqualifiedType();
} else if (ToType->isBooleanType() &&
(FromType->isArithmeticType() ||
FromType->isAnyPointerType() ||
FromType->isBlockPointerType() ||
FromType->isMemberPointerType())) {
SCS.Second = ICK_Boolean_Conversion;
FromType = S.Context.BoolTy;
} else if (FromType->isIntegralOrUnscopedEnumerationType() &&
ToType->isIntegralType(S.Context)) {
SCS.Second = ICK_Integral_Conversion;
FromType = ToType.getUnqualifiedType();
} else if (FromType->isAnyComplexType() && ToType->isAnyComplexType()) {
SCS.Second = ICK_Complex_Conversion;
FromType = ToType.getUnqualifiedType();
} else if ((FromType->isAnyComplexType() && ToType->isArithmeticType()) ||
(ToType->isAnyComplexType() && FromType->isArithmeticType())) {
SCS.Second = ICK_Complex_Real;
FromType = ToType.getUnqualifiedType();
} else if (IsFloatingPointConversion(S, FromType, ToType)) {
SCS.Second = ICK_Floating_Conversion;
FromType = ToType.getUnqualifiedType();
} else if ((FromType->isRealFloatingType() &&
ToType->isIntegralType(S.Context)) ||
(FromType->isIntegralOrUnscopedEnumerationType() &&
ToType->isRealFloatingType())) {
SCS.Second = ICK_Floating_Integral;
FromType = ToType.getUnqualifiedType();
} else if (S.IsBlockPointerConversion(FromType, ToType, FromType)) {
SCS.Second = ICK_Block_Pointer_Conversion;
} else if (AllowObjCWritebackConversion &&
S.ObjC().isObjCWritebackConversion(FromType, ToType, FromType)) {
SCS.Second = ICK_Writeback_Conversion;
} else if (S.IsPointerConversion(From, FromType, ToType, InOverloadResolution,
FromType, IncompatibleObjC)) {
SCS.Second = ICK_Pointer_Conversion;
SCS.IncompatibleObjC = IncompatibleObjC;
FromType = FromType.getUnqualifiedType();
} else if (S.IsMemberPointerConversion(From, FromType, ToType,
InOverloadResolution, FromType)) {
SCS.Second = ICK_Pointer_Member;
} else if (IsVectorConversion(S, FromType, ToType, SecondICK, DimensionICK,
From, InOverloadResolution, CStyle)) {
SCS.Second = SecondICK;
SCS.Dimension = DimensionICK;
FromType = ToType.getUnqualifiedType();
} else if (!S.getLangOpts().CPlusPlus &&
S.Context.typesAreCompatible(ToType, FromType)) {
SCS.Second = ICK_Compatible_Conversion;
FromType = ToType.getUnqualifiedType();
} else if (IsTransparentUnionStandardConversion(
S, From, ToType, InOverloadResolution, SCS, CStyle)) {
SCS.Second = ICK_TransparentUnionConversion;
FromType = ToType;
} else if (tryAtomicConversion(S, From, ToType, InOverloadResolution, SCS,
CStyle)) {
return true;
} else if (ToType->isEventT() &&
From->isIntegerConstantExpr(S.getASTContext()) &&
From->EvaluateKnownConstInt(S.getASTContext()) == 0) {
SCS.Second = ICK_Zero_Event_Conversion;
FromType = ToType;
} else if (ToType->isQueueT() &&
From->isIntegerConstantExpr(S.getASTContext()) &&
(From->EvaluateKnownConstInt(S.getASTContext()) == 0)) {
SCS.Second = ICK_Zero_Queue_Conversion;
FromType = ToType;
} else if (ToType->isSamplerT() &&
From->isIntegerConstantExpr(S.getASTContext())) {
SCS.Second = ICK_Compatible_Conversion;
FromType = ToType;
} else if ((ToType->isFixedPointType() &&
FromType->isConvertibleToFixedPointType()) ||
(FromType->isFixedPointType() &&
ToType->isConvertibleToFixedPointType())) {
SCS.Second = ICK_Fixed_Point_Conversion;
FromType = ToType;
} else {
SCS.Second = ICK_Identity;
}
SCS.setToType(1, FromType);
bool ObjCLifetimeConversion;
if (S.IsFunctionConversion(FromType, ToType, FromType)) {
SCS.Third = ICK_Function_Conversion;
} else if (S.IsQualificationConversion(FromType, ToType, CStyle,
ObjCLifetimeConversion)) {
SCS.Third = ICK_Qualification;
SCS.QualificationIncludesObjCLifetime = ObjCLifetimeConversion;
FromType = ToType;
} else {
SCS.Third = ICK_Identity;
}
QualType CanonFrom = S.Context.getCanonicalType(FromType);
QualType CanonTo = S.Context.getCanonicalType(ToType);
if (CanonFrom.getLocalUnqualifiedType()
== CanonTo.getLocalUnqualifiedType() &&
CanonFrom.getLocalQualifiers() != CanonTo.getLocalQualifiers()) {
FromType = ToType;
CanonFrom = CanonTo;
}
SCS.setToType(2, FromType);
if (CanonFrom == CanonTo)
return true;
if (S.getLangOpts().CPlusPlus || !InOverloadResolution)
return false;
ExprResult ER = ExprResult{From};
Sema::AssignConvertType Conv =
S.CheckSingleAssignmentConstraints(ToType, ER,
false,
false,
false);
ImplicitConversionKind SecondConv;
switch (Conv) {
case Sema::Compatible:
SecondConv = ICK_C_Only_Conversion;
break;
case Sema::CompatiblePointerDiscardsQualifiers:
case Sema::IncompatiblePointer:
case Sema::IncompatiblePointerSign:
SecondConv = ICK_Incompatible_Pointer_Conversion;
break;
default:
return false;
}
SCS.Second = SecondConv;
SCS.setToType(1, ToType);
SCS.Third = ICK_Identity;
SCS.setToType(2, ToType);
return true;
}
static bool
IsTransparentUnionStandardConversion(Sema &S, Expr* From,
QualType &ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle) {
const RecordType *UT = ToType->getAsUnionType();
if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
return false;
RecordDecl *UD = UT->getDecl();
for (const auto *it : UD->fields()) {
if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS,
CStyle, false)) {
ToType = it->getType();
return true;
}
}
return false;
}
bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
const BuiltinType *To = ToType->getAs<BuiltinType>();
if (!To) {
return false;
}
if (Context.isPromotableIntegerType(FromType) && !FromType->isBooleanType() &&
!FromType->isEnumeralType()) {
if (
(FromType->isSignedIntegerType() ||
Context.getTypeSize(FromType) < Context.getTypeSize(ToType))) {
return To->getKind() == BuiltinType::Int;
}
return To->getKind() == BuiltinType::UInt;
}
if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) {
if (FromEnumType->getDecl()->isScoped())
return false;
if (FromEnumType->getDecl()->isFixed()) {
QualType Underlying = FromEnumType->getDecl()->getIntegerType();
return Context.hasSameUnqualifiedType(Underlying, ToType) ||
IsIntegralPromotion(nullptr, Underlying, ToType);
}
if (ToType->isIntegerType() &&
isCompleteType(From->getBeginLoc(), FromType))
return Context.hasSameUnqualifiedType(
ToType, FromEnumType->getDecl()->getPromotionType());
if (getLangOpts().CPlusPlus)
return false;
}
if (FromType->isAnyCharacterType() && !FromType->isCharType() &&
ToType->isIntegerType()) {
bool FromIsSigned = FromType->isSignedIntegerType();
uint64_t FromSize = Context.getTypeSize(FromType);
QualType PromoteTypes[6] = {
Context.IntTy, Context.UnsignedIntTy,
Context.LongTy, Context.UnsignedLongTy ,
Context.LongLongTy, Context.UnsignedLongLongTy
};
for (int Idx = 0; Idx < 6; ++Idx) {
uint64_t ToSize = Context.getTypeSize(PromoteTypes[Idx]);
if (FromSize < ToSize ||
(FromSize == ToSize &&
FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType())) {
return Context.hasSameUnqualifiedType(ToType, PromoteTypes[Idx]);
}
}
}
if (From) {
if (FieldDecl *MemberDecl = From->getSourceBitField()) {
std::optional<llvm::APSInt> BitWidth;
if (FromType->isIntegralType(Context) &&
(BitWidth =
MemberDecl->getBitWidth()->getIntegerConstantExpr(Context))) {
llvm::APSInt ToSize(BitWidth->getBitWidth(), BitWidth->isUnsigned());
ToSize = Context.getTypeSize(ToType);
if (*BitWidth < ToSize ||
(FromType->isSignedIntegerType() && *BitWidth <= ToSize)) {
return To->getKind() == BuiltinType::Int;
}
if (FromType->isUnsignedIntegerType() && *BitWidth <= ToSize) {
return To->getKind() == BuiltinType::UInt;
}
return false;
}
}
}
if (FromType->isBooleanType() && To->getKind() == BuiltinType::Int) {
return true;
}
if (Context.getLangOpts().HLSL && FromType->isIntegerType() &&
ToType->isIntegerType())
return Context.getTypeSize(FromType) < Context.getTypeSize(ToType);
return false;
}
bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) {
if (const BuiltinType *FromBuiltin = FromType->getAs<BuiltinType>())
if (const BuiltinType *ToBuiltin = ToType->getAs<BuiltinType>()) {
if (FromBuiltin->getKind() == BuiltinType::Float &&
ToBuiltin->getKind() == BuiltinType::Double)
return true;
if (!getLangOpts().CPlusPlus &&
(FromBuiltin->getKind() == BuiltinType::Float ||
FromBuiltin->getKind() == BuiltinType::Double) &&
(ToBuiltin->getKind() == BuiltinType::LongDouble ||
ToBuiltin->getKind() == BuiltinType::Float128 ||
ToBuiltin->getKind() == BuiltinType::Ibm128))
return true;
if (getLangOpts().HLSL && FromBuiltin->getKind() == BuiltinType::Half &&
(ToBuiltin->getKind() == BuiltinType::Float ||
ToBuiltin->getKind() == BuiltinType::Double))
return true;
if (!getLangOpts().NativeHalfType &&
FromBuiltin->getKind() == BuiltinType::Half &&
ToBuiltin->getKind() == BuiltinType::Float)
return true;
}
return false;
}
bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) {
const ComplexType *FromComplex = FromType->getAs<ComplexType>();
if (!FromComplex)
return false;
const ComplexType *ToComplex = ToType->getAs<ComplexType>();
if (!ToComplex)
return false;
return IsFloatingPointPromotion(FromComplex->getElementType(),
ToComplex->getElementType()) ||
IsIntegralPromotion(nullptr, FromComplex->getElementType(),
ToComplex->getElementType());
}
static QualType
BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
QualType ToPointee, QualType ToType,
ASTContext &Context,
bool StripObjCLifetime = false) {
assert((FromPtr->getTypeClass() == Type::Pointer ||
FromPtr->getTypeClass() == Type::ObjCObjectPointer) &&
"Invalid similarly-qualified pointer type");
if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType())
return ToType.getUnqualifiedType();
QualType CanonFromPointee
= Context.getCanonicalType(FromPtr->getPointeeType());
QualType CanonToPointee = Context.getCanonicalType(ToPointee);
Qualifiers Quals = CanonFromPointee.getQualifiers();
if (StripObjCLifetime)
Quals.removeObjCLifetime();
if (CanonToPointee.getLocalQualifiers() == Quals) {
if (!ToType.isNull())
return ToType.getUnqualifiedType();
if (isa<ObjCObjectPointerType>(ToType))
return Context.getObjCObjectPointerType(ToPointee);
return Context.getPointerType(ToPointee);
}
QualType QualifiedCanonToPointee
= Context.getQualifiedType(CanonToPointee.getLocalUnqualifiedType(), Quals);
if (isa<ObjCObjectPointerType>(ToType))
return Context.getObjCObjectPointerType(QualifiedCanonToPointee);
return Context.getPointerType(QualifiedCanonToPointee);
}
static bool isNullPointerConstantForConversion(Expr *Expr,
bool InOverloadResolution,
ASTContext &Context) {
if (Expr->isValueDependent() && !Expr->isTypeDependent() &&
Expr->getType()->isIntegerType() && !Expr->getType()->isEnumeralType())
return !InOverloadResolution;
return Expr->isNullPointerConstant(Context,
InOverloadResolution? Expr::NPC_ValueDependentIsNotNull
: Expr::NPC_ValueDependentIsNull);
}
bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
bool InOverloadResolution,
QualType& ConvertedType,
bool &IncompatibleObjC) {
IncompatibleObjC = false;
if (isObjCPointerConversion(FromType, ToType, ConvertedType,
IncompatibleObjC))
return true;
if (ToType->isObjCObjectPointerType() &&
isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
if (FromType->isBlockPointerType() && ToType->isPointerType() &&
ToType->castAs<PointerType>()->getPointeeType()->isVoidType()) {
ConvertedType = ToType;
return true;
}
if (ToType->isBlockPointerType() &&
isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
if (ToType->isNullPtrType() &&
isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
const PointerType* ToTypePtr = ToType->getAs<PointerType>();
if (!ToTypePtr)
return false;
if (isNullPointerConstantForConversion(From, InOverloadResolution, Context)) {
ConvertedType = ToType;
return true;
}
QualType ToPointeeType = ToTypePtr->getPointeeType();
if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType() &&
!getLangOpts().ObjCAutoRefCount) {
ConvertedType = BuildSimilarlyQualifiedPointerType(
FromType->castAs<ObjCObjectPointerType>(), ToPointeeType, ToType,
Context);
return true;
}
const PointerType *FromTypePtr = FromType->getAs<PointerType>();
if (!FromTypePtr)
return false;
QualType FromPointeeType = FromTypePtr->getPointeeType();
if (Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType))
return false;
if (FromPointeeType->isIncompleteOrObjectType() &&
ToPointeeType->isVoidType()) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
ToType, Context,
true);
return true;
}
if (getLangOpts().MSVCCompat && FromPointeeType->isFunctionType() &&
ToPointeeType->isVoidType()) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
ToType, Context);
return true;
}
if (!getLangOpts().CPlusPlus &&
Context.typesAreCompatible(FromPointeeType, ToPointeeType)) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
ToType, Context);
return true;
}
if (getLangOpts().CPlusPlus && FromPointeeType->isRecordType() &&
ToPointeeType->isRecordType() &&
!Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType) &&
IsDerivedFrom(From->getBeginLoc(), FromPointeeType, ToPointeeType)) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
ToType, Context);
return true;
}
if (FromPointeeType->isVectorType() && ToPointeeType->isVectorType() &&
Context.areCompatibleVectorTypes(FromPointeeType, ToPointeeType)) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
ToType, Context);
return true;
}
return false;
}
static QualType AdoptQualifiers(ASTContext &Context, QualType T, Qualifiers Qs){
Qualifiers TQs = T.getQualifiers();
if (TQs == Qs)
return T;
if (Qs.compatiblyIncludes(TQs))
return Context.getQualifiedType(T, Qs);
return Context.getQualifiedType(T.getUnqualifiedType(), Qs);
}
bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType,
bool &IncompatibleObjC) {
if (!getLangOpts().ObjC)
return false;
Qualifiers FromQualifiers = FromType.getQualifiers();
const ObjCObjectPointerType* ToObjCPtr =
ToType->getAs<ObjCObjectPointerType>();
const ObjCObjectPointerType *FromObjCPtr =
FromType->getAs<ObjCObjectPointerType>();
if (ToObjCPtr && FromObjCPtr) {
if (Context.hasSameUnqualifiedType(ToObjCPtr->getPointeeType(),
FromObjCPtr->getPointeeType()))
return false;
if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) {
const ObjCInterfaceType* LHS = ToObjCPtr->getInterfaceType();
const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType();
if (getLangOpts().CPlusPlus && LHS && RHS &&
!ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs(
FromObjCPtr->getPointeeType()))
return false;
ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr,
ToObjCPtr->getPointeeType(),
ToType, Context);
ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
}
if (Context.canAssignObjCInterfaces(FromObjCPtr, ToObjCPtr)) {
IncompatibleObjC = true;
ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr,
ToObjCPtr->getPointeeType(),
ToType, Context);
ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
}
}
QualType ToPointeeType;
if (const PointerType *ToCPtr = ToType->getAs<PointerType>())
ToPointeeType = ToCPtr->getPointeeType();
else if (const BlockPointerType *ToBlockPtr =
ToType->getAs<BlockPointerType>()) {
if (FromObjCPtr && FromObjCPtr->isObjCBuiltinType()) {
ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers);
return true;
}
ToPointeeType = ToBlockPtr->getPointeeType();
}
else if (FromType->getAs<BlockPointerType>() &&
ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) {
ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers);
return true;
}
else
return false;
QualType FromPointeeType;
if (const PointerType *FromCPtr = FromType->getAs<PointerType>())
FromPointeeType = FromCPtr->getPointeeType();
else if (const BlockPointerType *FromBlockPtr =
FromType->getAs<BlockPointerType>())
FromPointeeType = FromBlockPtr->getPointeeType();
else
return false;
if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() &&
isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
IncompatibleObjC)) {
IncompatibleObjC = true;
ConvertedType = Context.getPointerType(ConvertedType);
ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
}
if (FromPointeeType->getAs<ObjCObjectPointerType>() &&
ToPointeeType->getAs<ObjCObjectPointerType>() &&
isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
IncompatibleObjC)) {
ConvertedType = Context.getPointerType(ConvertedType);
ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
}
const FunctionProtoType *FromFunctionType
= FromPointeeType->getAs<FunctionProtoType>();
const FunctionProtoType *ToFunctionType
= ToPointeeType->getAs<FunctionProtoType>();
if (FromFunctionType && ToFunctionType) {
if (Context.getCanonicalType(FromPointeeType)
== Context.getCanonicalType(ToPointeeType))
return false;
if (FromFunctionType->getNumParams() != ToFunctionType->getNumParams() ||
FromFunctionType->isVariadic() != ToFunctionType->isVariadic() ||
FromFunctionType->getMethodQuals() != ToFunctionType->getMethodQuals())
return false;
bool HasObjCConversion = false;
if (Context.getCanonicalType(FromFunctionType->getReturnType()) ==
Context.getCanonicalType(ToFunctionType->getReturnType())) {
} else if (isObjCPointerConversion(FromFunctionType->getReturnType(),
ToFunctionType->getReturnType(),
ConvertedType, IncompatibleObjC)) {
HasObjCConversion = true;
} else {
return false;
}
for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumParams();
ArgIdx != NumArgs; ++ArgIdx) {
QualType FromArgType = FromFunctionType->getParamType(ArgIdx);
QualType ToArgType = ToFunctionType->getParamType(ArgIdx);
if (Context.getCanonicalType(FromArgType)
== Context.getCanonicalType(ToArgType)) {
} else if (isObjCPointerConversion(FromArgType, ToArgType,
ConvertedType, IncompatibleObjC)) {
HasObjCConversion = true;
} else {
return false;
}
}
if (HasObjCConversion) {
ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers);
IncompatibleObjC = true;
return true;
}
}
return false;
}
bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType) {
QualType ToPointeeType;
if (const BlockPointerType *ToBlockPtr =
ToType->getAs<BlockPointerType>())
ToPointeeType = ToBlockPtr->getPointeeType();
else
return false;
QualType FromPointeeType;
if (const BlockPointerType *FromBlockPtr =
FromType->getAs<BlockPointerType>())
FromPointeeType = FromBlockPtr->getPointeeType();
else
return false;
const FunctionProtoType *FromFunctionType
= FromPointeeType->getAs<FunctionProtoType>();
const FunctionProtoType *ToFunctionType
= ToPointeeType->getAs<FunctionProtoType>();
if (!FromFunctionType || !ToFunctionType)
return false;
if (Context.hasSameType(FromPointeeType, ToPointeeType))
return true;
if (FromFunctionType->getNumParams() != ToFunctionType->getNumParams() ||
FromFunctionType->isVariadic() != ToFunctionType->isVariadic())
return false;
FunctionType::ExtInfo FromEInfo = FromFunctionType->getExtInfo();
FunctionType::ExtInfo ToEInfo = ToFunctionType->getExtInfo();
if (FromEInfo != ToEInfo)
return false;
bool IncompatibleObjC = false;
if (Context.hasSameType(FromFunctionType->getReturnType(),
ToFunctionType->getReturnType())) {
} else {
QualType RHS = FromFunctionType->getReturnType();
QualType LHS = ToFunctionType->getReturnType();
if ((!getLangOpts().CPlusPlus || !RHS->isRecordType()) &&
!RHS.hasQualifiers() && LHS.hasQualifiers())
LHS = LHS.getUnqualifiedType();
if (Context.hasSameType(RHS,LHS)) {
} else if (isObjCPointerConversion(RHS, LHS,
ConvertedType, IncompatibleObjC)) {
if (IncompatibleObjC)
return false;
}
else
return false;
}
for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumParams();
ArgIdx != NumArgs; ++ArgIdx) {
IncompatibleObjC = false;
QualType FromArgType = FromFunctionType->getParamType(ArgIdx);
QualType ToArgType = ToFunctionType->getParamType(ArgIdx);
if (Context.hasSameType(FromArgType, ToArgType)) {
} else if (isObjCPointerConversion(ToArgType, FromArgType,
ConvertedType, IncompatibleObjC)) {
if (IncompatibleObjC)
return false;
} else
return false;
}
SmallVector<FunctionProtoType::ExtParameterInfo, 4> NewParamInfos;
bool CanUseToFPT, CanUseFromFPT;
if (!Context.mergeExtParameterInfo(ToFunctionType, FromFunctionType,
CanUseToFPT, CanUseFromFPT,
NewParamInfos))
return false;
ConvertedType = ToType;
return true;
}
enum {
ft_default,
ft_different_class,
ft_parameter_arity,
ft_parameter_mismatch,
ft_return_type,
ft_qualifer_mismatch,
ft_noexcept
};
static const FunctionProtoType *tryGetFunctionProtoType(QualType FromType) {
if (auto *FPT = FromType->getAs<FunctionProtoType>())
return FPT;
if (auto *MPT = FromType->getAs<MemberPointerType>())
return MPT->getPointeeType()->getAs<FunctionProtoType>();
return nullptr;
}
void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
QualType FromType, QualType ToType) {
if (FromType.isNull() || ToType.isNull()) {
PDiag << ft_default;
return;
}
if (FromType->isMemberPointerType() && ToType->isMemberPointerType()) {
const auto *FromMember = FromType->castAs<MemberPointerType>(),
*ToMember = ToType->castAs<MemberPointerType>();
if (!Context.hasSameType(FromMember->getClass(), ToMember->getClass())) {
PDiag << ft_different_class << QualType(ToMember->getClass(), 0)
<< QualType(FromMember->getClass(), 0);
return;
}
FromType = FromMember->getPointeeType();
ToType = ToMember->getPointeeType();
}
if (FromType->isPointerType())
FromType = FromType->getPointeeType();
if (ToType->isPointerType())
ToType = ToType->getPointeeType();
FromType = FromType.getNonReferenceType();
ToType = ToType.getNonReferenceType();
if (FromType->isInstantiationDependentType() &&
!FromType->getAs<TemplateSpecializationType>()) {
PDiag << ft_default;
return;
}
if (Context.hasSameType(FromType, ToType)) {
PDiag << ft_default;
return;
}
const FunctionProtoType *FromFunction = tryGetFunctionProtoType(FromType),
*ToFunction = tryGetFunctionProtoType(ToType);
if (!FromFunction || !ToFunction) {
PDiag << ft_default;
return;
}
if (FromFunction->getNumParams() != ToFunction->getNumParams()) {
PDiag << ft_parameter_arity << ToFunction->getNumParams()
<< FromFunction->getNumParams();
return;
}
unsigned ArgPos;
if (!FunctionParamTypesAreEqual(FromFunction, ToFunction, &ArgPos)) {
PDiag << ft_parameter_mismatch << ArgPos + 1
<< ToFunction->getParamType(ArgPos)
<< FromFunction->getParamType(ArgPos);
return;
}
if (!Context.hasSameType(FromFunction->getReturnType(),
ToFunction->getReturnType())) {
PDiag << ft_return_type << ToFunction->getReturnType()
<< FromFunction->getReturnType();
return;
}
if (FromFunction->getMethodQuals() != ToFunction->getMethodQuals()) {
PDiag << ft_qualifer_mismatch << ToFunction->getMethodQuals()
<< FromFunction->getMethodQuals();
return;
}
if (cast<FunctionProtoType>(FromFunction->getCanonicalTypeUnqualified())
->isNothrow() !=
cast<FunctionProtoType>(ToFunction->getCanonicalTypeUnqualified())
->isNothrow()) {
PDiag << ft_noexcept;
return;
}
PDiag << ft_default;
}
bool Sema::FunctionParamTypesAreEqual(ArrayRef<QualType> Old,
ArrayRef<QualType> New, unsigned *ArgPos,
bool Reversed) {
assert(llvm::size(Old) == llvm::size(New) &&
"Can't compare parameters of functions with different number of "
"parameters!");
for (auto &&[Idx, Type] : llvm::enumerate(Old)) {
size_t J = Reversed ? (llvm::size(New) - Idx - 1) : Idx;
QualType OldType =
Context.removePtrSizeAddrSpace(Type.getUnqualifiedType());
QualType NewType =
Context.removePtrSizeAddrSpace((New.begin() + J)->getUnqualifiedType());
if (!Context.hasSameType(OldType, NewType)) {
if (ArgPos)
*ArgPos = Idx;
return false;
}
}
return true;
}
bool Sema::FunctionParamTypesAreEqual(const FunctionProtoType *OldType,
const FunctionProtoType *NewType,
unsigned *ArgPos, bool Reversed) {
return FunctionParamTypesAreEqual(OldType->param_types(),
NewType->param_types(), ArgPos, Reversed);
}
bool Sema::FunctionNonObjectParamTypesAreEqual(const FunctionDecl *OldFunction,
const FunctionDecl *NewFunction,
unsigned *ArgPos,
bool Reversed) {
if (OldFunction->getNumNonObjectParams() !=
NewFunction->getNumNonObjectParams())
return false;
unsigned OldIgnore =
unsigned(OldFunction->hasCXXExplicitFunctionObjectParameter());
unsigned NewIgnore =
unsigned(NewFunction->hasCXXExplicitFunctionObjectParameter());
auto *OldPT = cast<FunctionProtoType>(OldFunction->getFunctionType());
auto *NewPT = cast<FunctionProtoType>(NewFunction->getFunctionType());
return FunctionParamTypesAreEqual(OldPT->param_types().slice(OldIgnore),
NewPT->param_types().slice(NewIgnore),
ArgPos, Reversed);
}
bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
CastKind &Kind,
CXXCastPath& BasePath,
bool IgnoreBaseAccess,
bool Diagnose) {
QualType FromType = From->getType();
bool IsCStyleOrFunctionalCast = IgnoreBaseAccess;
Kind = CK_BitCast;
if (Diagnose && !IsCStyleOrFunctionalCast && !FromType->isAnyPointerType() &&
From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) ==
Expr::NPCK_ZeroExpression) {
if (Context.hasSameUnqualifiedType(From->getType(), Context.BoolTy))
DiagRuntimeBehavior(From->getExprLoc(), From,
PDiag(diag::warn_impcast_bool_to_null_pointer)
<< ToType << From->getSourceRange());
else if (!isUnevaluatedContext())
Diag(From->getExprLoc(), diag::warn_non_literal_null_pointer)
<< ToType << From->getSourceRange();
}
if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) {
if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) {
QualType FromPointeeType = FromPtrType->getPointeeType(),
ToPointeeType = ToPtrType->getPointeeType();
if (FromPointeeType->isRecordType() && ToPointeeType->isRecordType() &&
!Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType)) {
unsigned InaccessibleID = 0;
unsigned AmbiguousID = 0;
if (Diagnose) {
InaccessibleID = diag::err_upcast_to_inaccessible_base;
AmbiguousID = diag::err_ambiguous_derived_to_base_conv;
}
if (CheckDerivedToBaseConversion(
FromPointeeType, ToPointeeType, InaccessibleID, AmbiguousID,
From->getExprLoc(), From->getSourceRange(), DeclarationName(),
&BasePath, IgnoreBaseAccess))
return true;
Kind = CK_DerivedToBase;
}
if (Diagnose && !IsCStyleOrFunctionalCast &&
FromPointeeType->isFunctionType() && ToPointeeType->isVoidType()) {
assert(getLangOpts().MSVCCompat &&
"this should only be possible with MSVCCompat!");
Diag(From->getExprLoc(), diag::ext_ms_impcast_fn_obj)
<< From->getSourceRange();
}
}
} else if (const ObjCObjectPointerType *ToPtrType =
ToType->getAs<ObjCObjectPointerType>()) {
if (const ObjCObjectPointerType *FromPtrType =
FromType->getAs<ObjCObjectPointerType>()) {
if (FromPtrType->isObjCBuiltinType() || ToPtrType->isObjCBuiltinType())
return false;
} else if (FromType->isBlockPointerType()) {
Kind = CK_BlockPointerToObjCPointerCast;
} else {
Kind = CK_CPointerToObjCPointerCast;
}
} else if (ToType->isBlockPointerType()) {
if (!FromType->isBlockPointerType())
Kind = CK_AnyPointerToBlockPointerCast;
}
if (From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
Kind = CK_NullToPointer;
return false;
}
bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
QualType ToType,
bool InOverloadResolution,
QualType &ConvertedType) {
const MemberPointerType *ToTypePtr = ToType->getAs<MemberPointerType>();
if (!ToTypePtr)
return false;
if (From->isNullPointerConstant(Context,
InOverloadResolution? Expr::NPC_ValueDependentIsNotNull
: Expr::NPC_ValueDependentIsNull)) {
ConvertedType = ToType;
return true;
}
const MemberPointerType *FromTypePtr = FromType->getAs<MemberPointerType>();
if (!FromTypePtr)
return false;
QualType FromClass(FromTypePtr->getClass(), 0);
QualType ToClass(ToTypePtr->getClass(), 0);
if (!Context.hasSameUnqualifiedType(FromClass, ToClass) &&
IsDerivedFrom(From->getBeginLoc(), ToClass, FromClass)) {
ConvertedType = Context.getMemberPointerType(FromTypePtr->getPointeeType(),
ToClass.getTypePtr());
return true;
}
return false;
}
bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
CastKind &Kind,
CXXCastPath &BasePath,
bool IgnoreBaseAccess) {
QualType FromType = From->getType();
const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
if (!FromPtrType) {
assert(From->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull) &&
"Expr must be null pointer constant!");
Kind = CK_NullToMemberPointer;
return false;
}
const MemberPointerType *ToPtrType = ToType->getAs<MemberPointerType>();
assert(ToPtrType && "No member pointer cast has a target type "
"that is not a member pointer.");
QualType FromClass = QualType(FromPtrType->getClass(), 0);
QualType ToClass = QualType(ToPtrType->getClass(), 0);
assert(FromClass->isRecordType() && "Pointer into non-class.");
assert(ToClass->isRecordType() && "Pointer into non-class.");
CXXBasePaths Paths(true, true,
true);
bool DerivationOkay =
IsDerivedFrom(From->getBeginLoc(), ToClass, FromClass, Paths);
assert(DerivationOkay &&
"Should not have been called if derivation isn't OK.");
(void)DerivationOkay;
if (Paths.isAmbiguous(Context.getCanonicalType(FromClass).
getUnqualifiedType())) {
std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
Diag(From->getExprLoc(), diag::err_ambiguous_memptr_conv)
<< 0 << FromClass << ToClass << PathDisplayStr << From->getSourceRange();
return true;
}
if (const RecordType *VBase = Paths.getDetectedVirtual()) {
Diag(From->getExprLoc(), diag::err_memptr_conv_via_virtual)
<< FromClass << ToClass << QualType(VBase, 0)
<< From->getSourceRange();
return true;
}
if (!IgnoreBaseAccess)
CheckBaseClassAccess(From->getExprLoc(), FromClass, ToClass,
Paths.front(),
diag::err_downcast_from_inaccessible_base);
BuildBasePathArray(Paths, BasePath);
Kind = CK_BaseToDerivedMemberPointer;
return false;
}
static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
Qualifiers ToQuals) {
if (ToQuals.hasConst() &&
ToQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone)
return false;
return true;
}
static bool isQualificationConversionStep(QualType FromType, QualType ToType,
bool CStyle, bool IsTopLevel,
bool &PreviousToQualsIncludeConst,
bool &ObjCLifetimeConversion) {
Qualifiers FromQuals = FromType.getQualifiers();
Qualifiers ToQuals = ToType.getQualifiers();
FromQuals.removeUnaligned();
if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime()) {
if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
ObjCLifetimeConversion = true;
FromQuals.removeObjCLifetime();
ToQuals.removeObjCLifetime();
} else {
return false;
}
}
if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
(!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
FromQuals.removeObjCGCAttr();
ToQuals.removeObjCGCAttr();
}
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
return false;
if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() &&
(!IsTopLevel ||
!(ToQuals.isAddressSpaceSupersetOf(FromQuals) ||
(CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals)))))
return false;
if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers() &&
!PreviousToQualsIncludeConst)
return false;
if (FromType->isIncompleteArrayType() && !ToType->isIncompleteArrayType())
return false;
if (!CStyle && FromType->isConstantArrayType() &&
ToType->isIncompleteArrayType() && !PreviousToQualsIncludeConst)
return false;
PreviousToQualsIncludeConst =
PreviousToQualsIncludeConst && ToQuals.hasConst();
return true;
}
bool
Sema::IsQualificationConversion(QualType FromType, QualType ToType,
bool CStyle, bool &ObjCLifetimeConversion) {
FromType = Context.getCanonicalType(FromType);
ToType = Context.getCanonicalType(ToType);
ObjCLifetimeConversion = false;
if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType())
return false;
bool PreviousToQualsIncludeConst = true;
bool UnwrappedAnyPointer = false;
while (Context.UnwrapSimilarTypes(FromType, ToType)) {
if (!isQualificationConversionStep(
FromType, ToType, CStyle, !UnwrappedAnyPointer,
PreviousToQualsIncludeConst, ObjCLifetimeConversion))
return false;
UnwrappedAnyPointer = true;
}
return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
}
static bool tryAtomicConversion(Sema &S, Expr *From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle) {
const AtomicType *ToAtomic = ToType->getAs<AtomicType>();
if (!ToAtomic)
return false;
StandardConversionSequence InnerSCS;
if (!IsStandardConversion(S, From, ToAtomic->getValueType(),
InOverloadResolution, InnerSCS,
CStyle, false))
return false;
SCS.Second = InnerSCS.Second;
SCS.setToType(1, InnerSCS.getToType(1));
SCS.Third = InnerSCS.Third;
SCS.QualificationIncludesObjCLifetime
= InnerSCS.QualificationIncludesObjCLifetime;
SCS.setToType(2, InnerSCS.getToType(2));
return true;
}
static bool isFirstArgumentCompatibleWithType(ASTContext &Context,
CXXConstructorDecl *Constructor,
QualType Type) {
const auto *CtorType = Constructor->getType()->castAs<FunctionProtoType>();
if (CtorType->getNumParams() > 0) {
QualType FirstArg = CtorType->getParamType(0);
if (Context.hasSameUnqualifiedType(Type, FirstArg.getNonReferenceType()))
return true;
}
return false;
}
static OverloadingResult
IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
CXXRecordDecl *To,
UserDefinedConversionSequence &User,
OverloadCandidateSet &CandidateSet,
bool AllowExplicit) {
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
for (auto *D : S.LookupConstructors(To)) {
auto Info = getConstructorInfo(D);
if (!Info)
continue;
bool Usable = !Info.Constructor->isInvalidDecl() &&
S.isInitListConstructor(Info.Constructor);
if (Usable) {
bool SuppressUserConversions = false;
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
nullptr, From,
CandidateSet, SuppressUserConversions,
false,
AllowExplicit);
else
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, From,
CandidateSet, SuppressUserConversions,
false, AllowExplicit);
}
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
switch (auto Result =
CandidateSet.BestViableFunction(S, From->getBeginLoc(), Best)) {
case OR_Deleted:
case OR_Success: {
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
QualType ThisType = Constructor->getFunctionObjectParameterType();
User.Before.setAsIdentityConversion();
User.HadMultipleCandidates = HadMultipleCandidates;
User.ConversionFunction = Constructor;
User.FoundConversionFunction = Best->FoundDecl;
User.After.setAsIdentityConversion();
User.After.setFromType(ThisType);
User.After.setAllToTypes(ToType);
return Result;
}
case OR_No_Viable_Function:
return OR_No_Viable_Function;
case OR_Ambiguous:
return OR_Ambiguous;
}
llvm_unreachable("Invalid OverloadResult!");
}
static OverloadingResult
IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence &User,
OverloadCandidateSet &CandidateSet,
AllowedExplicit AllowExplicit,
bool AllowObjCConversionOnExplicit) {
assert(AllowExplicit != AllowedExplicit::None ||
!AllowObjCConversionOnExplicit);
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
bool ConstructorsOnly = false;
if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) {
if (S.Context.hasSameUnqualifiedType(ToType, From->getType()) ||
(From->getType()->getAs<RecordType>() &&
S.IsDerivedFrom(From->getBeginLoc(), From->getType(), ToType)))
ConstructorsOnly = true;
if (!S.isCompleteType(From->getExprLoc(), ToType)) {
} else if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
Expr **Args = &From;
unsigned NumArgs = 1;
bool ListInitializing = false;
if (InitListExpr *InitList = dyn_cast<InitListExpr>(From)) {
OverloadingResult Result = IsInitializerListConstructorConversion(
S, From, ToType, ToRecordDecl, User, CandidateSet,
AllowExplicit == AllowedExplicit::All);
if (Result != OR_No_Viable_Function)
return Result;
CandidateSet.clear(
OverloadCandidateSet::CSK_InitByUserDefinedConversion);
Args = InitList->getInits();
NumArgs = InitList->getNumInits();
ListInitializing = true;
}
for (auto *D : S.LookupConstructors(ToRecordDecl)) {
auto Info = getConstructorInfo(D);
if (!Info)
continue;
bool Usable = !Info.Constructor->isInvalidDecl();
if (!ListInitializing)
Usable = Usable && Info.Constructor->isConvertingConstructor(
true);
if (Usable) {
bool SuppressUserConversions = !ConstructorsOnly;
if (SuppressUserConversions && ListInitializing) {
SuppressUserConversions =
NumArgs == 1 && isa<InitListExpr>(Args[0]) &&
isFirstArgumentCompatibleWithType(S.Context, Info.Constructor,
ToType);
}
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
nullptr, llvm::ArrayRef(Args, NumArgs),
CandidateSet, SuppressUserConversions,
false,
AllowExplicit == AllowedExplicit::All);
else
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
llvm::ArrayRef(Args, NumArgs), CandidateSet,
SuppressUserConversions,
false,
AllowExplicit == AllowedExplicit::All);
}
}
}
}
if (ConstructorsOnly || isa<InitListExpr>(From)) {
} else if (!S.isCompleteType(From->getBeginLoc(), From->getType())) {
} else if (const RecordType *FromRecordType =
From->getType()->getAs<RecordType>()) {
if (CXXRecordDecl *FromRecordDecl
= dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
const auto &Conversions = FromRecordDecl->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
DeclAccessPair FoundDecl = I.getPair();
NamedDecl *D = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
CXXConversionDecl *Conv;
FunctionTemplateDecl *ConvTemplate;
if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(D)))
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
Conv = cast<CXXConversionDecl>(D);
if (ConvTemplate)
S.AddTemplateConversionCandidate(
ConvTemplate, FoundDecl, ActingContext, From, ToType,
CandidateSet, AllowObjCConversionOnExplicit,
AllowExplicit != AllowedExplicit::None);
else
S.AddConversionCandidate(Conv, FoundDecl, ActingContext, From, ToType,
CandidateSet, AllowObjCConversionOnExplicit,
AllowExplicit != AllowedExplicit::None);
}
}
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
switch (auto Result =
CandidateSet.BestViableFunction(S, From->getBeginLoc(), Best)) {
case OR_Success:
case OR_Deleted:
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Best->Function)) {
if (isa<InitListExpr>(From)) {
User.Before.setAsIdentityConversion();
} else {
if (Best->Conversions[0].isEllipsis())
User.EllipsisConversion = true;
else {
User.Before = Best->Conversions[0].Standard;
User.EllipsisConversion = false;
}
}
User.HadMultipleCandidates = HadMultipleCandidates;
User.ConversionFunction = Constructor;
User.FoundConversionFunction = Best->FoundDecl;
User.After.setAsIdentityConversion();
User.After.setFromType(Constructor->getFunctionObjectParameterType());
User.After.setAllToTypes(ToType);
return Result;
}
if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
User.Before = Best->Conversions[0].Standard;
User.HadMultipleCandidates = HadMultipleCandidates;
User.ConversionFunction = Conversion;
User.FoundConversionFunction = Best->FoundDecl;
User.EllipsisConversion = false;
User.After = Best->FinalConversion;
return Result;
}
llvm_unreachable("Not a constructor or conversion function?");
case OR_No_Viable_Function:
return OR_No_Viable_Function;
case OR_Ambiguous:
return OR_Ambiguous;
}
llvm_unreachable("Invalid OverloadResult!");
}
bool
Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
ImplicitConversionSequence ICS;
OverloadCandidateSet CandidateSet(From->getExprLoc(),
OverloadCandidateSet::CSK_Normal);
OverloadingResult OvResult =
IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined,
CandidateSet, AllowedExplicit::None, false);
if (!(OvResult == OR_Ambiguous ||
(OvResult == OR_No_Viable_Function && !CandidateSet.empty())))
return false;
auto Cands = CandidateSet.CompleteCandidates(
*this,
OvResult == OR_Ambiguous ? OCD_AmbiguousCandidates : OCD_AllCandidates,
From);
if (OvResult == OR_Ambiguous)
Diag(From->getBeginLoc(), diag::err_typecheck_ambiguous_condition)
<< From->getType() << ToType << From->getSourceRange();
else {
if (!RequireCompleteType(From->getBeginLoc(), ToType,
diag::err_typecheck_nonviable_condition_incomplete,
From->getType(), From->getSourceRange()))
Diag(From->getBeginLoc(), diag::err_typecheck_nonviable_condition)
<< false << From->getType() << From->getSourceRange() << ToType;
}
CandidateSet.NoteCandidates(
*this, From, Cands);
return true;
}
static const FunctionType *
getConversionOpReturnTyAsFunction(CXXConversionDecl *Conv) {
const FunctionType *ConvFuncTy = Conv->getType()->castAs<FunctionType>();
const PointerType *RetPtrTy =
ConvFuncTy->getReturnType()->getAs<PointerType>();
if (!RetPtrTy)
return nullptr;
return RetPtrTy->getPointeeType()->getAs<FunctionType>();
}
static ImplicitConversionSequence::CompareKind
compareConversionFunctions(Sema &S, FunctionDecl *Function1,
FunctionDecl *Function2) {
CXXConversionDecl *Conv1 = dyn_cast_or_null<CXXConversionDecl>(Function1);
CXXConversionDecl *Conv2 = dyn_cast_or_null<CXXConversionDecl>(Function2);
if (!Conv1 || !Conv2)
return ImplicitConversionSequence::Indistinguishable;
if (!Conv1->getParent()->isLambda() || !Conv2->getParent()->isLambda())
return ImplicitConversionSequence::Indistinguishable;
if (S.getLangOpts().ObjC && S.getLangOpts().CPlusPlus11) {
bool Block1 = Conv1->getConversionType()->isBlockPointerType();
bool Block2 = Conv2->getConversionType()->isBlockPointerType();
if (Block1 != Block2)
return Block1 ? ImplicitConversionSequence::Worse
: ImplicitConversionSequence::Better;
}
const FunctionType *Conv1FuncRet = getConversionOpReturnTyAsFunction(Conv1);
const FunctionType *Conv2FuncRet = getConversionOpReturnTyAsFunction(Conv2);
if (Conv1FuncRet && Conv2FuncRet &&
Conv1FuncRet->getCallConv() != Conv2FuncRet->getCallConv()) {
CallingConv Conv1CC = Conv1FuncRet->getCallConv();
CallingConv Conv2CC = Conv2FuncRet->getCallConv();
CXXMethodDecl *CallOp = Conv2->getParent()->getLambdaCallOperator();
const auto *CallOpProto = CallOp->getType()->castAs<FunctionProtoType>();
CallingConv CallOpCC =
CallOp->getType()->castAs<FunctionType>()->getCallConv();
CallingConv DefaultFree = S.Context.getDefaultCallingConvention(
CallOpProto->isVariadic(), false);
CallingConv DefaultMember = S.Context.getDefaultCallingConvention(
CallOpProto->isVariadic(), true);
CallingConv PrefOrder[] = {DefaultFree, DefaultMember, CallOpCC};
for (CallingConv CC : PrefOrder) {
if (Conv1CC == CC)
return ImplicitConversionSequence::Better;
if (Conv2CC == CC)
return ImplicitConversionSequence::Worse;
}
}
return ImplicitConversionSequence::Indistinguishable;
}
static bool hasDeprecatedStringLiteralToCharPtrConversion(
const ImplicitConversionSequence &ICS) {
return (ICS.isStandard() && ICS.Standard.DeprecatedStringLiteralToCharPtr) ||
(ICS.isUserDefined() &&
ICS.UserDefined.Before.DeprecatedStringLiteralToCharPtr);
}
static ImplicitConversionSequence::CompareKind
CompareImplicitConversionSequences(Sema &S, SourceLocation Loc,
const ImplicitConversionSequence& ICS1,
const ImplicitConversionSequence& ICS2)
{
if (S.getLangOpts().CPlusPlus11 && !S.getLangOpts().WritableStrings &&
hasDeprecatedStringLiteralToCharPtrConversion(ICS1) !=
hasDeprecatedStringLiteralToCharPtrConversion(ICS2) &&
ICS1.isBad() == ICS2.isBad())
return hasDeprecatedStringLiteralToCharPtrConversion(ICS1)
? ImplicitConversionSequence::Worse
: ImplicitConversionSequence::Better;
if (ICS1.getKindRank() < ICS2.getKindRank())
return ImplicitConversionSequence::Better;
if (ICS2.getKindRank() < ICS1.getKindRank())
return ImplicitConversionSequence::Worse;
if (ICS1.getKind() != ICS2.getKind())
return ImplicitConversionSequence::Indistinguishable;
ImplicitConversionSequence::CompareKind Result =
ImplicitConversionSequence::Indistinguishable;
if (!ICS1.isBad()) {
bool StdInit1 = false, StdInit2 = false;
if (ICS1.hasInitializerListContainerType())
StdInit1 = S.isStdInitializerList(ICS1.getInitializerListContainerType(),
nullptr);
if (ICS2.hasInitializerListContainerType())
StdInit2 = S.isStdInitializerList(ICS2.getInitializerListContainerType(),
nullptr);
if (StdInit1 != StdInit2)
return StdInit1 ? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
if (ICS1.hasInitializerListContainerType() &&
ICS2.hasInitializerListContainerType())
if (auto *CAT1 = S.Context.getAsConstantArrayType(
ICS1.getInitializerListContainerType()))
if (auto *CAT2 = S.Context.getAsConstantArrayType(
ICS2.getInitializerListContainerType())) {
if (S.Context.hasSameUnqualifiedType(CAT1->getElementType(),
CAT2->getElementType())) {
if (CAT1->getSize() != CAT2->getSize())
return CAT1->getSize().ult(CAT2->getSize())
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
if (ICS1.isInitializerListOfIncompleteArray() !=
ICS2.isInitializerListOfIncompleteArray())
return ICS2.isInitializerListOfIncompleteArray()
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
}
}
}
if (ICS1.isStandard())
Result = CompareStandardConversionSequences(S, Loc,
ICS1.Standard, ICS2.Standard);
else if (ICS1.isUserDefined()) {
if (ICS1.UserDefined.ConversionFunction ==
ICS2.UserDefined.ConversionFunction)
Result = CompareStandardConversionSequences(S, Loc,
ICS1.UserDefined.After,
ICS2.UserDefined.After);
else
Result = compareConversionFunctions(S,
ICS1.UserDefined.ConversionFunction,
ICS2.UserDefined.ConversionFunction);
}
return Result;
}
static ImplicitConversionSequence::CompareKind
compareStandardConversionSubsets(ASTContext &Context,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion())
return ImplicitConversionSequence::Better;
else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion())
return ImplicitConversionSequence::Worse;
if (SCS1.Second != SCS2.Second) {
if (SCS1.Second == ICK_Identity)
Result = ImplicitConversionSequence::Better;
else if (SCS2.Second == ICK_Identity)
Result = ImplicitConversionSequence::Worse;
else
return ImplicitConversionSequence::Indistinguishable;
} else if (!Context.hasSimilarType(SCS1.getToType(1), SCS2.getToType(1)))
return ImplicitConversionSequence::Indistinguishable;
if (SCS1.Third == SCS2.Third) {
return Context.hasSameType(SCS1.getToType(2), SCS2.getToType(2))? Result
: ImplicitConversionSequence::Indistinguishable;
}
if (SCS1.Third == ICK_Identity)
return Result == ImplicitConversionSequence::Worse
? ImplicitConversionSequence::Indistinguishable
: ImplicitConversionSequence::Better;
if (SCS2.Third == ICK_Identity)
return Result == ImplicitConversionSequence::Better
? ImplicitConversionSequence::Indistinguishable
: ImplicitConversionSequence::Worse;
return ImplicitConversionSequence::Indistinguishable;
}
static bool
isBetterReferenceBindingKind(const StandardConversionSequence &SCS1,
const StandardConversionSequence &SCS2) {
if (SCS1.BindsImplicitObjectArgumentWithoutRefQualifier ||
SCS2.BindsImplicitObjectArgumentWithoutRefQualifier)
return false;
return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue &&
SCS2.IsLvalueReference) ||
(SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue &&
!SCS2.IsLvalueReference && SCS2.BindsToFunctionLvalue);
}
enum class FixedEnumPromotion {
None,
ToUnderlyingType,
ToPromotedUnderlyingType
};
static FixedEnumPromotion
getFixedEnumPromtion(Sema &S, const StandardConversionSequence &SCS) {
if (SCS.Second != ICK_Integral_Promotion)
return FixedEnumPromotion::None;
QualType FromType = SCS.getFromType();
if (!FromType->isEnumeralType())
return FixedEnumPromotion::None;
EnumDecl *Enum = FromType->castAs<EnumType>()->getDecl();
if (!Enum->isFixed())
return FixedEnumPromotion::None;
QualType UnderlyingType = Enum->getIntegerType();
if (S.Context.hasSameType(SCS.getToType(1), UnderlyingType))
return FixedEnumPromotion::ToUnderlyingType;
return FixedEnumPromotion::ToPromotedUnderlyingType;
}
static ImplicitConversionSequence::CompareKind
CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2)
{
if (ImplicitConversionSequence::CompareKind CK
= compareStandardConversionSubsets(S.Context, SCS1, SCS2))
return CK;
ImplicitConversionRank Rank1 = SCS1.getRank();
ImplicitConversionRank Rank2 = SCS2.getRank();
if (Rank1 < Rank2)
return ImplicitConversionSequence::Better;
else if (Rank2 < Rank1)
return ImplicitConversionSequence::Worse;
if (SCS1.isPointerConversionToBool() != SCS2.isPointerConversionToBool())
return SCS2.isPointerConversionToBool()
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
FixedEnumPromotion FEP1 = getFixedEnumPromtion(S, SCS1);
FixedEnumPromotion FEP2 = getFixedEnumPromtion(S, SCS2);
if (FEP1 != FixedEnumPromotion::None && FEP2 != FixedEnumPromotion::None &&
FEP1 != FEP2)
return FEP1 == FixedEnumPromotion::ToUnderlyingType
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
bool SCS1ConvertsToVoid
= SCS1.isPointerConversionToVoidPointer(S.Context);
bool SCS2ConvertsToVoid
= SCS2.isPointerConversionToVoidPointer(S.Context);
if (SCS1ConvertsToVoid != SCS2ConvertsToVoid) {
return SCS2ConvertsToVoid ? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
} else if (!SCS1ConvertsToVoid && !SCS2ConvertsToVoid) {
if (ImplicitConversionSequence::CompareKind DerivedCK
= CompareDerivedToBaseConversions(S, Loc, SCS1, SCS2))
return DerivedCK;
} else if (SCS1ConvertsToVoid && SCS2ConvertsToVoid &&
!S.Context.hasSameType(SCS1.getFromType(), SCS2.getFromType())) {
QualType FromType1 = SCS1.getFromType();
QualType FromType2 = SCS2.getFromType();
if (SCS1.First == ICK_Array_To_Pointer)
FromType1 = S.Context.getArrayDecayedType(FromType1);
if (SCS2.First == ICK_Array_To_Pointer)
FromType2 = S.Context.getArrayDecayedType(FromType2);
QualType FromPointee1 = FromType1->getPointeeType().getUnqualifiedType();
QualType FromPointee2 = FromType2->getPointeeType().getUnqualifiedType();
if (S.IsDerivedFrom(Loc, FromPointee2, FromPointee1))
return ImplicitConversionSequence::Better;
else if (S.IsDerivedFrom(Loc, FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
const ObjCObjectPointerType* FromObjCPtr1
= FromType1->getAs<ObjCObjectPointerType>();
const ObjCObjectPointerType* FromObjCPtr2
= FromType2->getAs<ObjCObjectPointerType>();
if (FromObjCPtr1 && FromObjCPtr2) {
bool AssignLeft = S.Context.canAssignObjCInterfaces(FromObjCPtr1,
FromObjCPtr2);
bool AssignRight = S.Context.canAssignObjCInterfaces(FromObjCPtr2,
FromObjCPtr1);
if (AssignLeft != AssignRight) {
return AssignLeft? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
}
}
}
if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
if (isBetterReferenceBindingKind(SCS1, SCS2))
return ImplicitConversionSequence::Better;
else if (isBetterReferenceBindingKind(SCS2, SCS1))
return ImplicitConversionSequence::Worse;
}
if (ImplicitConversionSequence::CompareKind QualCK
= CompareQualificationConversions(S, SCS1, SCS2))
return QualCK;
if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
QualType T1 = SCS1.getToType(2);
QualType T2 = SCS2.getToType(2);
T1 = S.Context.getCanonicalType(T1);
T2 = S.Context.getCanonicalType(T2);
Qualifiers T1Quals, T2Quals;
QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
if (UnqualT1 == UnqualT2) {
if (SCS1.ObjCLifetimeConversionBinding !=
SCS2.ObjCLifetimeConversionBinding) {
return SCS1.ObjCLifetimeConversionBinding
? ImplicitConversionSequence::Worse
: ImplicitConversionSequence::Better;
}
if (isa<ArrayType>(T1) && T1Quals)
T1 = S.Context.getQualifiedType(UnqualT1, T1Quals);
if (isa<ArrayType>(T2) && T2Quals)
T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
if (T2.isMoreQualifiedThan(T1))
return ImplicitConversionSequence::Better;
if (T1.isMoreQualifiedThan(T2))
return ImplicitConversionSequence::Worse;
}
}
if (S.getLangOpts().MSVCCompat &&
!S.getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2019_8) &&
SCS1.Second == ICK_Integral_Conversion &&
SCS2.Second == ICK_Floating_Integral &&
S.Context.getTypeSize(SCS1.getFromType()) ==
S.Context.getTypeSize(SCS1.getToType(2)))
return ImplicitConversionSequence::Better;
if (SCS1.Second == ICK_Vector_Conversion &&
SCS2.Second == ICK_Vector_Conversion) {
bool SCS1IsCompatibleVectorConversion = S.Context.areCompatibleVectorTypes(
SCS1.getFromType(), SCS1.getToType(2));
bool SCS2IsCompatibleVectorConversion = S.Context.areCompatibleVectorTypes(
SCS2.getFromType(), SCS2.getToType(2));
if (SCS1IsCompatibleVectorConversion != SCS2IsCompatibleVectorConversion)
return SCS1IsCompatibleVectorConversion
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
}
if (SCS1.Second == ICK_SVE_Vector_Conversion &&
SCS2.Second == ICK_SVE_Vector_Conversion) {
bool SCS1IsCompatibleSVEVectorConversion =
S.Context.areCompatibleSveTypes(SCS1.getFromType(), SCS1.getToType(2));
bool SCS2IsCompatibleSVEVectorConversion =
S.Context.areCompatibleSveTypes(SCS2.getFromType(), SCS2.getToType(2));
if (SCS1IsCompatibleSVEVectorConversion !=
SCS2IsCompatibleSVEVectorConversion)
return SCS1IsCompatibleSVEVectorConversion
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
}
if (SCS1.Second == ICK_RVV_Vector_Conversion &&
SCS2.Second == ICK_RVV_Vector_Conversion) {
bool SCS1IsCompatibleRVVVectorConversion =
S.Context.areCompatibleRVVTypes(SCS1.getFromType(), SCS1.getToType(2));
bool SCS2IsCompatibleRVVVectorConversion =
S.Context.areCompatibleRVVTypes(SCS2.getFromType(), SCS2.getToType(2));
if (SCS1IsCompatibleRVVVectorConversion !=
SCS2IsCompatibleRVVVectorConversion)
return SCS1IsCompatibleRVVVectorConversion
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
}
return ImplicitConversionSequence::Indistinguishable;
}
static ImplicitConversionSequence::CompareKind
CompareQualificationConversions(Sema &S,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
if (SCS1.First != SCS2.First || SCS1.Second != SCS2.Second ||
SCS1.Third != SCS2.Third || SCS1.Third != ICK_Qualification)
return ImplicitConversionSequence::Indistinguishable;
QualType T1 = SCS1.getToType(2);
QualType T2 = SCS2.getToType(2);
T1 = S.Context.getCanonicalType(T1);
T2 = S.Context.getCanonicalType(T2);
assert(!T1->isReferenceType() && !T2->isReferenceType());
Qualifiers T1Quals, T2Quals;
QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
if (UnqualT1 == UnqualT2)
return ImplicitConversionSequence::Indistinguishable;
bool CanPick1 = !SCS1.DeprecatedStringLiteralToCharPtr;
bool CanPick2 = !SCS2.DeprecatedStringLiteralToCharPtr;
if (SCS1.QualificationIncludesObjCLifetime &&
!SCS2.QualificationIncludesObjCLifetime)
CanPick1 = false;
if (SCS2.QualificationIncludesObjCLifetime &&
!SCS1.QualificationIncludesObjCLifetime)
CanPick2 = false;
bool ObjCLifetimeConversion;
if (CanPick1 &&
!S.IsQualificationConversion(T1, T2, false, ObjCLifetimeConversion))
CanPick1 = false;
if (CanPick2 &&
!S.IsQualificationConversion(T2, T1, false, ObjCLifetimeConversion))
CanPick2 = false;
if (CanPick1 != CanPick2)
return CanPick1 ? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
return ImplicitConversionSequence::Indistinguishable;
}
static ImplicitConversionSequence::CompareKind
CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
QualType FromType1 = SCS1.getFromType();
QualType ToType1 = SCS1.getToType(1);
QualType FromType2 = SCS2.getFromType();
QualType ToType2 = SCS2.getToType(1);
if (SCS1.First == ICK_Array_To_Pointer)
FromType1 = S.Context.getArrayDecayedType(FromType1);
if (SCS2.First == ICK_Array_To_Pointer)
FromType2 = S.Context.getArrayDecayedType(FromType2);
FromType1 = S.Context.getCanonicalType(FromType1);
ToType1 = S.Context.getCanonicalType(ToType1);
FromType2 = S.Context.getCanonicalType(FromType2);
ToType2 = S.Context.getCanonicalType(ToType2);
if (SCS1.Second == ICK_Pointer_Conversion &&
SCS2.Second == ICK_Pointer_Conversion &&
FromType1->isPointerType() && FromType2->isPointerType() &&
ToType1->isPointerType() && ToType2->isPointerType()) {
QualType FromPointee1 =
FromType1->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
QualType ToPointee1 =
ToType1->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
QualType FromPointee2 =
FromType2->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
QualType ToPointee2 =
ToType2->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
if (S.IsDerivedFrom(Loc, ToPointee1, ToPointee2))
return ImplicitConversionSequence::Better;
else if (S.IsDerivedFrom(Loc, ToPointee2, ToPointee1))
return ImplicitConversionSequence::Worse;
}
if (FromPointee1 != FromPointee2 && ToPointee1 == ToPointee2) {
if (S.IsDerivedFrom(Loc, FromPointee2, FromPointee1))
return ImplicitConversionSequence::Better;
else if (S.IsDerivedFrom(Loc, FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
}
} else if (SCS1.Second == ICK_Pointer_Conversion &&
SCS2.Second == ICK_Pointer_Conversion) {
const ObjCObjectPointerType *FromPtr1
= FromType1->getAs<ObjCObjectPointerType>();
const ObjCObjectPointerType *FromPtr2
= FromType2->getAs<ObjCObjectPointerType>();
const ObjCObjectPointerType *ToPtr1
= ToType1->getAs<ObjCObjectPointerType>();
const ObjCObjectPointerType *ToPtr2
= ToType2->getAs<ObjCObjectPointerType>();
if (FromPtr1 && FromPtr2 && ToPtr1 && ToPtr2) {
bool FromAssignLeft
= S.Context.canAssignObjCInterfaces(FromPtr1, FromPtr2);
bool FromAssignRight
= S.Context.canAssignObjCInterfaces(FromPtr2, FromPtr1);
bool ToAssignLeft
= S.Context.canAssignObjCInterfaces(ToPtr1, ToPtr2);
bool ToAssignRight
= S.Context.canAssignObjCInterfaces(ToPtr2, ToPtr1);
if (ToPtr1->isObjCIdType() &&
(ToPtr2->isObjCQualifiedIdType() || ToPtr2->getInterfaceDecl()))
return ImplicitConversionSequence::Worse;
if (ToPtr2->isObjCIdType() &&
(ToPtr1->isObjCQualifiedIdType() || ToPtr1->getInterfaceDecl()))
return ImplicitConversionSequence::Better;
if (ToPtr1->isObjCQualifiedIdType() && ToPtr2->getInterfaceDecl())
return ImplicitConversionSequence::Worse;
if (ToPtr2->isObjCQualifiedIdType() && ToPtr1->getInterfaceDecl())
return ImplicitConversionSequence::Better;
if (ToPtr1->isObjCClassType() &&
(ToPtr2->isObjCQualifiedClassType() || ToPtr2->getInterfaceDecl()))
return ImplicitConversionSequence::Worse;
if (ToPtr2->isObjCClassType() &&
(ToPtr1->isObjCQualifiedClassType() || ToPtr1->getInterfaceDecl()))
return ImplicitConversionSequence::Better;
if (ToPtr1->isObjCQualifiedClassType() && ToPtr2->getInterfaceDecl())
return ImplicitConversionSequence::Worse;
if (ToPtr2->isObjCQualifiedClassType() && ToPtr1->getInterfaceDecl())
return ImplicitConversionSequence::Better;
if (S.Context.hasSameType(FromType1, FromType2) &&
!FromPtr1->isObjCIdType() && !FromPtr1->isObjCClassType() &&
(ToAssignLeft != ToAssignRight)) {
if (FromPtr1->isSpecialized()) {
bool IsFirstSame =
FromPtr1->getInterfaceDecl() == ToPtr1->getInterfaceDecl();
bool IsSecondSame =
FromPtr1->getInterfaceDecl() == ToPtr2->getInterfaceDecl();
if (IsFirstSame) {
if (!IsSecondSame)
return ImplicitConversionSequence::Better;
} else if (IsSecondSame)
return ImplicitConversionSequence::Worse;
}
return ToAssignLeft? ImplicitConversionSequence::Worse
: ImplicitConversionSequence::Better;
}
if (S.Context.hasSameUnqualifiedType(ToType1, ToType2) &&
(FromAssignLeft != FromAssignRight))
return FromAssignLeft? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
}
}
if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member &&
FromType1->isMemberPointerType() && FromType2->isMemberPointerType() &&
ToType1->isMemberPointerType() && ToType2->isMemberPointerType()) {
const auto *FromMemPointer1 = FromType1->castAs<MemberPointerType>();
const auto *ToMemPointer1 = ToType1->castAs<MemberPointerType>();
const auto *FromMemPointer2 = FromType2->castAs<MemberPointerType>();
const auto *ToMemPointer2 = ToType2->castAs<MemberPointerType>();
const Type *FromPointeeType1 = FromMemPointer1->getClass();
const Type *ToPointeeType1 = ToMemPointer1->getClass();
const Type *FromPointeeType2 = FromMemPointer2->getClass();
const Type *ToPointeeType2 = ToMemPointer2->getClass();
QualType FromPointee1 = QualType(FromPointeeType1, 0).getUnqualifiedType();
QualType ToPointee1 = QualType(ToPointeeType1, 0).getUnqualifiedType();
QualType FromPointee2 = QualType(FromPointeeType2, 0).getUnqualifiedType();
QualType ToPointee2 = QualType(ToPointeeType2, 0).getUnqualifiedType();
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
if (S.IsDerivedFrom(Loc, ToPointee1, ToPointee2))
return ImplicitConversionSequence::Worse;
else if (S.IsDerivedFrom(Loc, ToPointee2, ToPointee1))
return ImplicitConversionSequence::Better;
}
if (ToPointee1 == ToPointee2 && FromPointee1 != FromPointee2) {
if (S.IsDerivedFrom(Loc, FromPointee1, FromPointee2))
return ImplicitConversionSequence::Better;
else if (S.IsDerivedFrom(Loc, FromPointee2, FromPointee1))
return ImplicitConversionSequence::Worse;
}
}
if (SCS1.Second == ICK_Derived_To_Base) {
if (S.Context.hasSameUnqualifiedType(FromType1, FromType2) &&
!S.Context.hasSameUnqualifiedType(ToType1, ToType2)) {
if (S.IsDerivedFrom(Loc, ToType1, ToType2))
return ImplicitConversionSequence::Better;
else if (S.IsDerivedFrom(Loc, ToType2, ToType1))
return ImplicitConversionSequence::Worse;
}
if (!S.Context.hasSameUnqualifiedType(FromType1, FromType2) &&
S.Context.hasSameUnqualifiedType(ToType1, ToType2)) {
if (S.IsDerivedFrom(Loc, FromType2, FromType1))
return ImplicitConversionSequence::Better;
else if (S.IsDerivedFrom(Loc, FromType1, FromType2))
return ImplicitConversionSequence::Worse;
}
}
return ImplicitConversionSequence::Indistinguishable;
}
static QualType withoutUnaligned(ASTContext &Ctx, QualType T) {
if (!T.getQualifiers().hasUnaligned())
return T;
Qualifiers Q;
T = Ctx.getUnqualifiedArrayType(T, Q);
Q.removeUnaligned();
return Ctx.getQualifiedType(T, Q);
}
Sema::ReferenceCompareResult
Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType OrigT1, QualType OrigT2,
ReferenceConversions *ConvOut) {
assert(!OrigT1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
QualType T1 = Context.getCanonicalType(OrigT1);
QualType T2 = Context.getCanonicalType(OrigT2);
Qualifiers T1Quals, T2Quals;
QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
ReferenceConversions ConvTmp;
ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp;
Conv = ReferenceConversions();
QualType ConvertedT2;
if (UnqualT1 == UnqualT2) {
} else if (isCompleteType(Loc, OrigT2) &&
IsDerivedFrom(Loc, UnqualT2, UnqualT1))
Conv |= ReferenceConversions::DerivedToBase;
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
UnqualT2->isObjCObjectOrInterfaceType() &&
Context.canBindObjCObjectType(UnqualT1, UnqualT2))
Conv |= ReferenceConversions::ObjC;
else if (UnqualT2->isFunctionType() &&
IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
Conv |= ReferenceConversions::Function;
return Ref_Compatible;
}
bool ConvertedReferent = Conv != 0;
bool PreviousToQualsIncludeConst = true;
bool TopLevel = true;
do {
if (T1 == T2)
break;
Conv |= ReferenceConversions::Qualification;
if (!TopLevel)
Conv |= ReferenceConversions::NestedQualification;
T1 = withoutUnaligned(Context, T1);
T2 = withoutUnaligned(Context, T2);
bool ObjCLifetimeConversion = false;
if (!isQualificationConversionStep(T2, T1, false, TopLevel,
PreviousToQualsIncludeConst,
ObjCLifetimeConversion))
return (ConvertedReferent || Context.hasSimilarType(T1, T2))
? Ref_Related
: Ref_Incompatible;
if (ObjCLifetimeConversion)
Conv |= ReferenceConversions::ObjCLifetime;
TopLevel = false;
} while (Context.UnwrapSimilarTypes(T1, T2));
return (ConvertedReferent || Context.hasSameUnqualifiedType(T1, T2))
? Ref_Compatible
: Ref_Incompatible;
}
static bool
FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
QualType DeclType, SourceLocation DeclLoc,
Expr *Init, QualType T2, bool AllowRvalues,
bool AllowExplicit) {
assert(T2->isRecordType() && "Can only find conversions of record types.");
auto *T2RecordDecl = cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet(
DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
FunctionTemplateDecl *ConvTemplate
= dyn_cast<FunctionTemplateDecl>(D);
CXXConversionDecl *Conv;
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
Conv = cast<CXXConversionDecl>(D);
if (AllowRvalues) {
if (!ConvTemplate && DeclType->isRValueReferenceType()) {
const ReferenceType *RefType
= Conv->getConversionType()->getAs<LValueReferenceType>();
if (RefType && !RefType->getPointeeType()->isFunctionType())
continue;
}
if (!ConvTemplate &&
S.CompareReferenceRelationship(
DeclLoc,
Conv->getConversionType()
.getNonReferenceType()
.getUnqualifiedType(),
DeclType.getNonReferenceType().getUnqualifiedType()) ==
Sema::Ref_Incompatible)
continue;
} else {
const ReferenceType *RefType =
Conv->getConversionType()->getAs<ReferenceType>();
if (!RefType ||
(!RefType->isLValueReferenceType() &&
!RefType->getPointeeType()->isFunctionType()))
continue;
}
if (ConvTemplate)
S.AddTemplateConversionCandidate(
ConvTemplate, I.getPair(), ActingDC, Init, DeclType, CandidateSet,
false, AllowExplicit);
else
S.AddConversionCandidate(
Conv, I.getPair(), ActingDC, Init, DeclType, CandidateSet,
false, AllowExplicit);
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
case OR_Success:
if (!Best->FinalConversion.DirectBinding)
return false;
ICS.setUserDefined();
ICS.UserDefined.Before = Best->Conversions[0].Standard;
ICS.UserDefined.After = Best->FinalConversion;
ICS.UserDefined.HadMultipleCandidates = HadMultipleCandidates;
ICS.UserDefined.ConversionFunction = Best->Function;
ICS.UserDefined.FoundConversionFunction = Best->FoundDecl;
ICS.UserDefined.EllipsisConversion = false;
assert(ICS.UserDefined.After.ReferenceBinding &&
ICS.UserDefined.After.DirectBinding &&
"Expected a direct reference binding!");
return true;
case OR_Ambiguous:
ICS.setAmbiguous();
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
Cand != CandidateSet.end(); ++Cand)
if (Cand->Best)
ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function);
return true;
case OR_No_Viable_Function:
case OR_Deleted:
return false;
}
llvm_unreachable("Invalid OverloadResult!");
}
static ImplicitConversionSequence
TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
SourceLocation DeclLoc,
bool SuppressUserConversions,
bool AllowExplicit) {
assert(DeclType->isReferenceType() && "Reference init needs a reference");
ImplicitConversionSequence ICS;
ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType);
QualType T1 = DeclType->castAs<ReferenceType>()->getPointeeType();
QualType T2 = Init->getType();
if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
DeclAccessPair Found;
if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Init, DeclType,
false, Found))
T2 = Fn->getType();
}
bool isRValRef = DeclType->isRValueReferenceType();
Expr::Classification InitCategory = Init->Classify(S.Context);
Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult RefRelationship =
S.CompareReferenceRelationship(DeclLoc, T1, T2, &RefConv);
auto SetAsReferenceBinding = [&](bool BindsDirectly) {
ICS.setStandard();
ICS.Standard.First = ICK_Identity;
ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase)
? ICK_Derived_To_Base
: (RefConv & Sema::ReferenceConversions::ObjC)
? ICK_Compatible_Conversion
: ICK_Identity;
ICS.Standard.Dimension = ICK_Identity;
ICS.Standard.Third = (RefConv &
Sema::ReferenceConversions::NestedQualification)
? ICK_Qualification
: ICK_Identity;
ICS.Standard.setFromType(T2);
ICS.Standard.setToType(0, T2);
ICS.Standard.setToType(1, T1);
ICS.Standard.setToType(2, T1);
ICS.Standard.ReferenceBinding = true;
ICS.Standard.DirectBinding = BindsDirectly;
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = InitCategory.isRValue();
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding =
(RefConv & Sema::ReferenceConversions::ObjCLifetime) != 0;
ICS.Standard.CopyConstructor = nullptr;
ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
};
if (!isRValRef) {
if (InitCategory.isLValue() && RefRelationship == Sema::Ref_Compatible) {
SetAsReferenceBinding(true);
return ICS;
}
if (!SuppressUserConversions && T2->isRecordType() &&
S.isCompleteType(DeclLoc, T2) &&
RefRelationship == Sema::Ref_Incompatible) {
if (FindConversionForRefInit(S, ICS, DeclType, DeclLoc,
Init, T2, false,
AllowExplicit))
return ICS;
}
}
if (!isRValRef && (!T1.isConstQualified() || T1.isVolatileQualified())) {
if (InitCategory.isRValue() && RefRelationship != Sema::Ref_Incompatible)
ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, DeclType);
return ICS;
}
if (RefRelationship == Sema::Ref_Compatible &&
(InitCategory.isXValue() ||
(InitCategory.isPRValue() &&
(T2->isRecordType() || T2->isArrayType())) ||
(InitCategory.isLValue() && T2->isFunctionType()))) {
SetAsReferenceBinding(S.getLangOpts().CPlusPlus11 ||
!(InitCategory.isPRValue() || T2->isRecordType()));
return ICS;
}
if (!SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible &&
T2->isRecordType() && S.isCompleteType(DeclLoc, T2) &&
FindConversionForRefInit(S, ICS, DeclType, DeclLoc,
Init, T2, true,
AllowExplicit)) {
if (ICS.isUserDefined() && isRValRef &&
ICS.UserDefined.After.First == ICK_Lvalue_To_Rvalue)
ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType);
return ICS;
}
if (T1->isFunctionType())
return ICS;
if (RefRelationship == Sema::Ref_Related) {
Qualifiers T1Quals = T1.getQualifiers();
Qualifiers T2Quals = T2.getQualifiers();
T1Quals.removeObjCGCAttr();
T1Quals.removeObjCLifetime();
T2Quals.removeObjCGCAttr();
T2Quals.removeObjCLifetime();
T1Quals.removeUnaligned();
T2Quals.removeUnaligned();
if (!T1Quals.compatiblyIncludes(T2Quals))
return ICS;
}
if (SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible &&
(T1->isRecordType() || T2->isRecordType()))
return ICS;
if (RefRelationship >= Sema::Ref_Related && isRValRef &&
Init->Classify(S.Context).isLValue()) {
ICS.setBad(BadConversionSequence::rvalue_ref_to_lvalue, Init, DeclType);
return ICS;
}
ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions,
AllowedExplicit::None,
false,
false,
false,
false);
if (ICS.isStandard()) {
ICS.Standard.ReferenceBinding = true;
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = false;
ICS.Standard.BindsToRvalue = true;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = false;
} else if (ICS.isUserDefined()) {
const ReferenceType *LValRefType =
ICS.UserDefined.ConversionFunction->getReturnType()
->getAs<LValueReferenceType>();
if (isRValRef && LValRefType) {
ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType);
return ICS;
}
ICS.UserDefined.After.ReferenceBinding = true;
ICS.UserDefined.After.IsLvalueReference = !isRValRef;
ICS.UserDefined.After.BindsToFunctionLvalue = false;
ICS.UserDefined.After.BindsToRvalue = !LValRefType;
ICS.UserDefined.After.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.UserDefined.After.ObjCLifetimeConversionBinding = false;
}
return ICS;
}
static ImplicitConversionSequence
TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
bool InOverloadResolution,
bool AllowObjCWritebackConversion,
bool AllowExplicit = false);
static ImplicitConversionSequence
TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
bool SuppressUserConversions,
bool InOverloadResolution,
bool AllowObjCWritebackConversion) {
ImplicitConversionSequence Result;
Result.setBad(BadConversionSequence::no_conversion, From, ToType);
QualType InitTy = ToType;
const ArrayType *AT = S.Context.getAsArrayType(ToType);
if (AT && S.getLangOpts().CPlusPlus20)
if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT))
InitTy = IAT->getElementType();
if (!S.isCompleteType(From->getBeginLoc(), InitTy))
return Result;
bool IsDesignatedInit = From->hasDesignatedInit();
if (!ToType->isAggregateType() && !ToType->isReferenceType() &&
IsDesignatedInit)
return Result;
if (From->getNumInits() == 1 && !IsDesignatedInit) {
if (ToType->isRecordType()) {
QualType InitType = From->getInit(0)->getType();
if (S.Context.hasSameUnqualifiedType(InitType, ToType) ||
S.IsDerivedFrom(From->getBeginLoc(), InitType, ToType))
return TryCopyInitialization(S, From->getInit(0), ToType,
SuppressUserConversions,
InOverloadResolution,
AllowObjCWritebackConversion);
}
if (AT && S.IsStringInit(From->getInit(0), AT)) {
InitializedEntity Entity =
InitializedEntity::InitializeParameter(S.Context, ToType,
false);
if (S.CanPerformCopyInitialization(Entity, From)) {
Result.setStandard();
Result.Standard.setAsIdentityConversion();
Result.Standard.setFromType(ToType);
Result.Standard.setAllToTypes(ToType);
return Result;
}
}
}
if ((AT || S.isStdInitializerList(ToType, &InitTy)) && !IsDesignatedInit) {
unsigned e = From->getNumInits();
ImplicitConversionSequence DfltElt;
DfltElt.setBad(BadConversionSequence::no_conversion, QualType(),
QualType());
QualType ContTy = ToType;
bool IsUnbounded = false;
if (AT) {
InitTy = AT->getElementType();
if (ConstantArrayType const *CT = dyn_cast<ConstantArrayType>(AT)) {
if (CT->getSize().ult(e)) {
Result.setBad(BadConversionSequence::too_many_initializers, From,
ToType);
Result.setInitializerListContainerType(ContTy, IsUnbounded);
return Result;
}
if (CT->getSize().ugt(e)) {
InitListExpr EmptyList(S.Context, From->getEndLoc(), std::nullopt,
From->getEndLoc());
EmptyList.setType(S.Context.VoidTy);
DfltElt = TryListConversion(
S, &EmptyList, InitTy, SuppressUserConversions,
InOverloadResolution, AllowObjCWritebackConversion);
if (DfltElt.isBad()) {
Result.setBad(BadConversionSequence::too_few_initializers, From,
ToType);
Result.setInitializerListContainerType(ContTy, IsUnbounded);
return Result;
}
}
} else {
assert(isa<IncompleteArrayType>(AT) && "Expected incomplete array");
IsUnbounded = true;
if (!e) {
Result.setBad(BadConversionSequence::too_few_initializers, From,
ToType);
Result.setInitializerListContainerType(ContTy, IsUnbounded);
return Result;
}
llvm::APInt Size(S.Context.getTypeSize(S.Context.getSizeType()), e);
ContTy = S.Context.getConstantArrayType(InitTy, Size, nullptr,
ArraySizeModifier::Normal, 0);
}
}
Result.setStandard();
Result.Standard.setAsIdentityConversion();
Result.Standard.setFromType(InitTy);
Result.Standard.setAllToTypes(InitTy);
for (unsigned i = 0; i < e; ++i) {
Expr *Init = From->getInit(i);
ImplicitConversionSequence ICS = TryCopyInitialization(
S, Init, InitTy, SuppressUserConversions, InOverloadResolution,
AllowObjCWritebackConversion);
if (CompareImplicitConversionSequences(S, From->getBeginLoc(), ICS,
Result) ==
ImplicitConversionSequence::Worse) {
Result = ICS;
if (Result.isBad()) {
Result.setInitializerListContainerType(ContTy, IsUnbounded);
return Result;
}
}
}
if (!DfltElt.isBad() && CompareImplicitConversionSequences(
S, From->getEndLoc(), DfltElt, Result) ==
ImplicitConversionSequence::Worse)
Result = DfltElt;
Result.setInitializerListContainerType(ContTy, IsUnbounded);
return Result;
}
if (ToType->isRecordType() && !ToType->isAggregateType()) {
return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
AllowedExplicit::None,
InOverloadResolution, false,
AllowObjCWritebackConversion,
false);
}
if (ToType->isAggregateType()) {
InitializedEntity Entity =
InitializedEntity::InitializeParameter(S.Context, ToType,
false);
if (S.CanPerformAggregateInitializationForOverloadResolution(Entity,
From)) {
Result.setUserDefined();
Result.UserDefined.Before.setAsIdentityConversion();
Result.UserDefined.Before.setFromType(QualType());
Result.UserDefined.Before.setAllToTypes(QualType());
Result.UserDefined.After.setAsIdentityConversion();
Result.UserDefined.After.setFromType(ToType);
Result.UserDefined.After.setAllToTypes(ToType);
Result.UserDefined.ConversionFunction = nullptr;
}
return Result;
}
if (ToType->isReferenceType()) {
QualType T1 = ToType->castAs<ReferenceType>()->getPointeeType();
if (From->getNumInits() == 1 && !IsDesignatedInit) {
Expr *Init = From->getInit(0);
QualType T2 = Init->getType();
if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
DeclAccessPair Found;
if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(
Init, ToType, false, Found))
T2 = Fn->getType();
}
Sema::ReferenceCompareResult RefRelationship =
S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2);
if (RefRelationship >= Sema::Ref_Related) {
return TryReferenceInit(S, Init, ToType, From->getBeginLoc(),
SuppressUserConversions,
false);
}
}
Result = TryListConversion(S, From, T1, SuppressUserConversions,
InOverloadResolution,
AllowObjCWritebackConversion);
if (Result.isFailure())
return Result;
assert(!Result.isEllipsis() &&
"Sub-initialization cannot result in ellipsis conversion.");
if (ToType->isRValueReferenceType() ||
(T1.isConstQualified() && !T1.isVolatileQualified())) {
StandardConversionSequence &SCS = Result.isStandard() ? Result.Standard :
Result.UserDefined.After;
SCS.ReferenceBinding = true;
SCS.IsLvalueReference = ToType->isLValueReferenceType();
SCS.BindsToRvalue = true;
SCS.BindsToFunctionLvalue = false;
SCS.BindsImplicitObjectArgumentWithoutRefQualifier = false;
SCS.ObjCLifetimeConversionBinding = false;
} else
Result.setBad(BadConversionSequence::lvalue_ref_to_rvalue,
From, ToType);
return Result;
}
if (!ToType->isRecordType()) {
unsigned NumInits = From->getNumInits();
if (NumInits == 1 && !isa<InitListExpr>(From->getInit(0)))
Result = TryCopyInitialization(S, From->getInit(0), ToType,
SuppressUserConversions,
InOverloadResolution,
AllowObjCWritebackConversion);
else if (NumInits == 0) {
Result.setStandard();
Result.Standard.setAsIdentityConversion();
Result.Standard.setFromType(ToType);
Result.Standard.setAllToTypes(ToType);
}
return Result;
}
return Result;
}
static ImplicitConversionSequence
TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
bool InOverloadResolution,
bool AllowObjCWritebackConversion,
bool AllowExplicit) {
if (InitListExpr *FromInitList = dyn_cast<InitListExpr>(From))
return TryListConversion(S, FromInitList, ToType, SuppressUserConversions,
InOverloadResolution,AllowObjCWritebackConversion);
if (ToType->isReferenceType())
return TryReferenceInit(S, From, ToType,
From->getBeginLoc(),
SuppressUserConversions, AllowExplicit);
return TryImplicitConversion(S, From, ToType,
SuppressUserConversions,
AllowedExplicit::None,
InOverloadResolution,
false,
AllowObjCWritebackConversion,
false);
}
static bool TryCopyInitialization(const CanQualType FromQTy,
const CanQualType ToQTy,
Sema &S,
SourceLocation Loc,
ExprValueKind FromVK) {
OpaqueValueExpr TmpExpr(Loc, FromQTy, FromVK);
ImplicitConversionSequence ICS =
TryCopyInitialization(S, &TmpExpr, ToQTy, true, true, false);
return !ICS.isBad();
}
static ImplicitConversionSequence TryObjectArgumentInitialization(
Sema &S, SourceLocation Loc, QualType FromType,
Expr::Classification FromClassification, CXXMethodDecl *Method,
const CXXRecordDecl *ActingContext, bool InOverloadResolution = false,
QualType ExplicitParameterType = QualType(),
bool SuppressUserConversion = false) {
if (const auto *PT = FromType->getAs<PointerType>()) {
FromType = PT->getPointeeType();
assert(FromClassification.isLValue());
}
auto ValueKindFromClassification = [](Expr::Classification C) {
if (C.isPRValue())
return clang::VK_PRValue;
if (C.isXValue())
return VK_XValue;
return clang::VK_LValue;
};
if (Method->isExplicitObjectMemberFunction()) {
if (ExplicitParameterType.isNull())
ExplicitParameterType = Method->getFunctionObjectParameterReferenceType();
OpaqueValueExpr TmpExpr(Loc, FromType.getNonReferenceType(),
ValueKindFromClassification(FromClassification));
ImplicitConversionSequence ICS = TryCopyInitialization(
S, &TmpExpr, ExplicitParameterType, SuppressUserConversion,
true, false);
if (ICS.isBad())
ICS.Bad.FromExpr = nullptr;
return ICS;
}
assert(FromType->isRecordType());
QualType ClassType = S.Context.getTypeDeclType(ActingContext);
Qualifiers Quals = Method->getMethodQualifiers();
if (isa<CXXDestructorDecl>(Method) || Method->isStatic()) {
Quals.addConst();
Quals.addVolatile();
}
QualType ImplicitParamType = S.Context.getQualifiedType(ClassType, Quals);
ImplicitConversionSequence ICS;
QualType FromTypeCanon = S.Context.getCanonicalType(FromType);
if (ImplicitParamType.getCVRQualifiers() !=
FromTypeCanon.getLocalCVRQualifiers() &&
!ImplicitParamType.isAtLeastAsQualifiedAs(
withoutUnaligned(S.Context, FromTypeCanon))) {
ICS.setBad(BadConversionSequence::bad_qualifiers,
FromType, ImplicitParamType);
return ICS;
}
if (FromTypeCanon.hasAddressSpace()) {
Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers();
Qualifiers QualsFromType = FromTypeCanon.getQualifiers();
if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) {
ICS.setBad(BadConversionSequence::bad_qualifiers,
FromType, ImplicitParamType);
return ICS;
}
}
QualType ClassTypeCanon = S.Context.getCanonicalType(ClassType);
ImplicitConversionKind SecondKind;
if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) {
SecondKind = ICK_Identity;
} else if (S.IsDerivedFrom(Loc, FromType, ClassType)) {
SecondKind = ICK_Derived_To_Base;
} else if (!Method->isExplicitObjectMemberFunction()) {
ICS.setBad(BadConversionSequence::unrelated_class,
FromType, ImplicitParamType);
return ICS;
}
switch (Method->getRefQualifier()) {
case RQ_None:
break;
case RQ_LValue:
if (!FromClassification.isLValue() && !Quals.hasOnlyConst()) {
ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, FromType,
ImplicitParamType);
return ICS;
}
break;
case RQ_RValue:
if (!FromClassification.isRValue()) {
ICS.setBad(BadConversionSequence::rvalue_ref_to_lvalue, FromType,
ImplicitParamType);
return ICS;
}
break;
}
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.Second = SecondKind;
ICS.Standard.setFromType(FromType);
ICS.Standard.setAllToTypes(ImplicitParamType);
ICS.Standard.ReferenceBinding = true;
ICS.Standard.DirectBinding = true;
ICS.Standard.IsLvalueReference = Method->getRefQualifier() != RQ_RValue;
ICS.Standard.BindsToFunctionLvalue = false;
ICS.Standard.BindsToRvalue = FromClassification.isRValue();
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier
= (Method->getRefQualifier() == RQ_None);
return ICS;
}
ExprResult Sema::PerformImplicitObjectArgumentInitialization(
Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl,
CXXMethodDecl *Method) {
QualType FromRecordType, DestType;
QualType ImplicitParamRecordType = Method->getFunctionObjectParameterType();
Expr::Classification FromClassification;
if (const PointerType *PT = From->getType()->getAs<PointerType>()) {
FromRecordType = PT->getPointeeType();
DestType = Method->getThisType();
FromClassification = Expr::Classification::makeSimpleLValue();
} else {
FromRecordType = From->getType();
DestType = ImplicitParamRecordType;
FromClassification = From->Classify(Context);
if (From->isPRValue()) {
From = CreateMaterializeTemporaryExpr(FromRecordType, From,
Method->getRefQualifier() !=
RefQualifierKind::RQ_RValue);
}
}
ImplicitConversionSequence ICS = TryObjectArgumentInitialization(
*this, From->getBeginLoc(), From->getType(), FromClassification, Method,
Method->getParent());
if (ICS.isBad()) {
switch (ICS.Bad.Kind) {
case BadConversionSequence::bad_qualifiers: {
Qualifiers FromQs = FromRecordType.getQualifiers();
Qualifiers ToQs = DestType.getQualifiers();
unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers();
if (CVR) {
Diag(From->getBeginLoc(), diag::err_member_function_call_bad_cvr)
<< Method->getDeclName() << FromRecordType << (CVR - 1)
<< From->getSourceRange();
Diag(Method->getLocation(), diag::note_previous_decl)
<< Method->getDeclName();
return ExprError();
}
break;
}
case BadConversionSequence::lvalue_ref_to_rvalue:
case BadConversionSequence::rvalue_ref_to_lvalue: {
bool IsRValueQualified =
Method->getRefQualifier() == RefQualifierKind::RQ_RValue;
Diag(From->getBeginLoc(), diag::err_member_function_call_bad_ref)
<< Method->getDeclName() << FromClassification.isRValue()
<< IsRValueQualified;
Diag(Method->getLocation(), diag::note_previous_decl)
<< Method->getDeclName();
return ExprError();
}
case BadConversionSequence::no_conversion:
case BadConversionSequence::unrelated_class:
break;
case BadConversionSequence::too_few_initializers:
case BadConversionSequence::too_many_initializers:
llvm_unreachable("Lists are not objects");
}
return Diag(From->getBeginLoc(), diag::err_member_function_call_bad_type)
<< ImplicitParamRecordType << FromRecordType
<< From->getSourceRange();
}
if (ICS.Standard.Second == ICK_Derived_To_Base) {
ExprResult FromRes =
PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method);
if (FromRes.isInvalid())
return ExprError();
From = FromRes.get();
}
if (!Context.hasSameType(From->getType(), DestType)) {
CastKind CK;
QualType PteeTy = DestType->getPointeeType();
LangAS DestAS =
PteeTy.isNull() ? DestType.getAddressSpace() : PteeTy.getAddressSpace();
if (FromRecordType.getAddressSpace() != DestAS)
CK = CK_AddressSpaceConversion;
else
CK = CK_NoOp;
From = ImpCastExprToType(From, DestType, CK, From->getValueKind()).get();
}
return From;
}
static ImplicitConversionSequence
TryContextuallyConvertToBool(Sema &S, Expr *From) {
if (From->getType()->isNullPtrType())
return ImplicitConversionSequence::getNullptrToBool(From->getType(),
S.Context.BoolTy,
From->isGLValue());
return TryImplicitConversion(S, From, S.Context.BoolTy,
false,
AllowedExplicit::Conversions,
false,
false,
false,
false);
}
ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) {
if (checkPlaceholderForOverload(*this, From))
return ExprError();
ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From);
if (!ICS.isBad())
return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting);
if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy))
return Diag(From->getBeginLoc(), diag::err_typecheck_bool_condition)
<< From->getType() << From->getSourceRange();
return ExprError();
}
static bool CheckConvertedConstantConversions(Sema &S,
StandardConversionSequence &SCS) {
switch (SCS.Second) {
case ICK_Identity:
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
case ICK_Zero_Queue_Conversion:
return true;
case ICK_Boolean_Conversion:
return SCS.getFromType()->isIntegralOrUnscopedEnumerationType() &&
SCS.getToType(2)->isBooleanType();
case ICK_Pointer_Conversion:
case ICK_Pointer_Member:
return SCS.getFromType()->isNullPtrType();
case ICK_Floating_Promotion:
case ICK_Complex_Promotion:
case ICK_Floating_Conversion:
case ICK_Complex_Conversion:
case ICK_Floating_Integral:
case ICK_Compatible_Conversion:
case ICK_Derived_To_Base:
case ICK_Vector_Conversion:
case ICK_SVE_Vector_Conversion:
case ICK_RVV_Vector_Conversion:
case ICK_HLSL_Vector_Splat:
case ICK_Vector_Splat:
case ICK_Complex_Real:
case ICK_Block_Pointer_Conversion:
case ICK_TransparentUnionConversion:
case ICK_Writeback_Conversion:
case ICK_Zero_Event_Conversion:
case ICK_C_Only_Conversion:
case ICK_Incompatible_Pointer_Conversion:
case ICK_Fixed_Point_Conversion:
case ICK_HLSL_Vector_Truncation:
return false;
case ICK_Lvalue_To_Rvalue:
case ICK_Array_To_Pointer:
case ICK_Function_To_Pointer:
case ICK_HLSL_Array_RValue:
llvm_unreachable("found a first conversion kind in Second");
case ICK_Function_Conversion:
case ICK_Qualification:
llvm_unreachable("found a third conversion kind in Second");
case ICK_Num_Conversion_Kinds:
break;
}
llvm_unreachable("unknown conversion kind");
}
static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From,
QualType T,
Sema::CCEKind CCE,
NamedDecl *Dest,
APValue &PreNarrowingValue) {
assert(S.getLangOpts().CPlusPlus11 &&
"converted constant expression outside C++11");
if (checkPlaceholderForOverload(S, From))
return ExprError();
ImplicitConversionSequence ICS =
(CCE == Sema::CCEK_ExplicitBool || CCE == Sema::CCEK_Noexcept)
? TryContextuallyConvertToBool(S, From)
: TryCopyInitialization(S, From, T,
false,
false,
false,
false);
StandardConversionSequence *SCS = nullptr;
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
SCS = &ICS.Standard;
break;
case ImplicitConversionSequence::UserDefinedConversion:
if (T->isRecordType())
SCS = &ICS.UserDefined.Before;
else
SCS = &ICS.UserDefined.After;
break;
case ImplicitConversionSequence::AmbiguousConversion:
case ImplicitConversionSequence::BadConversion:
if (!S.DiagnoseMultipleUserDefinedConversion(From, T))
return S.Diag(From->getBeginLoc(),
diag::err_typecheck_converted_constant_expression)
<< From->getType() << From->getSourceRange() << T;
return ExprError();
case ImplicitConversionSequence::EllipsisConversion:
case ImplicitConversionSequence::StaticObjectArgumentConversion:
llvm_unreachable("bad conversion in converted constant expression");
}
if (!CheckConvertedConstantConversions(S, *SCS)) {
return S.Diag(From->getBeginLoc(),
diag::err_typecheck_converted_constant_expression_disallowed)
<< From->getType() << From->getSourceRange() << T;
}
if (SCS->ReferenceBinding && !SCS->DirectBinding) {
return S.Diag(From->getBeginLoc(),
diag::err_typecheck_converted_constant_expression_indirect)
<< From->getType() << From->getSourceRange() << T;
}
if (From->refersToBitField() && T.getTypePtr()->isReferenceType()) {
return S.Diag(From->getBeginLoc(),
diag::err_reference_bind_to_bitfield_in_cce)
<< From->getSourceRange();
}
ExprResult Result;
if (T->isRecordType()) {
assert(CCE == Sema::CCEK_TemplateArg &&
"unexpected class type converted constant expr");
Result = S.PerformCopyInitialization(
InitializedEntity::InitializeTemplateParameter(
T, cast<NonTypeTemplateParmDecl>(Dest)),
SourceLocation(), From);
} else {
Result = S.PerformImplicitConversion(From, T, ICS, Sema::AA_Converting);
}
if (Result.isInvalid())
return Result;
Result = S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(),
false, true,
CCE == Sema::CCEKind::CCEK_TemplateArg);
if (Result.isInvalid())
return Result;
bool ReturnPreNarrowingValue = false;
QualType PreNarrowingType;
switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
PreNarrowingType)) {
case NK_Dependent_Narrowing:
case NK_Variable_Narrowing:
case NK_Not_Narrowing:
break;
case NK_Constant_Narrowing:
if (CCE == Sema::CCEK_ArrayBound &&
PreNarrowingType->isIntegralOrEnumerationType() &&
PreNarrowingValue.isInt()) {
ReturnPreNarrowingValue = true;
break;
}
S.Diag(From->getBeginLoc(), diag::ext_cce_narrowing)
<< CCE << 1
<< PreNarrowingValue.getAsString(S.Context, PreNarrowingType) << T;
break;
case NK_Type_Narrowing:
S.Diag(From->getBeginLoc(), diag::ext_cce_narrowing)
<< CCE << 0 << From->getType() << T;
break;
}
if (!ReturnPreNarrowingValue)
PreNarrowingValue = {};
return Result;
}
static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
QualType T, APValue &Value,
Sema::CCEKind CCE,
bool RequireInt,
NamedDecl *Dest) {
APValue PreNarrowingValue;
ExprResult Result = BuildConvertedConstantExpression(S, From, T, CCE, Dest,
PreNarrowingValue);
if (Result.isInvalid() || Result.get()->isValueDependent()) {
Value = APValue();
return Result;
}
return S.EvaluateConvertedConstantExpression(Result.get(), T, Value, CCE,
RequireInt, PreNarrowingValue);
}
ExprResult Sema::BuildConvertedConstantExpression(Expr *From, QualType T,
CCEKind CCE,
NamedDecl *Dest) {
APValue PreNarrowingValue;
return ::BuildConvertedConstantExpression(*this, From, T, CCE, Dest,
PreNarrowingValue);
}
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
APValue &Value, CCEKind CCE,
NamedDecl *Dest) {
return ::CheckConvertedConstantExpression(*this, From, T, Value, CCE, false,
Dest);
}
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
llvm::APSInt &Value,
CCEKind CCE) {
assert(T->isIntegralOrEnumerationType() && "unexpected converted const type");
APValue V;
auto R = ::CheckConvertedConstantExpression(*this, From, T, V, CCE, true,
nullptr);
if (!R.isInvalid() && !R.get()->isValueDependent())
Value = V.getInt();
return R;
}
ExprResult
Sema::EvaluateConvertedConstantExpression(Expr *E, QualType T, APValue &Value,
Sema::CCEKind CCE, bool RequireInt,
const APValue &PreNarrowingValue) {
ExprResult Result = E;
SmallVector<PartialDiagnosticAt, 8> Notes;
Expr::EvalResult Eval;
Eval.Diag = &Notes;
ConstantExprKind Kind;
if (CCE == Sema::CCEK_TemplateArg && T->isRecordType())
Kind = ConstantExprKind::ClassTemplateArgument;
else if (CCE == Sema::CCEK_TemplateArg)
Kind = ConstantExprKind::NonClassTemplateArgument;
else
Kind = ConstantExprKind::Normal;
if (!E->EvaluateAsConstantExpr(Eval, Context, Kind) ||
(RequireInt && !Eval.Val.isInt())) {
Result = ExprError();
} else {
Value = Eval.Val;
if (Notes.empty()) {
Expr *E = Result.get();
if (const auto *CE = dyn_cast<ConstantExpr>(E)) {
assert(CE->getResultStorageKind() != ConstantResultStorageKind::None &&
"ConstantExpr has no value associated with it");
(void)CE;
} else {
E = ConstantExpr::Create(Context, Result.get(), Value);
}
if (!PreNarrowingValue.isAbsent())
Value = std::move(PreNarrowingValue);
return E;
}
}
if (Notes.size() == 1 &&
Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr) {
Diag(Notes[0].first, diag::err_expr_not_cce) << CCE;
} else if (!Notes.empty() && Notes[0].second.getDiagID() ==
diag::note_constexpr_invalid_template_arg) {
Notes[0].second.setDiagID(diag::err_constexpr_invalid_template_arg);
for (unsigned I = 0; I < Notes.size(); ++I)
Diag(Notes[I].first, Notes[I].second);
} else {
Diag(E->getBeginLoc(), diag::err_expr_not_cce)
<< CCE << E->getSourceRange();
for (unsigned I = 0; I < Notes.size(); ++I)
Diag(Notes[I].first, Notes[I].second);
}
return ExprError();
}
static void dropPointerConversion(StandardConversionSequence &SCS) {
if (SCS.Second == ICK_Pointer_Conversion) {
SCS.Second = ICK_Identity;
SCS.Dimension = ICK_Identity;
SCS.Third = ICK_Identity;
SCS.ToTypePtrs[2] = SCS.ToTypePtrs[1] = SCS.ToTypePtrs[0];
}
}
static ImplicitConversionSequence
TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) {
QualType Ty = S.Context.getObjCIdType();
ImplicitConversionSequence ICS
= TryImplicitConversion(S, From, Ty,
false,
AllowedExplicit::Conversions,
false,
false,
false,
true);
switch (ICS.getKind()) {
case ImplicitConversionSequence::BadConversion:
case ImplicitConversionSequence::AmbiguousConversion:
case ImplicitConversionSequence::EllipsisConversion:
case ImplicitConversionSequence::StaticObjectArgumentConversion:
break;
case ImplicitConversionSequence::UserDefinedConversion:
dropPointerConversion(ICS.UserDefined.After);
break;
case ImplicitConversionSequence::StandardConversion:
dropPointerConversion(ICS.Standard);
break;
}
return ICS;
}
ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) {
if (checkPlaceholderForOverload(*this, From))
return ExprError();
QualType Ty = Context.getObjCIdType();
ImplicitConversionSequence ICS =
TryContextuallyConvertToObjCPointer(*this, From);
if (!ICS.isBad())
return PerformImplicitConversion(From, Ty, ICS, AA_Converting);
return ExprResult();
}
static QualType GetExplicitObjectType(Sema &S, const Expr *MemExprE) {
const Expr *Base = nullptr;
assert((isa<UnresolvedMemberExpr, MemberExpr>(MemExprE)) &&
"expected a member expression");
if (const auto M = dyn_cast<UnresolvedMemberExpr>(MemExprE);
M && !M->isImplicitAccess())
Base = M->getBase();
else if (const auto M = dyn_cast<MemberExpr>(MemExprE);
M && !M->isImplicitAccess())
Base = M->getBase();
QualType T = Base ? Base->getType() : S.getCurrentThisType();
if (T->isPointerType())
T = T->getPointeeType();
return T;
}
static Expr *GetExplicitObjectExpr(Sema &S, Expr *Obj,
const FunctionDecl *Fun) {
QualType ObjType = Obj->getType();
if (ObjType->isPointerType()) {
ObjType = ObjType->getPointeeType();
Obj = UnaryOperator::Create(S.getASTContext(), Obj, UO_Deref, ObjType,
VK_LValue, OK_Ordinary, SourceLocation(),
false, FPOptionsOverride());
}
if (Obj->Classify(S.getASTContext()).isPRValue()) {
Obj = S.CreateMaterializeTemporaryExpr(
ObjType, Obj,
!Fun->getParamDecl(0)->getType()->isRValueReferenceType());
}
return Obj;
}
ExprResult Sema::InitializeExplicitObjectArgument(Sema &S, Expr *Obj,
FunctionDecl *Fun) {
Obj = GetExplicitObjectExpr(S, Obj, Fun);
return S.PerformCopyInitialization(
InitializedEntity::InitializeParameter(S.Context, Fun->getParamDecl(0)),
Obj->getExprLoc(), Obj);
}
static bool PrepareExplicitObjectArgument(Sema &S, CXXMethodDecl *Method,
Expr *Object, MultiExprArg &Args,
SmallVectorImpl<Expr *> &NewArgs) {
assert(Method->isExplicitObjectMemberFunction() &&
"Method is not an explicit member function");
assert(NewArgs.empty() && "NewArgs should be empty");
NewArgs.reserve(Args.size() + 1);
Expr *This = GetExplicitObjectExpr(S, Object, Method);
NewArgs.push_back(This);
NewArgs.append(Args.begin(), Args.end());
Args = NewArgs;
return S.DiagnoseInvalidExplicitObjectParameterInLambda(
Method, Object->getBeginLoc());
}
bool Sema::ICEConvertDiagnoser::match(QualType T) {
return AllowScopedEnumerations ? T->isIntegralOrEnumerationType()
: T->isIntegralOrUnscopedEnumerationType();
}
static ExprResult
diagnoseAmbiguousConversion(Sema &SemaRef, SourceLocation Loc, Expr *From,
Sema::ContextualImplicitConverter &Converter,
QualType T, UnresolvedSetImpl &ViableConversions) {
if (Converter.Suppress)
return ExprError();
Converter.diagnoseAmbiguous(SemaRef, Loc, T) << From->getSourceRange();
for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
CXXConversionDecl *Conv =
cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
QualType ConvTy = Conv->getConversionType().getNonReferenceType();
Converter.noteAmbiguous(SemaRef, Conv, ConvTy);
}
return From;
}
static bool
diagnoseNoViableConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
Sema::ContextualImplicitConverter &Converter,
QualType T, bool HadMultipleCandidates,
UnresolvedSetImpl &ExplicitConversions) {
if (ExplicitConversions.size() == 1 && !Converter.Suppress) {
DeclAccessPair Found = ExplicitConversions[0];
CXXConversionDecl *Conversion =
cast<CXXConversionDecl>(Found->getUnderlyingDecl());
QualType ConvTy = Conversion->getConversionType().getNonReferenceType();
std::string TypeStr;
ConvTy.getAsStringInternal(TypeStr, SemaRef.getPrintingPolicy());
Converter.diagnoseExplicitConv(SemaRef, Loc, T, ConvTy)
<< FixItHint::CreateInsertion(From->getBeginLoc(),
"static_cast<" + TypeStr + ">(")
<< FixItHint::CreateInsertion(
SemaRef.getLocForEndOfToken(From->getEndLoc()), ")");
Converter.noteExplicitConv(SemaRef, Conversion, ConvTy);
if (SemaRef.isSFINAEContext())
return true;
SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, nullptr, Found);
ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion,
HadMultipleCandidates);
if (Result.isInvalid())
return true;
Result = SemaRef.CreateRecoveryExpr(From->getBeginLoc(), From->getEndLoc(),
From, Result.get()->getType());
if (Result.isInvalid())
return true;
From = Result.get();
}
return false;
}
static bool recordConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
Sema::ContextualImplicitConverter &Converter,
QualType T, bool HadMultipleCandidates,
DeclAccessPair &Found) {
CXXConversionDecl *Conversion =
cast<CXXConversionDecl>(Found->getUnderlyingDecl());
SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, nullptr, Found);
QualType ToType = Conversion->getConversionType().getNonReferenceType();
if (!Converter.SuppressConversion) {
if (SemaRef.isSFINAEContext())
return true;
Converter.diagnoseConversion(SemaRef, Loc, T, ToType)
<< From->getSourceRange();
}
ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion,
HadMultipleCandidates);
if (Result.isInvalid())
return true;
From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),
CK_UserDefinedConversion, Result.get(),
nullptr, Result.get()->getValueKind(),
SemaRef.CurFPFeatureOverrides());
return false;
}
static ExprResult finishContextualImplicitConversion(
Sema &SemaRef, SourceLocation Loc, Expr *From,
Sema::ContextualImplicitConverter &Converter) {
if (!Converter.match(From->getType()) && !Converter.Suppress)
Converter.diagnoseNoMatch(SemaRef, Loc, From->getType())
<< From->getSourceRange();
return SemaRef.DefaultLvalueConversion(From);
}
static void
collectViableConversionCandidates(Sema &SemaRef, Expr *From, QualType ToType,
UnresolvedSetImpl &ViableConversions,
OverloadCandidateSet &CandidateSet) {
for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
DeclAccessPair FoundDecl = ViableConversions[I];
NamedDecl *D = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
CXXConversionDecl *Conv;
FunctionTemplateDecl *ConvTemplate;
if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(D)))
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
Conv = cast<CXXConversionDecl>(D);
if (ConvTemplate)
SemaRef.AddTemplateConversionCandidate(
ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet,
false, true);
else
SemaRef.AddConversionCandidate(Conv, FoundDecl, ActingContext, From,
ToType, CandidateSet,
false,
true);
}
}
ExprResult Sema::PerformContextualImplicitConversion(
SourceLocation Loc, Expr *From, ContextualImplicitConverter &Converter) {
if (From->isTypeDependent())
return From;
if (From->hasPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(From);
if (result.isInvalid())
return result;
From = result.get();
}
ExprResult Converted = DefaultLvalueConversion(From);
QualType T = Converted.isUsable() ? Converted.get()->getType() : QualType();
if (Converter.match(T))
return Converted;
const RecordType *RecordTy = T->getAs<RecordType>();
if (!RecordTy || !getLangOpts().CPlusPlus) {
if (!Converter.Suppress)
Converter.diagnoseNoMatch(*this, Loc, T) << From->getSourceRange();
return From;
}
struct TypeDiagnoserPartialDiag : TypeDiagnoser {
ContextualImplicitConverter &Converter;
Expr *From;
TypeDiagnoserPartialDiag(ContextualImplicitConverter &Converter, Expr *From)
: Converter(Converter), From(From) {}
void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
Converter.diagnoseIncomplete(S, Loc, T) << From->getSourceRange();
}
} IncompleteDiagnoser(Converter, From);
if (Converter.Suppress ? !isCompleteType(Loc, T)
: RequireCompleteType(Loc, T, IncompleteDiagnoser))
return From;
UnresolvedSet<4>
ViableConversions;
UnresolvedSet<4> ExplicitConversions;
const auto &Conversions =
cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
bool HadMultipleCandidates =
(std::distance(Conversions.begin(), Conversions.end()) > 1);
QualType ToType;
bool HasUniqueTargetType = true;
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
CXXConversionDecl *Conversion;
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
if (ConvTemplate) {
if (getLangOpts().CPlusPlus14)
Conversion = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
continue;
} else
Conversion = cast<CXXConversionDecl>(D);
assert((!ConvTemplate || getLangOpts().CPlusPlus14) &&
"Conversion operator templates are considered potentially "
"viable in C++1y");
QualType CurToType = Conversion->getConversionType().getNonReferenceType();
if (Converter.match(CurToType) || ConvTemplate) {
if (Conversion->isExplicit()) {
if (!ConvTemplate)
ExplicitConversions.addDecl(I.getDecl(), I.getAccess());
} else {
if (!ConvTemplate && getLangOpts().CPlusPlus14) {
if (ToType.isNull())
ToType = CurToType.getUnqualifiedType();
else if (HasUniqueTargetType &&
(CurToType.getUnqualifiedType() != ToType))
HasUniqueTargetType = false;
}
ViableConversions.addDecl(I.getDecl(), I.getAccess());
}
}
}
if (getLangOpts().CPlusPlus14) {
if (ToType.isNull()) {
if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,
HadMultipleCandidates,
ExplicitConversions))
return ExprError();
return finishContextualImplicitConversion(*this, Loc, From, Converter);
}
if (!HasUniqueTargetType)
return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
ViableConversions);
OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
collectViableConversionCandidates(*this, From, ToType, ViableConversions,
CandidateSet);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, Loc, Best)) {
case OR_Success: {
DeclAccessPair Found =
DeclAccessPair::make(Best->Function, Best->FoundDecl.getAccess());
if (recordConversion(*this, Loc, From, Converter, T,
HadMultipleCandidates, Found))
return ExprError();
break;
}
case OR_Ambiguous:
return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
ViableConversions);
case OR_No_Viable_Function:
if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,
HadMultipleCandidates,
ExplicitConversions))
return ExprError();
[[fallthrough]];
case OR_Deleted:
break;
}
} else {
switch (ViableConversions.size()) {
case 0: {
if (diagnoseNoViableConversion(*this, Loc, From, Converter, T,
HadMultipleCandidates,
ExplicitConversions))
return ExprError();
break;
}
case 1: {
DeclAccessPair Found = ViableConversions[0];
if (recordConversion(*this, Loc, From, Converter, T,
HadMultipleCandidates, Found))
return ExprError();
break;
}
default:
return diagnoseAmbiguousConversion(*this, Loc, From, Converter, T,
ViableConversions);
}
}
return finishContextualImplicitConversion(*this, Loc, From, Converter);
}
static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
FunctionDecl *Fn,
ArrayRef<Expr *> Args) {
QualType T1 = Args[0]->getType();
QualType T2 = Args.size() > 1 ? Args[1]->getType() : QualType();
if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType()))
return true;
if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
return true;
const auto *Proto = Fn->getType()->castAs<FunctionProtoType>();
if (Proto->getNumParams() < 1)
return false;
if (T1->isEnumeralType()) {
QualType ArgType = Proto->getParamType(0).getNonReferenceType();
if (Context.hasSameUnqualifiedType(T1, ArgType))
return true;
}
if (Proto->getNumParams() < 2)
return false;
if (!T2.isNull() && T2->isEnumeralType()) {
QualType ArgType = Proto->getParamType(1).getNonReferenceType();
if (Context.hasSameUnqualifiedType(T2, ArgType))
return true;
}
return false;
}
static bool isNonViableMultiVersionOverload(FunctionDecl *FD) {
if (FD->isTargetMultiVersionDefault())
return false;
if (!FD->getASTContext().getTargetInfo().getTriple().isAArch64())
return FD->isTargetMultiVersion();
if (!FD->isMultiVersion())
return false;
unsigned SeenAt = 0;
unsigned I = 0;
bool HasDefault = false;
FD->getASTContext().forEachMultiversionedFunctionVersion(
FD, [&](const FunctionDecl *CurFD) {
if (FD == CurFD)
SeenAt = I;
else if (CurFD->isTargetMultiVersionDefault())
HasDefault = true;
++I;
});
return HasDefault || SeenAt != 0;
}
void Sema::AddOverloadCandidate(
FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions,
OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
assert(!Function->getDescribedFunctionTemplate() &&
"Use AddTemplateOverloadCandidate for function templates");
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
if (!isa<CXXConstructorDecl>(Method)) {
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
Expr::Classification::makeSimpleLValue(), Args,
CandidateSet, SuppressUserConversions,
PartialOverloading, EarlyConversions, PO);
return;
}
}
if (!CandidateSet.isNewCandidate(Function, PO))
return;
CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Function);
if (Constructor && Constructor->isDefaulted() && Constructor->isDeleted() &&
Constructor->isMoveConstructor())
return;
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&
!IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))
return;
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Args.size(), EarlyConversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Function;
Candidate.Viable = true;
Candidate.RewriteKind =
CandidateSet.getRewriteInfo().getRewriteKind(Function, PO);
Candidate.IsADLCandidate = IsADLCandidate;
Candidate.ExplicitCallArguments = Args.size();
if (!AllowExplicit && ExplicitSpecifier::getFromDecl(Function).isExplicit()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_explicit;
return;
}
if (getLangOpts().CPlusPlusModules && Function->isInAnotherModuleUnit()) {
NamedDecl *ND = Function;
if (auto *SpecInfo = Function->getTemplateSpecializationInfo())
ND = SpecInfo->getTemplate();
if (ND->getFormalLinkage() == Linkage::Internal) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_module_mismatched;
return;
}
}
if (isNonViableMultiVersionOverload(Function)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_non_default_multiversion_function;
return;
}
if (Constructor) {
QualType ClassType = Context.getTypeDeclType(Constructor->getParent());
if (Args.size() == 1 && Constructor->isSpecializationCopyingObject() &&
(Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) ||
IsDerivedFrom(Args[0]->getBeginLoc(), Args[0]->getType(),
ClassType))) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_illegal_constructor;
return;
}
auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl.getDecl());
if (Shadow && Args.size() == 1 && Constructor->getNumParams() >= 1 &&
Constructor->getParamDecl(0)->getType()->isReferenceType()) {
QualType P = Constructor->getParamDecl(0)->getType()->getPointeeType();
QualType C = Context.getRecordType(Constructor->getParent());
QualType D = Context.getRecordType(Shadow->getParent());
SourceLocation Loc = Args.front()->getExprLoc();
if ((Context.hasSameUnqualifiedType(P, C) || IsDerivedFrom(Loc, P, C)) &&
(Context.hasSameUnqualifiedType(D, P) || IsDerivedFrom(Loc, D, P))) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_inhctor_slice;
return;
}
}
if (!Qualifiers::isAddressSpaceSupersetOf(
Constructor->getMethodQualifiers().getAddressSpace(),
CandidateSet.getDestAS())) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_object_addrspace_mismatch;
}
}
unsigned NumParams = Proto->getNumParams();
if (TooManyArguments(NumParams, Args.size(), PartialOverloading) &&
!Proto->isVariadic() &&
shouldEnforceArgLimit(PartialOverloading, Function)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
unsigned MinRequiredArgs = Function->getMinRequiredArguments();
if (!AggregateCandidateDeduction && Args.size() < MinRequiredArgs &&
!PartialOverloading) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
if (getLangOpts().CUDA) {
const FunctionDecl *Caller = getCurFunctionDecl(true);
if (!(Caller && Caller->isImplicit()) &&
!CUDA().IsAllowedCall(Caller, Function)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_target;
return;
}
}
if (Function->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
if (CheckFunctionConstraints(Function, Satisfaction, {},
true) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
return;
}
}
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
unsigned ConvIdx =
PO == OverloadCandidateParamOrder::Reversed ? 1 - ArgIdx : ArgIdx;
if (Candidate.Conversions[ConvIdx].isInitialized()) {
} else if (ArgIdx < NumParams) {
QualType ParamType = Proto->getParamType(ArgIdx);
Candidate.Conversions[ConvIdx] = TryCopyInitialization(
*this, Args[ArgIdx], ParamType, SuppressUserConversions,
true,
getLangOpts().ObjCAutoRefCount, AllowExplicitConversions);
if (Candidate.Conversions[ConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
} else {
Candidate.Conversions[ConvIdx].setEllipsis();
}
}
if (EnableIfAttr *FailedAttr =
CheckEnableIf(Function, CandidateSet.getLocation(), Args)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
}
ObjCMethodDecl *
Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance,
SmallVectorImpl<ObjCMethodDecl *> &Methods) {
if (Methods.size() <= 1)
return nullptr;
for (unsigned b = 0, e = Methods.size(); b < e; b++) {
bool Match = true;
ObjCMethodDecl *Method = Methods[b];
unsigned NumNamedArgs = Sel.getNumArgs();
if (Method->param_size() > NumNamedArgs)
NumNamedArgs = Method->param_size();
if (Args.size() < NumNamedArgs)
continue;
for (unsigned i = 0; i < NumNamedArgs; i++) {
if (Args[i]->isTypeDependent()) {
Match = false;
break;
}
ParmVarDecl *param = Method->parameters()[i];
Expr *argExpr = Args[i];
assert(argExpr && "SelectBestMethod(): missing expression");
if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) &&
!param->hasAttr<CFConsumedAttr>())
argExpr = ObjC().stripARCUnbridgedCast(argExpr);
if (param->getType() == Context.UnknownAnyTy) {
Match = false;
break;
}
ImplicitConversionSequence ConversionState
= TryCopyInitialization(*this, argExpr, param->getType(),
false,
true,
getLangOpts().ObjCAutoRefCount,
false);
if (ConversionState.isBad() ||
(ConversionState.isStandard() &&
ConversionState.Standard.Second ==
ICK_Incompatible_Pointer_Conversion)) {
Match = false;
break;
}
}
if (Match && Method->isVariadic()) {
for (unsigned i = NumNamedArgs, e = Args.size(); i < e; ++i) {
if (Args[i]->isTypeDependent()) {
Match = false;
break;
}
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
nullptr);
if (Arg.isInvalid()) {
Match = false;
break;
}
}
} else {
if (Args.size() != NumNamedArgs)
Match = false;
else if (Match && NumNamedArgs == 0 && Methods.size() > 1) {
for (unsigned b = 0, e = Methods.size(); b < e; b++) {
QualType ReturnT = Methods[b]->getReturnType();
if (ReturnT->isObjCIdType())
return Methods[b];
}
}
}
if (Match)
return Method;
}
return nullptr;
}
static bool convertArgsForAvailabilityChecks(
Sema &S, FunctionDecl *Function, Expr *ThisArg, SourceLocation CallLoc,
ArrayRef<Expr *> Args, Sema::SFINAETrap &Trap, bool MissingImplicitThis,
Expr *&ConvertedThis, SmallVectorImpl<Expr *> &ConvertedArgs) {
if (ThisArg) {
CXXMethodDecl *Method = cast<CXXMethodDecl>(Function);
assert(!isa<CXXConstructorDecl>(Method) &&
"Shouldn't have `this` for ctors!");
assert(!Method->isStatic() && "Shouldn't have `this` for static methods!");
ExprResult R = S.PerformImplicitObjectArgumentInitialization(
ThisArg, nullptr, Method, Method);
if (R.isInvalid())
return false;
ConvertedThis = R.get();
} else {
if (auto *MD = dyn_cast<CXXMethodDecl>(Function)) {
(void)MD;
assert((MissingImplicitThis || MD->isStatic() ||
isa<CXXConstructorDecl>(MD)) &&
"Expected `this` for non-ctor instance methods");
}
ConvertedThis = nullptr;
}
unsigned ArgSizeNoVarargs = std::min(Function->param_size(), Args.size());
for (unsigned I = 0; I != ArgSizeNoVarargs; ++I) {
ExprResult R;
R = S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
S.Context, Function->getParamDecl(I)),
SourceLocation(), Args[I]);
if (R.isInvalid())
return false;
ConvertedArgs.push_back(R.get());
}
if (Trap.hasErrorOccurred())
return false;
if (!Function->isVariadic() && Args.size() < Function->getNumParams()) {
for (unsigned i = Args.size(), e = Function->getNumParams(); i != e; ++i) {
ParmVarDecl *P = Function->getParamDecl(i);
if (!P->hasDefaultArg())
return false;
ExprResult R = S.BuildCXXDefaultArgExpr(CallLoc, Function, P);
if (R.isInvalid())
return false;
ConvertedArgs.push_back(R.get());
}
if (Trap.hasErrorOccurred())
return false;
}
return true;
}
EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function,
SourceLocation CallLoc,
ArrayRef<Expr *> Args,
bool MissingImplicitThis) {
auto EnableIfAttrs = Function->specific_attrs<EnableIfAttr>();
if (EnableIfAttrs.begin() == EnableIfAttrs.end())
return nullptr;
SFINAETrap Trap(*this);
SmallVector<Expr *, 16> ConvertedArgs;
Expr *DiscardedThis;
if (!convertArgsForAvailabilityChecks(
*this, Function, nullptr, CallLoc, Args, Trap,
true, DiscardedThis, ConvertedArgs))
return *EnableIfAttrs.begin();
for (auto *EIA : EnableIfAttrs) {
APValue Result;
if (EIA->getCond()->isValueDependent() ||
!EIA->getCond()->EvaluateWithSubstitution(
Result, Context, Function, llvm::ArrayRef(ConvertedArgs)))
return EIA;
if (!Result.isInt() || !Result.getInt().getBoolValue())
return EIA;
}
return nullptr;
}
template <typename CheckFn>
static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const NamedDecl *ND,
bool ArgDependent, SourceLocation Loc,
CheckFn &&IsSuccessful) {
SmallVector<const DiagnoseIfAttr *, 8> Attrs;
for (const auto *DIA : ND->specific_attrs<DiagnoseIfAttr>()) {
if (ArgDependent == DIA->getArgDependent())
Attrs.push_back(DIA);
}
if (Attrs.empty())
return false;
auto WarningBegin = std::stable_partition(
Attrs.begin(), Attrs.end(),
[](const DiagnoseIfAttr *DIA) { return DIA->isError(); });
auto ErrAttr = llvm::find_if(llvm::make_range(Attrs.begin(), WarningBegin),
IsSuccessful);
if (ErrAttr != WarningBegin) {
const DiagnoseIfAttr *DIA = *ErrAttr;
S.Diag(Loc, diag::err_diagnose_if_succeeded) << DIA->getMessage();
S.Diag(DIA->getLocation(), diag::note_from_diagnose_if)
<< DIA->getParent() << DIA->getCond()->getSourceRange();
return true;
}
for (const auto *DIA : llvm::make_range(WarningBegin, Attrs.end()))
if (IsSuccessful(DIA)) {
S.Diag(Loc, diag::warn_diagnose_if_succeeded) << DIA->getMessage();
S.Diag(DIA->getLocation(), diag::note_from_diagnose_if)
<< DIA->getParent() << DIA->getCond()->getSourceRange();
}
return false;
}
bool Sema::diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function,
const Expr *ThisArg,
ArrayRef<const Expr *> Args,
SourceLocation Loc) {
return diagnoseDiagnoseIfAttrsWith(
*this, Function, true, Loc,
[&](const DiagnoseIfAttr *DIA) {
APValue Result;
if (!DIA->getCond()->EvaluateWithSubstitution(
Result, Context, cast<FunctionDecl>(DIA->getParent()), Args, ThisArg))
return false;
return Result.isInt() && Result.getInt().getBoolValue();
});
}
bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND,
SourceLocation Loc) {
return diagnoseDiagnoseIfAttrsWith(
*this, ND, false, Loc,
[&](const DiagnoseIfAttr *DIA) {
bool Result;
return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) &&
Result;
});
}
void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
TemplateArgumentListInfo *ExplicitTemplateArgs,
bool SuppressUserConversions,
bool PartialOverloading,
bool FirstArgumentIsBase) {
for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
NamedDecl *D = F.getDecl()->getUnderlyingDecl();
ArrayRef<Expr *> FunctionArgs = Args;
FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D);
FunctionDecl *FD =
FunTmpl ? FunTmpl->getTemplatedDecl() : cast<FunctionDecl>(D);
if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) {
QualType ObjectType;
Expr::Classification ObjectClassification;
if (Args.size() > 0) {
if (Expr *E = Args[0]) {
ObjectType = E->getType();
if (!ObjectType.isNull() && ObjectType->isPointerType())
ObjectClassification = Expr::Classification::makeSimpleLValue();
else
ObjectClassification = E->Classify(Context);
}
FunctionArgs = Args.slice(1);
}
if (FunTmpl) {
AddMethodTemplateCandidate(
FunTmpl, F.getPair(),
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
ExplicitTemplateArgs, ObjectType, ObjectClassification,
FunctionArgs, CandidateSet, SuppressUserConversions,
PartialOverloading);
} else {
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
cast<CXXMethodDecl>(FD)->getParent(), ObjectType,
ObjectClassification, FunctionArgs, CandidateSet,
SuppressUserConversions, PartialOverloading);
}
} else {
if (Args.size() > 0 &&
(!Args[0] || (FirstArgumentIsBase && isa<CXXMethodDecl>(FD) &&
!isa<CXXConstructorDecl>(FD)))) {
assert(cast<CXXMethodDecl>(FD)->isStatic());
FunctionArgs = Args.slice(1);
}
if (FunTmpl) {
AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
ExplicitTemplateArgs, FunctionArgs,
CandidateSet, SuppressUserConversions,
PartialOverloading);
} else {
AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet,
SuppressUserConversions, PartialOverloading);
}
}
}
}
void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType,
Expr::Classification ObjectClassification,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
OverloadCandidateParamOrder PO) {
NamedDecl *Decl = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext());
if (isa<UsingShadowDecl>(Decl))
Decl = cast<UsingShadowDecl>(Decl)->getTargetDecl();
if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) {
assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
"Expected a member function template");
AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
nullptr, ObjectType,
ObjectClassification, Args, CandidateSet,
SuppressUserConversions, false, PO);
} else {
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
ObjectType, ObjectClassification, Args, CandidateSet,
SuppressUserConversions, false, std::nullopt, PO);
}
}
void
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
bool PartialOverloading,
ConversionSequenceList EarlyConversions,
OverloadCandidateParamOrder PO) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
assert(!isa<CXXConstructorDecl>(Method) &&
"Use AddOverloadCandidate for constructors");
if (!CandidateSet.isNewCandidate(Method, PO))
return;
if (Method->isDefaulted() && Method->isDeleted() &&
Method->isMoveAssignmentOperator())
return;
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Args.size() + 1, EarlyConversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Method;
Candidate.RewriteKind =
CandidateSet.getRewriteInfo().getRewriteKind(Method, PO);
Candidate.TookAddressOfOverload =
CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
Candidate.ExplicitCallArguments = Args.size();
bool IgnoreExplicitObject =
(Method->isExplicitObjectMemberFunction() &&
CandidateSet.getKind() ==
OverloadCandidateSet::CSK_AddressOfOverloadSet);
bool ImplicitObjectMethodTreatedAsStatic =
CandidateSet.getKind() ==
OverloadCandidateSet::CSK_AddressOfOverloadSet &&
Method->isImplicitObjectMemberFunction();
unsigned ExplicitOffset =
!IgnoreExplicitObject && Method->isExplicitObjectMemberFunction() ? 1 : 0;
unsigned NumParams = Method->getNumParams() - ExplicitOffset +
int(ImplicitObjectMethodTreatedAsStatic);
if (TooManyArguments(NumParams, Args.size(), PartialOverloading) &&
!Proto->isVariadic() &&
shouldEnforceArgLimit(PartialOverloading, Method)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
unsigned MinRequiredArgs = Method->getMinRequiredArguments() -
ExplicitOffset +
int(ImplicitObjectMethodTreatedAsStatic);
if (Args.size() < MinRequiredArgs && !PartialOverloading) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
Candidate.Viable = true;
unsigned FirstConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
if (ObjectType.isNull())
Candidate.IgnoreObjectArgument = true;
else if (Method->isStatic()) {
Candidate.Conversions[FirstConvIdx].setStaticObjectArgument();
} else {
Candidate.Conversions[FirstConvIdx] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
Method, ActingContext, true);
if (Candidate.Conversions[FirstConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
}
if (getLangOpts().CUDA)
if (!CUDA().IsAllowedCall(getCurFunctionDecl(true),
Method)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_target;
return;
}
if (Method->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
if (CheckFunctionConstraints(Method, Satisfaction, {},
true) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
return;
}
}
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
unsigned ConvIdx =
PO == OverloadCandidateParamOrder::Reversed ? 0 : (ArgIdx + 1);
if (Candidate.Conversions[ConvIdx].isInitialized()) {
} else if (ArgIdx < NumParams) {
QualType ParamType;
if (ImplicitObjectMethodTreatedAsStatic) {
ParamType = ArgIdx == 0
? Method->getFunctionObjectParameterReferenceType()
: Proto->getParamType(ArgIdx - 1);
} else {
ParamType = Proto->getParamType(ArgIdx + ExplicitOffset);
}
Candidate.Conversions[ConvIdx]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
SuppressUserConversions,
true,
getLangOpts().ObjCAutoRefCount);
if (Candidate.Conversions[ConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
} else {
Candidate.Conversions[ConvIdx].setEllipsis();
}
}
if (EnableIfAttr *FailedAttr =
CheckEnableIf(Method, CandidateSet.getLocation(), Args, true)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
if (isNonViableMultiVersionOverload(Method)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_non_default_multiversion_function;
}
}
void Sema::AddMethodTemplateCandidate(
FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType,
Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
bool PartialOverloading, OverloadCandidateParamOrder PO) {
if (!CandidateSet.isNewCandidate(MethodTmpl, PO))
return;
TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = nullptr;
ConversionSequenceList Conversions;
if (TemplateDeductionResult Result = DeduceTemplateArguments(
MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info,
PartialOverloading, false, ObjectType,
ObjectClassification,
[&](ArrayRef<QualType> ParamTypes) {
return CheckNonDependentConversions(
MethodTmpl, ParamTypes, Args, CandidateSet, Conversions,
SuppressUserConversions, ActingContext, ObjectType,
ObjectClassification, PO);
});
Result != TemplateDeductionResult::Success) {
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = MethodTmpl->getTemplatedDecl();
Candidate.Viable = false;
Candidate.RewriteKind =
CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument =
cast<CXXMethodDecl>(Candidate.Function)->isStatic() ||
ObjectType.isNull();
Candidate.ExplicitCallArguments = Args.size();
if (Result == TemplateDeductionResult::NonDependentConversionFailure)
Candidate.FailureKind = ovl_fail_bad_conversion;
else {
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
Info);
}
return;
}
assert(Specialization && "Missing member function template specialization?");
assert(isa<CXXMethodDecl>(Specialization) &&
"Specialization is not a member function?");
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, ObjectClassification, Args,
CandidateSet, SuppressUserConversions, PartialOverloading,
Conversions, PO);
}
static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) {
return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit();
}
void Sema::AddTemplateOverloadCandidate(
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate,
OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) {
if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))
return;
if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) {
OverloadCandidate &Candidate = CandidateSet.addCandidate();
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_explicit;
return;
}
TemplateDeductionInfo Info(CandidateSet.getLocation(),
FunctionTemplate->getTemplateDepth());
FunctionDecl *Specialization = nullptr;
ConversionSequenceList Conversions;
if (TemplateDeductionResult Result = DeduceTemplateArguments(
FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,
PartialOverloading, AggregateCandidateDeduction,
QualType(),
Expr::Classification(),
[&](ArrayRef<QualType> ParamTypes) {
return CheckNonDependentConversions(
FunctionTemplate, ParamTypes, Args, CandidateSet, Conversions,
SuppressUserConversions, nullptr, QualType(), {}, PO);
});
Result != TemplateDeductionResult::Success) {
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
Candidate.RewriteKind =
CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);
Candidate.IsSurrogate = false;
Candidate.IsADLCandidate = IsADLCandidate;
Candidate.IgnoreObjectArgument =
isa<CXXMethodDecl>(Candidate.Function) &&
!isa<CXXConstructorDecl>(Candidate.Function);
Candidate.ExplicitCallArguments = Args.size();
if (Result == TemplateDeductionResult::NonDependentConversionFailure)
Candidate.FailureKind = ovl_fail_bad_conversion;
else {
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
Info);
}
return;
}
assert(Specialization && "Missing function template specialization?");
AddOverloadCandidate(
Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
PartialOverloading, AllowExplicit,
false, IsADLCandidate, Conversions, PO,
Info.AggregateDeductionCandidateHasMismatchedArity);
}
bool Sema::CheckNonDependentConversions(
FunctionTemplateDecl *FunctionTemplate, ArrayRef<QualType> ParamTypes,
ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet,
ConversionSequenceList &Conversions, bool SuppressUserConversions,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification, OverloadCandidateParamOrder PO) {
const bool AllowExplicit = false;
auto *FD = FunctionTemplate->getTemplatedDecl();
auto *Method = dyn_cast<CXXMethodDecl>(FD);
bool HasThisConversion = Method && !isa<CXXConstructorDecl>(Method);
unsigned ThisConversions = HasThisConversion ? 1 : 0;
Conversions =
CandidateSet.allocateConversionSequences(ThisConversions + Args.size());
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
if (HasThisConversion && !cast<CXXMethodDecl>(FD)->isStatic() &&
!ObjectType.isNull()) {
unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
if (!FD->hasCXXExplicitFunctionObjectParameter() ||
!ParamTypes[0]->isDependentType()) {
Conversions[ConvIdx] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
Method, ActingContext, true,
FD->hasCXXExplicitFunctionObjectParameter() ? ParamTypes[0]
: QualType());
if (Conversions[ConvIdx].isBad())
return true;
}
}
unsigned Offset =
Method && Method->hasCXXExplicitFunctionObjectParameter() ? 1 : 0;
for (unsigned I = 0, N = std::min(ParamTypes.size() - Offset, Args.size());
I != N; ++I) {
QualType ParamType = ParamTypes[I + Offset];
if (!ParamType->isDependentType()) {
unsigned ConvIdx;
if (PO == OverloadCandidateParamOrder::Reversed) {
ConvIdx = Args.size() - 1 - I;
assert(Args.size() + ThisConversions == 2 &&
"number of args (including 'this') must be exactly 2 for "
"reversed order");
assert(!HasThisConversion || (ConvIdx == 0 && I == 0));
} else {
ConvIdx = ThisConversions + I;
}
Conversions[ConvIdx]
= TryCopyInitialization(*this, Args[I], ParamType,
SuppressUserConversions,
true,
getLangOpts().ObjCAutoRefCount,
AllowExplicit);
if (Conversions[ConvIdx].isBad())
return true;
}
}
return false;
}
static bool isAllowableExplicitConversion(Sema &S,
QualType ConvType, QualType ToType,
bool AllowObjCPointerConversion) {
QualType ToNonRefType = ToType.getNonReferenceType();
if (S.Context.hasSameUnqualifiedType(ConvType, ToNonRefType))
return true;
bool ObjCLifetimeConversion;
if (S.IsQualificationConversion(ConvType, ToNonRefType, false,
ObjCLifetimeConversion))
return true;
if (!AllowObjCPointerConversion)
return false;
bool IncompatibleObjC = false;
QualType ConvertedType;
return S.isObjCPointerConversion(ConvType, ToNonRefType, ConvertedType,
IncompatibleObjC);
}
void Sema::AddConversionCandidate(
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
bool AllowExplicit, bool AllowResultConversion) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
if (!CandidateSet.isNewCandidate(Conversion))
return;
if (getLangOpts().CPlusPlus14 && ConvType->isUndeducedType()) {
if (DeduceReturnType(Conversion, From->getExprLoc()))
return;
ConvType = Conversion->getConversionType().getNonReferenceType();
}
if (!AllowResultConversion &&
!Context.hasSameUnqualifiedType(Conversion->getConversionType(), ToType))
return;
if (Conversion->isExplicit() &&
!isAllowableExplicitConversion(*this, ConvType, ToType,
AllowObjCConversionOnExplicit))
return;
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
OverloadCandidate &Candidate = CandidateSet.addCandidate(1);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Conversion;
Candidate.FinalConversion.setAsIdentityConversion();
Candidate.FinalConversion.setFromType(ConvType);
Candidate.FinalConversion.setAllToTypes(ToType);
Candidate.Viable = true;
Candidate.ExplicitCallArguments = 1;
if (!AllowExplicit && Conversion->isExplicit()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_explicit;
return;
}
QualType ObjectType = From->getType();
if (const auto *FromPtrType = ObjectType->getAs<PointerType>())
ObjectType = FromPtrType->getPointeeType();
const auto *ConversionContext =
cast<CXXRecordDecl>(ObjectType->castAs<RecordType>()->getDecl());
Candidate.Conversions[0] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), From->getType(),
From->Classify(Context), Conversion, ConversionContext,
false, QualType(),
true);
if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
if (Conversion->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
if (CheckFunctionConstraints(Conversion, Satisfaction) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
return;
}
}
QualType FromCanon
= Context.getCanonicalType(From->getType().getUnqualifiedType());
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
if (FromCanon == ToCanon ||
IsDerivedFrom(CandidateSet.getLocation(), FromCanon, ToCanon)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_trivial_conversion;
return;
}
DeclRefExpr ConversionRef(Context, Conversion, false, Conversion->getType(),
VK_LValue, From->getBeginLoc());
ImplicitCastExpr ConversionFn(ImplicitCastExpr::OnStack,
Context.getPointerType(Conversion->getType()),
CK_FunctionToPointerDecay, &ConversionRef,
VK_PRValue, FPOptionsOverride());
QualType ConversionType = Conversion->getConversionType();
if (!isCompleteType(From->getBeginLoc(), ConversionType)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_final_conversion;
return;
}
ExprValueKind VK = Expr::getValueKindForType(ConversionType);
QualType CallResultType = ConversionType.getNonLValueExprType(Context);
alignas(CallExpr) char Buffer[sizeof(CallExpr) + sizeof(Stmt *)];
CallExpr *TheTemporaryCall = CallExpr::CreateTemporary(
Buffer, &ConversionFn, CallResultType, VK, From->getBeginLoc());
ImplicitConversionSequence ICS =
TryCopyInitialization(*this, TheTemporaryCall, ToType,
true,
false,
false);
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
Candidate.FinalConversion = ICS.Standard;
if (Conversion->getPrimaryTemplate() &&
GetConversionRank(ICS.Standard.Second) != ICR_Exact_Match) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_final_conversion_not_exact;
return;
}
if (ToType->isRValueReferenceType() &&
ICS.Standard.First == ICK_Lvalue_To_Rvalue) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_final_conversion;
return;
}
break;
case ImplicitConversionSequence::BadConversion:
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_final_conversion;
return;
default:
llvm_unreachable(
"Can only end up with a standard conversion sequence or failure");
}
if (EnableIfAttr *FailedAttr =
CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
if (isNonViableMultiVersionOverload(Conversion)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_non_default_multiversion_function;
}
}
void Sema::AddTemplateConversionCandidate(
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingDC, Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
bool AllowExplicit, bool AllowResultConversion) {
assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
"Only conversion function templates permitted here");
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) {
OverloadCandidate &Candidate = CandidateSet.addCandidate();
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_explicit;
return;
}
QualType ObjectType = From->getType();
Expr::Classification ObjectClassification = From->Classify(getASTContext());
TemplateDeductionInfo Info(CandidateSet.getLocation());
CXXConversionDecl *Specialization = nullptr;
if (TemplateDeductionResult Result = DeduceTemplateArguments(
FunctionTemplate, ObjectType, ObjectClassification, ToType,
Specialization, Info);
Result != TemplateDeductionResult::Success) {
OverloadCandidate &Candidate = CandidateSet.addCandidate();
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.ExplicitCallArguments = 1;
Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
Info);
return;
}
assert(Specialization && "Missing function template specialization?");
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
CandidateSet, AllowObjCConversionOnExplicit,
AllowExplicit, AllowResultConversion);
}
void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
Expr *Object,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet) {
if (!CandidateSet.isNewCandidate(Conversion))
return;
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size() + 1);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = nullptr;
Candidate.Surrogate = Conversion;
Candidate.IsSurrogate = true;
Candidate.Viable = true;
Candidate.ExplicitCallArguments = Args.size();
ImplicitConversionSequence ObjectInit;
if (Conversion->hasCXXExplicitFunctionObjectParameter()) {
ObjectInit = TryCopyInitialization(*this, Object,
Conversion->getParamDecl(0)->getType(),
false,
true, false);
} else {
ObjectInit = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), Object->getType(),
Object->Classify(Context), Conversion, ActingContext);
}
if (ObjectInit.isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
Candidate.Conversions[0] = ObjectInit;
return;
}
Candidate.Conversions[0].setUserDefined();
Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard;
Candidate.Conversions[0].UserDefined.EllipsisConversion = false;
Candidate.Conversions[0].UserDefined.HadMultipleCandidates = false;
Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion;
Candidate.Conversions[0].UserDefined.FoundConversionFunction = FoundDecl;
Candidate.Conversions[0].UserDefined.After
= Candidate.Conversions[0].UserDefined.Before;
Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion();
unsigned NumParams = Proto->getNumParams();
if (Args.size() > NumParams && !Proto->isVariadic()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
if (Args.size() < NumParams) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) {
if (ArgIdx < NumParams) {
QualType ParamType = Proto->getParamType(ArgIdx);
Candidate.Conversions[ArgIdx + 1]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
false,
false,
getLangOpts().ObjCAutoRefCount);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
} else {
Candidate.Conversions[ArgIdx + 1].setEllipsis();
}
}
if (Conversion->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
if (CheckFunctionConstraints(Conversion, Satisfaction, {},
true) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
return;
}
}
if (EnableIfAttr *FailedAttr =
CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
}
void Sema::AddNonMemberOperatorCandidates(
const UnresolvedSetImpl &Fns, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
TemplateArgumentListInfo *ExplicitTemplateArgs) {
for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
NamedDecl *D = F.getDecl()->getUnderlyingDecl();
ArrayRef<Expr *> FunctionArgs = Args;
FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D);
FunctionDecl *FD =
FunTmpl ? FunTmpl->getTemplatedDecl() : cast<FunctionDecl>(D);
if (!CandidateSet.getRewriteInfo().isAcceptableCandidate(FD))
continue;
assert(!isa<CXXMethodDecl>(FD) &&
"unqualified operator lookup found a member function");
if (FunTmpl) {
AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs,
FunctionArgs, CandidateSet);
if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD))
AddTemplateOverloadCandidate(
FunTmpl, F.getPair(), ExplicitTemplateArgs,
{FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false,
true, ADLCallKind::NotADL, OverloadCandidateParamOrder::Reversed);
} else {
if (ExplicitTemplateArgs)
continue;
AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet);
if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD))
AddOverloadCandidate(
FD, F.getPair(), {FunctionArgs[1], FunctionArgs[0]}, CandidateSet,
false, false, true, false, ADLCallKind::NotADL, std::nullopt,
OverloadCandidateParamOrder::Reversed);
}
}
}
void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
OverloadCandidateParamOrder PO) {
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
QualType T1 = Args[0]->getType();
if (const RecordType *T1Rec = T1->getAs<RecordType>()) {
if (!isCompleteType(OpLoc, T1) && !T1Rec->isBeingDefined())
return;
if (!T1Rec->getDecl()->getDefinition())
return;
LookupResult Operators(*this, OpName, OpLoc, LookupOrdinaryName);
LookupQualifiedName(Operators, T1Rec->getDecl());
Operators.suppressAccessDiagnostics();
for (LookupResult::iterator Oper = Operators.begin(),
OperEnd = Operators.end();
Oper != OperEnd; ++Oper) {
if (Oper->getAsFunction() &&
PO == OverloadCandidateParamOrder::Reversed &&
!CandidateSet.getRewriteInfo().shouldAddReversed(
*this, {Args[1], Args[0]}, Oper->getAsFunction()))
continue;
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
Args[0]->Classify(Context), Args.slice(1),
CandidateSet, false, PO);
}
}
}
void Sema::AddBuiltinCandidate(QualType *ParamTys, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool IsAssignmentOperator,
unsigned NumContextualBoolArguments) {
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
Candidate.FoundDecl = DeclAccessPair::make(nullptr, AS_none);
Candidate.Function = nullptr;
std::copy(ParamTys, ParamTys + Args.size(), Candidate.BuiltinParamTypes);
Candidate.Viable = true;
Candidate.ExplicitCallArguments = Args.size();
for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) {
if (ArgIdx < NumContextualBoolArguments) {
assert(ParamTys[ArgIdx] == Context.BoolTy &&
"Contextual conversion to bool requires bool type");
Candidate.Conversions[ArgIdx]
= TryContextuallyConvertToBool(*this, Args[ArgIdx]);
} else {
Candidate.Conversions[ArgIdx]
= TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx],
ArgIdx == 0 && IsAssignmentOperator,
false,
getLangOpts().ObjCAutoRefCount);
}
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
}
}
namespace {
class BuiltinCandidateTypeSet {
typedef llvm::SmallSetVector<QualType, 8> TypeSet;
TypeSet PointerTypes;
TypeSet MemberPointerTypes;
TypeSet EnumerationTypes;
TypeSet VectorTypes;
TypeSet MatrixTypes;
TypeSet BitIntTypes;
bool HasNonRecordTypes;
bool HasArithmeticOrEnumeralTypes;
bool HasNullPtrType;
Sema &SemaRef;
ASTContext &Context;
bool AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
const Qualifiers &VisibleQuals);
bool AddMemberPointerWithMoreQualifiedTypeVariants(QualType Ty);
public:
typedef TypeSet::iterator iterator;
BuiltinCandidateTypeSet(Sema &SemaRef)
: HasNonRecordTypes(false),
HasArithmeticOrEnumeralTypes(false),
HasNullPtrType(false),
SemaRef(SemaRef),
Context(SemaRef.Context) { }
void AddTypesConvertedFrom(QualType Ty,
SourceLocation Loc,
bool AllowUserConversions,
bool AllowExplicitConversions,
const Qualifiers &VisibleTypeConversionsQuals);
llvm::iterator_range<iterator> pointer_types() { return PointerTypes; }
llvm::iterator_range<iterator> member_pointer_types() {
return MemberPointerTypes;
}
llvm::iterator_range<iterator> enumeration_types() {
return EnumerationTypes;
}
llvm::iterator_range<iterator> vector_types() { return VectorTypes; }
llvm::iterator_range<iterator> matrix_types() { return MatrixTypes; }
llvm::iterator_range<iterator> bitint_types() { return BitIntTypes; }
bool containsMatrixType(QualType Ty) const { return MatrixTypes.count(Ty); }
bool hasNonRecordTypes() { return HasNonRecordTypes; }
bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; }
bool hasNullPtrType() const { return HasNullPtrType; }
};
}
bool
BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
const Qualifiers &VisibleQuals) {
if (!PointerTypes.insert(Ty))
return false;
QualType PointeeTy;
const PointerType *PointerTy = Ty->getAs<PointerType>();
bool buildObjCPtr = false;
if (!PointerTy) {
const ObjCObjectPointerType *PTy = Ty->castAs<ObjCObjectPointerType>();
PointeeTy = PTy->getPointeeType();
buildObjCPtr = true;
} else {
PointeeTy = PointerTy->getPointeeType();
}
if (PointeeTy->isArrayType())
return true;
unsigned BaseCVR = PointeeTy.getCVRQualifiers();
bool hasVolatile = VisibleQuals.hasVolatile();
bool hasRestrict = VisibleQuals.hasRestrict();
for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) {
if ((CVR | BaseCVR) != CVR) continue;
if ((CVR & Qualifiers::Volatile) && !hasVolatile) continue;
if ((CVR & Qualifiers::Restrict) &&
(!hasRestrict ||
(!(PointeeTy->isAnyPointerType() || PointeeTy->isReferenceType()))))
continue;
QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR);
QualType QPointerTy;
if (!buildObjCPtr)
QPointerTy = Context.getPointerType(QPointeeTy);
else
QPointerTy = Context.getObjCObjectPointerType(QPointeeTy);
PointerTypes.insert(QPointerTy);
}
return true;
}
bool
BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants(
QualType Ty) {
if (!MemberPointerTypes.insert(Ty))
return false;
const MemberPointerType *PointerTy = Ty->getAs<MemberPointerType>();
assert(PointerTy && "type was not a member pointer type!");
QualType PointeeTy = PointerTy->getPointeeType();
if (PointeeTy->isArrayType())
return true;
const Type *ClassTy = PointerTy->getClass();
unsigned BaseCVR = PointeeTy.getCVRQualifiers();
for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) {
if ((CVR | BaseCVR) != CVR) continue;
QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR);
MemberPointerTypes.insert(
Context.getMemberPointerType(QPointeeTy, ClassTy));
}
return true;
}
void
BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
SourceLocation Loc,
bool AllowUserConversions,
bool AllowExplicitConversions,
const Qualifiers &VisibleQuals) {
Ty = Context.getCanonicalType(Ty);
if (const ReferenceType *RefTy = Ty->getAs<ReferenceType>())
Ty = RefTy->getPointeeType();
if (Ty->isArrayType())
Ty = SemaRef.Context.getArrayDecayedType(Ty);
Ty = Ty.getLocalUnqualifiedType();
const RecordType *TyRec = Ty->getAs<RecordType>();
HasNonRecordTypes = HasNonRecordTypes || !TyRec;
HasArithmeticOrEnumeralTypes =
HasArithmeticOrEnumeralTypes || Ty->isArithmeticType();
if (Ty->isObjCIdType() || Ty->isObjCClassType())
PointerTypes.insert(Ty);
else if (Ty->getAs<PointerType>() || Ty->getAs<ObjCObjectPointerType>()) {
if (!AddPointerWithMoreQualifiedTypeVariants(Ty, VisibleQuals))
return;
} else if (Ty->isMemberPointerType()) {
if (!AddMemberPointerWithMoreQualifiedTypeVariants(Ty))
return;
} else if (Ty->isEnumeralType()) {
HasArithmeticOrEnumeralTypes = true;
EnumerationTypes.insert(Ty);
} else if (Ty->isBitIntType()) {
HasArithmeticOrEnumeralTypes = true;
BitIntTypes.insert(Ty);
} else if (Ty->isVectorType()) {
HasArithmeticOrEnumeralTypes = true;
VectorTypes.insert(Ty);
} else if (Ty->isMatrixType()) {
HasArithmeticOrEnumeralTypes = true;
MatrixTypes.insert(Ty);
} else if (Ty->isNullPtrType()) {
HasNullPtrType = true;
} else if (AllowUserConversions && TyRec) {
if (!SemaRef.isCompleteType(Loc, Ty))
return;
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) {
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
if (isa<FunctionTemplateDecl>(D))
continue;
CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
if (AllowExplicitConversions || !Conv->isExplicit()) {
AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false,
VisibleQuals);
}
}
}
}
static QualType AdjustAddressSpaceForBuiltinOperandType(Sema &S, QualType T,
Expr *Arg) {
return S.Context.getAddrSpaceQualType(T, Arg->getType().getAddressSpace());
}
static void AddBuiltinAssignmentOperatorCandidates(Sema &S,
QualType T,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet) {
QualType ParamTypes[2];
ParamTypes[0] = S.Context.getLValueReferenceType(
AdjustAddressSpaceForBuiltinOperandType(S, T, Args[0]));
ParamTypes[1] = T;
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
true);
if (!S.Context.getCanonicalType(T).isVolatileQualified()) {
ParamTypes[0] = S.Context.getLValueReferenceType(
AdjustAddressSpaceForBuiltinOperandType(S, S.Context.getVolatileType(T),
Args[0]));
ParamTypes[1] = T;
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
true);
}
}
static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
Qualifiers VRQuals;
const RecordType *TyRec;
if (const MemberPointerType *RHSMPType =
ArgExpr->getType()->getAs<MemberPointerType>())
TyRec = RHSMPType->getClass()->getAs<RecordType>();
else
TyRec = ArgExpr->getType()->getAs<RecordType>();
if (!TyRec) {
VRQuals.addVolatile();
VRQuals.addRestrict();
return VRQuals;
}
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
if (!ClassDecl->hasDefinition())
return VRQuals;
for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) {
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D)) {
QualType CanTy = Context.getCanonicalType(Conv->getConversionType());
if (const ReferenceType *ResTypeRef = CanTy->getAs<ReferenceType>())
CanTy = ResTypeRef->getPointeeType();
bool done = false;
while (!done) {
if (CanTy.isRestrictQualified())
VRQuals.addRestrict();
if (const PointerType *ResTypePtr = CanTy->getAs<PointerType>())
CanTy = ResTypePtr->getPointeeType();
else if (const MemberPointerType *ResTypeMPtr =
CanTy->getAs<MemberPointerType>())
CanTy = ResTypeMPtr->getPointeeType();
else
done = true;
if (CanTy.isVolatileQualified())
VRQuals.addVolatile();
if (VRQuals.hasRestrict() && VRQuals.hasVolatile())
return VRQuals;
}
}
}
return VRQuals;
}
static void forAllQualifierCombinationsImpl(
QualifiersAndAtomic Available, QualifiersAndAtomic Applied,
llvm::function_ref<void(QualifiersAndAtomic)> Callback) {
if (Available.hasAtomic()) {
Available.removeAtomic();
forAllQualifierCombinationsImpl(Available, Applied.withAtomic(), Callback);
forAllQualifierCombinationsImpl(Available, Applied, Callback);
return;
}
if (Available.hasVolatile()) {
Available.removeVolatile();
assert(!Applied.hasVolatile());
forAllQualifierCombinationsImpl(Available, Applied.withVolatile(),
Callback);
forAllQualifierCombinationsImpl(Available, Applied, Callback);
return;
}
Callback(Applied);
}
static void forAllQualifierCombinations(
QualifiersAndAtomic Quals,
llvm::function_ref<void(QualifiersAndAtomic)> Callback) {
return forAllQualifierCombinationsImpl(Quals, QualifiersAndAtomic(),
Callback);
}
static QualType makeQualifiedLValueReferenceType(QualType Base,
QualifiersAndAtomic Quals,
Sema &S) {
if (Quals.hasAtomic())
Base = S.Context.getAtomicType(Base);
if (Quals.hasVolatile())
Base = S.Context.getVolatileType(Base);
return S.Context.getLValueReferenceType(Base);
}
namespace {
class BuiltinOperatorOverloadBuilder {
Sema &S;
ArrayRef<Expr *> Args;
QualifiersAndAtomic VisibleTypeConversionsQuals;
bool HasArithmeticOrEnumeralCandidateType;
SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes;
OverloadCandidateSet &CandidateSet;
static constexpr int ArithmeticTypesCap = 26;
SmallVector<CanQualType, ArithmeticTypesCap> ArithmeticTypes;
unsigned FirstIntegralType,
LastIntegralType;
unsigned FirstPromotedIntegralType,
LastPromotedIntegralType;
unsigned FirstPromotedArithmeticType,
LastPromotedArithmeticType;
unsigned NumArithmeticTypes;
void InitArithmeticTypes() {
FirstPromotedArithmeticType = 0;
ArithmeticTypes.push_back(S.Context.FloatTy);
ArithmeticTypes.push_back(S.Context.DoubleTy);
ArithmeticTypes.push_back(S.Context.LongDoubleTy);
if (S.Context.getTargetInfo().hasFloat128Type())
ArithmeticTypes.push_back(S.Context.Float128Ty);
if (S.Context.getTargetInfo().hasIbm128Type())
ArithmeticTypes.push_back(S.Context.Ibm128Ty);
FirstIntegralType = ArithmeticTypes.size();
FirstPromotedIntegralType = ArithmeticTypes.size();
ArithmeticTypes.push_back(S.Context.IntTy);
ArithmeticTypes.push_back(S.Context.LongTy);
ArithmeticTypes.push_back(S.Context.LongLongTy);
if (S.Context.getTargetInfo().hasInt128Type() ||
(S.Context.getAuxTargetInfo() &&
S.Context.getAuxTargetInfo()->hasInt128Type()))
ArithmeticTypes.push_back(S.Context.Int128Ty);
ArithmeticTypes.push_back(S.Context.UnsignedIntTy);
ArithmeticTypes.push_back(S.Context.UnsignedLongTy);
ArithmeticTypes.push_back(S.Context.UnsignedLongLongTy);
if (S.Context.getTargetInfo().hasInt128Type() ||
(S.Context.getAuxTargetInfo() &&
S.Context.getAuxTargetInfo()->hasInt128Type()))
ArithmeticTypes.push_back(S.Context.UnsignedInt128Ty);
llvm::SmallSetVector<CanQualType, 2> BitIntCandidates;
llvm::for_each(CandidateTypes, [&BitIntCandidates](
BuiltinCandidateTypeSet &Candidate) {
for (QualType BitTy : Candidate.bitint_types())
BitIntCandidates.insert(CanQualType::CreateUnsafe(BitTy));
});
llvm::move(BitIntCandidates, std::back_inserter(ArithmeticTypes));
LastPromotedIntegralType = ArithmeticTypes.size();
LastPromotedArithmeticType = ArithmeticTypes.size();
ArithmeticTypes.push_back(S.Context.BoolTy);
ArithmeticTypes.push_back(S.Context.CharTy);
ArithmeticTypes.push_back(S.Context.WCharTy);
if (S.Context.getLangOpts().Char8)
ArithmeticTypes.push_back(S.Context.Char8Ty);
ArithmeticTypes.push_back(S.Context.Char16Ty);
ArithmeticTypes.push_back(S.Context.Char32Ty);
ArithmeticTypes.push_back(S.Context.SignedCharTy);
ArithmeticTypes.push_back(S.Context.ShortTy);
ArithmeticTypes.push_back(S.Context.UnsignedCharTy);
ArithmeticTypes.push_back(S.Context.UnsignedShortTy);
LastIntegralType = ArithmeticTypes.size();
NumArithmeticTypes = ArithmeticTypes.size();
assert(ArithmeticTypes.size() - BitIntCandidates.size() <=
ArithmeticTypesCap &&
"Enough inline storage for all arithmetic types.");
}
void addPlusPlusMinusMinusStyleOverloads(QualType CandidateTy,
bool HasVolatile,
bool HasRestrict) {
QualType ParamTypes[2] = {
S.Context.getLValueReferenceType(CandidateTy),
S.Context.IntTy
};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
if (HasVolatile) {
ParamTypes[0] =
S.Context.getLValueReferenceType(
S.Context.getVolatileType(CandidateTy));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
if (HasRestrict && CandidateTy->isAnyPointerType() &&
!CandidateTy.isRestrictQualified()) {
ParamTypes[0]
= S.Context.getLValueReferenceType(
S.Context.getCVRQualifiedType(CandidateTy, Qualifiers::Restrict));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
if (HasVolatile) {
ParamTypes[0]
= S.Context.getLValueReferenceType(
S.Context.getCVRQualifiedType(CandidateTy,
(Qualifiers::Volatile |
Qualifiers::Restrict)));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
void AddCandidate(QualType L, QualType R) {
QualType LandR[2] = {L, R};
S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
public:
BuiltinOperatorOverloadBuilder(
Sema &S, ArrayRef<Expr *> Args,
QualifiersAndAtomic VisibleTypeConversionsQuals,
bool HasArithmeticOrEnumeralCandidateType,
SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes,
OverloadCandidateSet &CandidateSet)
: S(S), Args(Args),
VisibleTypeConversionsQuals(VisibleTypeConversionsQuals),
HasArithmeticOrEnumeralCandidateType(
HasArithmeticOrEnumeralCandidateType),
CandidateTypes(CandidateTypes),
CandidateSet(CandidateSet) {
InitArithmeticTypes();
}
void addPlusPlusMinusMinusArithmeticOverloads(OverloadedOperatorKind Op) {
if (!HasArithmeticOrEnumeralCandidateType)
return;
for (unsigned Arith = 0; Arith < NumArithmeticTypes; ++Arith) {
const auto TypeOfT = ArithmeticTypes[Arith];
if (TypeOfT == S.Context.BoolTy) {
if (Op == OO_MinusMinus)
continue;
if (Op == OO_PlusPlus && S.getLangOpts().CPlusPlus17)
continue;
}
addPlusPlusMinusMinusStyleOverloads(
TypeOfT,
VisibleTypeConversionsQuals.hasVolatile(),
VisibleTypeConversionsQuals.hasRestrict());
}
}
void addPlusPlusMinusMinusPointerOverloads() {
for (QualType PtrTy : CandidateTypes[0].pointer_types()) {
if (!PtrTy->getPointeeType()->isObjectType())
continue;
addPlusPlusMinusMinusStyleOverloads(
PtrTy,
(!PtrTy.isVolatileQualified() &&
VisibleTypeConversionsQuals.hasVolatile()),
(!PtrTy.isRestrictQualified() &&
VisibleTypeConversionsQuals.hasRestrict()));
}
}
void addUnaryStarPointerOverloads() {
for (QualType ParamTy : CandidateTypes[0].pointer_types()) {
QualType PointeeTy = ParamTy->getPointeeType();
if (!PointeeTy->isObjectType() && !PointeeTy->isFunctionType())
continue;
if (const FunctionProtoType *Proto =PointeeTy->getAs<FunctionProtoType>())
if (Proto->getMethodQuals() || Proto->getRefQualifier())
continue;
S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet);
}
}
void addUnaryPlusOrMinusArithmeticOverloads() {
if (!HasArithmeticOrEnumeralCandidateType)
return;
for (unsigned Arith = FirstPromotedArithmeticType;
Arith < LastPromotedArithmeticType; ++Arith) {
QualType ArithTy = ArithmeticTypes[Arith];
S.AddBuiltinCandidate(&ArithTy, Args, CandidateSet);
}
for (QualType VecTy : CandidateTypes[0].vector_types())
S.AddBuiltinCandidate(&VecTy, Args, CandidateSet);
}
void addUnaryPlusPointerOverloads() {
for (QualType ParamTy : CandidateTypes[0].pointer_types())
S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet);
}
void addUnaryTildePromotedIntegralOverloads() {
if (!HasArithmeticOrEnumeralCandidateType)
return;
for (unsigned Int = FirstPromotedIntegralType;
Int < LastPromotedIntegralType; ++Int) {
QualType IntTy = ArithmeticTypes[Int];
S.AddBuiltinCandidate(&IntTy, Args, CandidateSet);
}
for (QualType VecTy : CandidateTypes[0].vector_types())
S.AddBuiltinCandidate(&VecTy, Args, CandidateSet);
}
void addEqualEqualOrNotEqualMemberPointerOrNullptrOverloads() {
llvm::SmallPtrSet<QualType, 8> AddedTypes;
for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) {
for (QualType MemPtrTy : CandidateTypes[ArgIdx].member_pointer_types()) {
if (!AddedTypes.insert(S.Context.getCanonicalType(MemPtrTy)).second)
continue;
QualType ParamTypes[2] = {MemPtrTy, MemPtrTy};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
if (CandidateTypes[ArgIdx].hasNullPtrType()) {
CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy);
if (AddedTypes.insert(NullPtrTy).second) {
QualType ParamTypes[2] = { NullPtrTy, NullPtrTy };
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
}
void addGenericBinaryPointerOrEnumeralOverloads(bool IsSpaceship) {
llvm::DenseSet<std::pair<CanQualType, CanQualType> >
UserDefinedBinaryOperators;
for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) {
if (!CandidateTypes[ArgIdx].enumeration_types().empty()) {
for (OverloadCandidateSet::iterator C = CandidateSet.begin(),
CEnd = CandidateSet.end();
C != CEnd; ++C) {
if (!C->Viable || !C->Function || C->Function->getNumParams() != 2)
continue;
if (C->Function->isFunctionTemplateSpecialization())
continue;
bool Reversed = C->isReversed();
QualType FirstParamType = C->Function->getParamDecl(Reversed ? 1 : 0)
->getType()
.getUnqualifiedType();
QualType SecondParamType = C->Function->getParamDecl(Reversed ? 0 : 1)
->getType()
.getUnqualifiedType();
if (!FirstParamType->isEnumeralType() ||
!SecondParamType->isEnumeralType())
continue;
UserDefinedBinaryOperators.insert(
std::make_pair(S.Context.getCanonicalType(FirstParamType),
S.Context.getCanonicalType(SecondParamType)));
}
}
}
llvm::SmallPtrSet<QualType, 8> AddedTypes;
for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) {
for (QualType PtrTy : CandidateTypes[ArgIdx].pointer_types()) {
if (!AddedTypes.insert(S.Context.getCanonicalType(PtrTy)).second)
continue;
if (IsSpaceship && PtrTy->isFunctionPointerType())
continue;
QualType ParamTypes[2] = {PtrTy, PtrTy};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
for (QualType EnumTy : CandidateTypes[ArgIdx].enumeration_types()) {
CanQualType CanonType = S.Context.getCanonicalType(EnumTy);
if (!AddedTypes.insert(CanonType).second ||
UserDefinedBinaryOperators.count(std::make_pair(CanonType,
CanonType)))
continue;
QualType ParamTypes[2] = {EnumTy, EnumTy};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
void addBinaryPlusOrMinusPointerOverloads(OverloadedOperatorKind Op) {
llvm::SmallPtrSet<QualType, 8> AddedTypes;
for (int Arg = 0; Arg < 2; ++Arg) {
QualType AsymmetricParamTypes[2] = {
S.Context.getPointerDiffType(),
S.Context.getPointerDiffType(),
};
for (QualType PtrTy : CandidateTypes[Arg].pointer_types()) {
QualType PointeeTy = PtrTy->getPointeeType();
if (!PointeeTy->isObjectType())
continue;
AsymmetricParamTypes[Arg] = PtrTy;
if (Arg == 0 || Op == OO_Plus) {
S.AddBuiltinCandidate(AsymmetricParamTypes, Args, CandidateSet);
}
if (Op == OO_Minus) {
if (!AddedTypes.insert(S.Context.getCanonicalType(PtrTy)).second)
continue;
QualType ParamTypes[2] = {PtrTy, PtrTy};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
}
void addGenericBinaryArithmeticOverloads() {
if (!HasArithmeticOrEnumeralCandidateType)
return;
for (unsigned Left = FirstPromotedArithmeticType;
Left < LastPromotedArithmeticType; ++Left) {
for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
QualType LandR[2] = { ArithmeticTypes[Left],
ArithmeticTypes[Right] };
S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
for (QualType Vec1Ty : CandidateTypes[0].vector_types())
for (QualType Vec2Ty : CandidateTypes[1].vector_types()) {
QualType LandR[2] = {Vec1Ty, Vec2Ty};
S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
void addMatrixBinaryArithmeticOverloads() {
if (!HasArithmeticOrEnumeralCandidateType)
return;
for (QualType M1 : CandidateTypes[0].matrix_types()) {
AddCandidate(M1, cast<MatrixType>(M1)->getElementType());
AddCandidate(M1, M1);
}
for (QualType M2 : CandidateTypes[1].matrix_types()) {
AddCandidate(cast<MatrixType>(M2)->getElementType(), M2);
if (!CandidateTypes[0].containsMatrixType(M2))
AddCandidate(M2, M2);
}
}
void addThreeWayArithmeticOverloads() {
addGenericBinaryArithmeticOverloads();
}
void addBinaryBitwiseArithmeticOverloads() {
if (!HasArithmeticOrEnumeralCandidateType)
return;
for (unsigned Left = FirstPromotedIntegralType;
Left < LastPromotedIntegralType; ++Left) {
for (unsigned Right = FirstPromotedIntegralType;
Right < LastPromotedIntegralType; ++Right) {
QualType LandR[2] = { ArithmeticTypes[Left],
ArithmeticTypes[Right] };
S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
}
void addAssignmentMemberPointerOrEnumeralOverloads() {
llvm::SmallPtrSet<QualType, 8> AddedTypes;
for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {
for (QualType EnumTy : CandidateTypes[ArgIdx].enumeration_types()) {
if (!AddedTypes.insert(S.Context.getCanonicalType(EnumTy)).second)
continue;
AddBuiltinAssignmentOperatorCandidates(S, EnumTy, Args, CandidateSet);
}
for (QualType MemPtrTy : CandidateTypes[ArgIdx].member_pointer_types()) {
if (!AddedTypes.insert(S.Context.getCanonicalType(MemPtrTy)).second)
continue;
AddBuiltinAssignmentOperatorCandidates(S, MemPtrTy, Args, CandidateSet);
}
}
}
void addAssignmentPointerOverloads(bool isEqualOp) {
llvm::SmallPtrSet<QualType, 8> AddedTypes;
for (QualType PtrTy : CandidateTypes[0].pointer_types()) {
if (isEqualOp)
AddedTypes.insert(S.Context.getCanonicalType(PtrTy));
else if (!PtrTy->getPointeeType()->isObjectType())
continue;
QualType ParamTypes[2] = {
S.Context.getLValueReferenceType(PtrTy),
isEqualOp ? PtrTy : S.Context.getPointerDiffType(),
};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
isEqualOp);
bool NeedVolatile = !PtrTy.isVolatileQualified() &&
VisibleTypeConversionsQuals.hasVolatile();
if (NeedVolatile) {
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getVolatileType(PtrTy));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
isEqualOp);
}
if (!PtrTy.isRestrictQualified() &&
VisibleTypeConversionsQuals.hasRestrict()) {
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getRestrictType(PtrTy));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
isEqualOp);
if (NeedVolatile) {
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getCVRQualifiedType(
PtrTy, (Qualifiers::Volatile | Qualifiers::Restrict)));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
isEqualOp);
}
}
}
if (isEqualOp) {
for (QualType PtrTy : CandidateTypes[1].pointer_types()) {
if (!AddedTypes.insert(S.Context.getCanonicalType(PtrTy)).second)
continue;
QualType ParamTypes[2] = {
S.Context.getLValueReferenceType(PtrTy),
PtrTy,
};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
true);
bool NeedVolatile = !PtrTy.isVolatileQualified() &&
VisibleTypeConversionsQuals.hasVolatile();
if (NeedVolatile) {
ParamTypes[0] = S.Context.getLValueReferenceType(
S.Context.getVolatileType(PtrTy));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
true);
}
if (!PtrTy.isRestrictQualified() &&
VisibleTypeConversionsQuals.hasRestrict()) {
ParamTypes[0] = S.Context.getLValueReferenceType(
S.Context.getRestrictType(PtrTy));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
true);
if (NeedVolatile) {
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getCVRQualifiedType(
PtrTy, (Qualifiers::Volatile | Qualifiers::Restrict)));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
true);
}
}
}
}
}
void addAssignmentArithmeticOverloads(bool isEqualOp) {
if (!HasArithmeticOrEnumeralCandidateType)
return;
for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) {
for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
QualType ParamTypes[2];
ParamTypes[1] = ArithmeticTypes[Right];
auto LeftBaseTy = AdjustAddressSpaceForBuiltinOperandType(
S, ArithmeticTypes[Left], Args[0]);
forAllQualifierCombinations(
VisibleTypeConversionsQuals, [&](QualifiersAndAtomic Quals) {
ParamTypes[0] =
makeQualifiedLValueReferenceType(LeftBaseTy, Quals, S);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
isEqualOp);
});
}
}
for (QualType Vec1Ty : CandidateTypes[0].vector_types())
for (QualType Vec2Ty : CandidateTypes[0].vector_types()) {
QualType ParamTypes[2];
ParamTypes[1] = Vec2Ty;
ParamTypes[0] = S.Context.getLValueReferenceType(Vec1Ty);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
isEqualOp);
if (VisibleTypeConversionsQuals.hasVolatile()) {
ParamTypes[0] = S.Context.getVolatileType(Vec1Ty);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
isEqualOp);
}
}
}
void addAssignmentIntegralOverloads() {
if (!HasArithmeticOrEnumeralCandidateType)
return;
for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) {
for (unsigned Right = FirstPromotedIntegralType;
Right < LastPromotedIntegralType; ++Right) {
QualType ParamTypes[2];
ParamTypes[1] = ArithmeticTypes[Right];
auto LeftBaseTy = AdjustAddressSpaceForBuiltinOperandType(
S, ArithmeticTypes[Left], Args[0]);
forAllQualifierCombinations(
VisibleTypeConversionsQuals, [&](QualifiersAndAtomic Quals) {
ParamTypes[0] =
makeQualifiedLValueReferenceType(LeftBaseTy, Quals, S);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
});
}
}
}
void addExclaimOverload() {
QualType ParamTy = S.Context.BoolTy;
S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet,
false,
1);
}
void addAmpAmpOrPipePipeOverload() {
QualType ParamTypes[2] = { S.Context.BoolTy, S.Context.BoolTy };
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
false,
2);
}
void addSubscriptOverloads() {
for (QualType PtrTy : CandidateTypes[0].pointer_types()) {
QualType ParamTypes[2] = {PtrTy, S.Context.getPointerDiffType()};
QualType PointeeType = PtrTy->getPointeeType();
if (!PointeeType->isObjectType())
continue;
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
for (QualType PtrTy : CandidateTypes[1].pointer_types()) {
QualType ParamTypes[2] = {S.Context.getPointerDiffType(), PtrTy};
QualType PointeeType = PtrTy->getPointeeType();
if (!PointeeType->isObjectType())
continue;
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
void addArrowStarOverloads() {
for (QualType PtrTy : CandidateTypes[0].pointer_types()) {
QualType C1Ty = PtrTy;
QualType C1;
QualifierCollector Q1;
C1 = QualType(Q1.strip(C1Ty->getPointeeType()), 0);
if (!isa<RecordType>(C1))
continue;
if (!VisibleTypeConversionsQuals.hasVolatile() && Q1.hasVolatile())
continue;
if (!VisibleTypeConversionsQuals.hasRestrict() && Q1.hasRestrict())
continue;
for (QualType MemPtrTy : CandidateTypes[1].member_pointer_types()) {
const MemberPointerType *mptr = cast<MemberPointerType>(MemPtrTy);
QualType C2 = QualType(mptr->getClass(), 0);
C2 = C2.getUnqualifiedType();
if (C1 != C2 && !S.IsDerivedFrom(CandidateSet.getLocation(), C1, C2))
break;
QualType ParamTypes[2] = {PtrTy, MemPtrTy};
QualType T = mptr->getPointeeType();
if (!VisibleTypeConversionsQuals.hasVolatile() &&
T.isVolatileQualified())
continue;
if (!VisibleTypeConversionsQuals.hasRestrict() &&
T.isRestrictQualified())
continue;
T = Q1.apply(S.Context, T);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
void addConditionalOperatorOverloads() {
llvm::SmallPtrSet<QualType, 8> AddedTypes;
for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {
for (QualType PtrTy : CandidateTypes[ArgIdx].pointer_types()) {
if (!AddedTypes.insert(S.Context.getCanonicalType(PtrTy)).second)
continue;
QualType ParamTypes[2] = {PtrTy, PtrTy};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
for (QualType MemPtrTy : CandidateTypes[ArgIdx].member_pointer_types()) {
if (!AddedTypes.insert(S.Context.getCanonicalType(MemPtrTy)).second)
continue;
QualType ParamTypes[2] = {MemPtrTy, MemPtrTy};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
if (S.getLangOpts().CPlusPlus11) {
for (QualType EnumTy : CandidateTypes[ArgIdx].enumeration_types()) {
if (!EnumTy->castAs<EnumType>()->getDecl()->isScoped())
continue;
if (!AddedTypes.insert(S.Context.getCanonicalType(EnumTy)).second)
continue;
QualType ParamTypes[2] = {EnumTy, EnumTy};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
}
};
}
void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet) {
QualifiersAndAtomic VisibleTypeConversionsQuals;
VisibleTypeConversionsQuals.addConst();
for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) {
VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]);
if (Args[ArgIdx]->getType()->isAtomicType())
VisibleTypeConversionsQuals.addAtomic();
}
bool HasNonRecordCandidateType = false;
bool HasArithmeticOrEnumeralCandidateType = false;
SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes;
for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) {
CandidateTypes.emplace_back(*this);
CandidateTypes[ArgIdx].AddTypesConvertedFrom(Args[ArgIdx]->getType(),
OpLoc,
true,
(Op == OO_Exclaim ||
Op == OO_AmpAmp ||
Op == OO_PipePipe),
VisibleTypeConversionsQuals);
HasNonRecordCandidateType = HasNonRecordCandidateType ||
CandidateTypes[ArgIdx].hasNonRecordTypes();
HasArithmeticOrEnumeralCandidateType =
HasArithmeticOrEnumeralCandidateType ||
CandidateTypes[ArgIdx].hasArithmeticOrEnumeralTypes();
}
if (!HasNonRecordCandidateType &&
!(Op == OO_Exclaim || Op == OO_AmpAmp || Op == OO_PipePipe))
return;
BuiltinOperatorOverloadBuilder OpBuilder(*this, Args,
VisibleTypeConversionsQuals,
HasArithmeticOrEnumeralCandidateType,
CandidateTypes, CandidateSet);
switch (Op) {
case OO_None:
case NUM_OVERLOADED_OPERATORS:
llvm_unreachable("Expected an overloaded operator");
case OO_New:
case OO_Delete:
case OO_Array_New:
case OO_Array_Delete:
case OO_Call:
llvm_unreachable(
"Special operators don't use AddBuiltinOperatorCandidates");
case OO_Comma:
case OO_Arrow:
case OO_Coawait:
break;
case OO_Plus:
if (Args.size() == 1)
OpBuilder.addUnaryPlusPointerOverloads();
[[fallthrough]];
case OO_Minus:
if (Args.size() == 1) {
OpBuilder.addUnaryPlusOrMinusArithmeticOverloads();
} else {
OpBuilder.addBinaryPlusOrMinusPointerOverloads(Op);
OpBuilder.addGenericBinaryArithmeticOverloads();
OpBuilder.addMatrixBinaryArithmeticOverloads();
}
break;
case OO_Star:
if (Args.size() == 1)
OpBuilder.addUnaryStarPointerOverloads();
else {
OpBuilder.addGenericBinaryArithmeticOverloads();
OpBuilder.addMatrixBinaryArithmeticOverloads();
}
break;
case OO_Slash:
OpBuilder.addGenericBinaryArithmeticOverloads();
break;
case OO_PlusPlus:
case OO_MinusMinus:
OpBuilder.addPlusPlusMinusMinusArithmeticOverloads(Op);
OpBuilder.addPlusPlusMinusMinusPointerOverloads();
break;
case OO_EqualEqual:
case OO_ExclaimEqual:
OpBuilder.addEqualEqualOrNotEqualMemberPointerOrNullptrOverloads();
OpBuilder.addGenericBinaryPointerOrEnumeralOverloads(false);
OpBuilder.addGenericBinaryArithmeticOverloads();
break;
case OO_Less:
case OO_Greater:
case OO_LessEqual:
case OO_GreaterEqual:
OpBuilder.addGenericBinaryPointerOrEnumeralOverloads(false);
OpBuilder.addGenericBinaryArithmeticOverloads();
break;
case OO_Spaceship:
OpBuilder.addGenericBinaryPointerOrEnumeralOverloads(true);
OpBuilder.addThreeWayArithmeticOverloads();
break;
case OO_Percent:
case OO_Caret:
case OO_Pipe:
case OO_LessLess:
case OO_GreaterGreater:
OpBuilder.addBinaryBitwiseArithmeticOverloads();
break;
case OO_Amp:
if (Args.size() == 1)
break;
OpBuilder.addBinaryBitwiseArithmeticOverloads();
break;
case OO_Tilde:
OpBuilder.addUnaryTildePromotedIntegralOverloads();
break;
case OO_Equal:
OpBuilder.addAssignmentMemberPointerOrEnumeralOverloads();
[[fallthrough]];
case OO_PlusEqual:
case OO_MinusEqual:
OpBuilder.addAssignmentPointerOverloads(Op == OO_Equal);
[[fallthrough]];
case OO_StarEqual:
case OO_SlashEqual:
OpBuilder.addAssignmentArithmeticOverloads(Op == OO_Equal);
break;
case OO_PercentEqual:
case OO_LessLessEqual:
case OO_GreaterGreaterEqual:
case OO_AmpEqual:
case OO_CaretEqual:
case OO_PipeEqual:
OpBuilder.addAssignmentIntegralOverloads();
break;
case OO_Exclaim:
OpBuilder.addExclaimOverload();
break;
case OO_AmpAmp:
case OO_PipePipe:
OpBuilder.addAmpAmpOrPipePipeOverload();
break;
case OO_Subscript:
if (Args.size() == 2)
OpBuilder.addSubscriptOverloads();
break;
case OO_ArrowStar:
OpBuilder.addArrowStarOverloads();
break;
case OO_Conditional:
OpBuilder.addConditionalOperatorOverloads();
OpBuilder.addGenericBinaryArithmeticOverloads();
break;
}
}
void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
SourceLocation Loc,
ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading) {
ADLResult Fns;
ArgumentDependentLookup(Name, Loc, Args, Fns);
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
CandEnd = CandidateSet.end();
Cand != CandEnd; ++Cand)
if (Cand->Function) {
Fns.erase(Cand->Function);
if (FunctionTemplateDecl *FunTmpl = Cand->Function->getPrimaryTemplate())
Fns.erase(FunTmpl);
}
for (ADLResult::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
DeclAccessPair FoundDecl = DeclAccessPair::make(*I, AS_none);
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
if (ExplicitTemplateArgs)
continue;
AddOverloadCandidate(
FD, FoundDecl, Args, CandidateSet, false,
PartialOverloading, true,
false, ADLCallKind::UsesADL);
if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) {
AddOverloadCandidate(
FD, FoundDecl, {Args[1], Args[0]}, CandidateSet,
false, PartialOverloading,
true, false,
ADLCallKind::UsesADL, std::nullopt,
OverloadCandidateParamOrder::Reversed);
}
} else {
auto *FTD = cast<FunctionTemplateDecl>(*I);
AddTemplateOverloadCandidate(
FTD, FoundDecl, ExplicitTemplateArgs, Args, CandidateSet,
false, PartialOverloading,
true, ADLCallKind::UsesADL);
if (CandidateSet.getRewriteInfo().shouldAddReversed(
*this, Args, FTD->getTemplatedDecl())) {
AddTemplateOverloadCandidate(
FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]},
CandidateSet, false, PartialOverloading,
true, ADLCallKind::UsesADL,
OverloadCandidateParamOrder::Reversed);
}
}
}
}
namespace {
enum class Comparison { Equal, Better, Worse };
}
static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1,
const FunctionDecl *Cand2) {
bool Cand1Attr = Cand1->hasAttr<EnableIfAttr>();
bool Cand2Attr = Cand2->hasAttr<EnableIfAttr>();
if (!Cand1Attr || !Cand2Attr) {
if (Cand1Attr == Cand2Attr)
return Comparison::Equal;
return Cand1Attr ? Comparison::Better : Comparison::Worse;
}
auto Cand1Attrs = Cand1->specific_attrs<EnableIfAttr>();
auto Cand2Attrs = Cand2->specific_attrs<EnableIfAttr>();
llvm::FoldingSetNodeID Cand1ID, Cand2ID;
for (auto Pair : zip_longest(Cand1Attrs, Cand2Attrs)) {
std::optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
std::optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
if (!Cand1A)
return Comparison::Worse;
if (!Cand2A)
return Comparison::Better;
Cand1ID.clear();
Cand2ID.clear();
(*Cand1A)->getCond()->Profile(Cand1ID, S.getASTContext(), true);
(*Cand2A)->getCond()->Profile(Cand2ID, S.getASTContext(), true);
if (Cand1ID != Cand2ID)
return Comparison::Worse;
}
return Comparison::Equal;
}
static Comparison
isBetterMultiversionCandidate(const OverloadCandidate &Cand1,
const OverloadCandidate &Cand2) {
if (!Cand1.Function || !Cand1.Function->isMultiVersion() || !Cand2.Function ||
!Cand2.Function->isMultiVersion())
return Comparison::Equal;
if (Cand1.Function->isInvalidDecl()) {
if (Cand2.Function->isInvalidDecl())
return Comparison::Equal;
return Comparison::Worse;
}
if (Cand2.Function->isInvalidDecl())
return Comparison::Better;
bool Cand1CPUDisp = Cand1.Function->hasAttr<CPUDispatchAttr>();
bool Cand2CPUDisp = Cand2.Function->hasAttr<CPUDispatchAttr>();
const auto *Cand1CPUSpec = Cand1.Function->getAttr<CPUSpecificAttr>();
const auto *Cand2CPUSpec = Cand2.Function->getAttr<CPUSpecificAttr>();
if (!Cand1CPUDisp && !Cand2CPUDisp && !Cand1CPUSpec && !Cand2CPUSpec)
return Comparison::Equal;
if (Cand1CPUDisp && !Cand2CPUDisp)
return Comparison::Better;
if (Cand2CPUDisp && !Cand1CPUDisp)
return Comparison::Worse;
if (Cand1CPUSpec && Cand2CPUSpec) {
if (Cand1CPUSpec->cpus_size() != Cand2CPUSpec->cpus_size())
return Cand1CPUSpec->cpus_size() < Cand2CPUSpec->cpus_size()
? Comparison::Better
: Comparison::Worse;
std::pair<CPUSpecificAttr::cpus_iterator, CPUSpecificAttr::cpus_iterator>
FirstDiff = std::mismatch(
Cand1CPUSpec->cpus_begin(), Cand1CPUSpec->cpus_end(),
Cand2CPUSpec->cpus_begin(),
[](const IdentifierInfo *LHS, const IdentifierInfo *RHS) {
return LHS->getName() == RHS->getName();
});
assert(FirstDiff.first != Cand1CPUSpec->cpus_end() &&
"Two different cpu-specific versions should not have the same "
"identifier list, otherwise they'd be the same decl!");
return (*FirstDiff.first)->getName() < (*FirstDiff.second)->getName()
? Comparison::Better
: Comparison::Worse;
}
llvm_unreachable("No way to get here unless both had cpu_dispatch");
}
static std::optional<QualType>
getImplicitObjectParamType(ASTContext &Context, const FunctionDecl *F) {
if (!isa<CXXMethodDecl>(F) || isa<CXXConstructorDecl>(F))
return std::nullopt;
auto *M = cast<CXXMethodDecl>(F);
if (M->isStatic())
return QualType();
return M->getFunctionObjectParameterReferenceType();
}
static bool allowAmbiguity(ASTContext &Context, const FunctionDecl *F1,
const FunctionDecl *F2) {
if (declaresSameEntity(F1, F2))
return true;
auto PT1 = F1->getPrimaryTemplate();
auto PT2 = F2->getPrimaryTemplate();
if (PT1 && PT2) {
if (declaresSameEntity(PT1, PT2) ||
declaresSameEntity(PT1->getInstantiatedFromMemberTemplate(),
PT2->getInstantiatedFromMemberTemplate()))
return true;
}
auto NextParam = [&](const FunctionDecl *F, unsigned &I, bool First) {
if (First) {
if (std::optional<QualType> T = getImplicitObjectParamType(Context, F))
return *T;
}
assert(I < F->getNumParams());
return F->getParamDecl(I++)->getType();
};
unsigned F1NumParams = F1->getNumParams() + isa<CXXMethodDecl>(F1);
unsigned F2NumParams = F2->getNumParams() + isa<CXXMethodDecl>(F2);
if (F1NumParams != F2NumParams)
return false;
unsigned I1 = 0, I2 = 0;
for (unsigned I = 0; I != F1NumParams; ++I) {
QualType T1 = NextParam(F1, I1, I == 0);
QualType T2 = NextParam(F2, I2, I == 0);
assert(!T1.isNull() && !T2.isNull() && "Unexpected null param types");
if (!Context.hasSameUnqualifiedType(T1, T2))
return false;
}
return true;
}
static bool sameFunctionParameterTypeLists(Sema &S,
const OverloadCandidate &Cand1,
const OverloadCandidate &Cand2) {
if (!Cand1.Function || !Cand2.Function)
return false;
FunctionDecl *Fn1 = Cand1.Function;
FunctionDecl *Fn2 = Cand2.Function;
if (Fn1->isVariadic() != Fn2->isVariadic())
return false;
if (!S.FunctionNonObjectParamTypesAreEqual(
Fn1, Fn2, nullptr, Cand1.isReversed() ^ Cand2.isReversed()))
return false;
auto *Mem1 = dyn_cast<CXXMethodDecl>(Fn1);
auto *Mem2 = dyn_cast<CXXMethodDecl>(Fn2);
if (Mem1 && Mem2) {
if (Mem1->getParent() != Mem2->getParent())
return false;
if (Mem1->isInstance() && Mem2->isInstance() &&
!S.getASTContext().hasSameType(
Mem1->getFunctionObjectParameterReferenceType(),
Mem1->getFunctionObjectParameterReferenceType()))
return false;
}
return true;
}
bool clang::isBetterOverloadCandidate(
Sema &S, const OverloadCandidate &Cand1, const OverloadCandidate &Cand2,
SourceLocation Loc, OverloadCandidateSet::CandidateSetKind Kind) {
if (!Cand2.Viable)
return Cand1.Viable;
else if (!Cand1.Viable)
return false;
if (S.getLangOpts().CUDA && Cand1.Function && Cand2.Function &&
S.getLangOpts().GPUExcludeWrongSideOverloads) {
if (FunctionDecl *Caller = S.getCurFunctionDecl(true)) {
bool IsCallerImplicitHD = SemaCUDA::isImplicitHostDeviceFunction(Caller);
bool IsCand1ImplicitHD =
SemaCUDA::isImplicitHostDeviceFunction(Cand1.Function);
bool IsCand2ImplicitHD =
SemaCUDA::isImplicitHostDeviceFunction(Cand2.Function);
auto P1 = S.CUDA().IdentifyPreference(Caller, Cand1.Function);
auto P2 = S.CUDA().IdentifyPreference(Caller, Cand2.Function);
assert(P1 != SemaCUDA::CFP_Never && P2 != SemaCUDA::CFP_Never);
auto EmitThreshold =
(S.getLangOpts().CUDAIsDevice && IsCallerImplicitHD &&
(IsCand1ImplicitHD || IsCand2ImplicitHD))
? SemaCUDA::CFP_Never
: SemaCUDA::CFP_WrongSide;
auto Cand1Emittable = P1 > EmitThreshold;
auto Cand2Emittable = P2 > EmitThreshold;
if (Cand1Emittable && !Cand2Emittable)
return true;
if (!Cand1Emittable && Cand2Emittable)
return false;
}
}
unsigned StartArg = 0;
if (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument)
StartArg = 1;
auto IsIllFormedConversion = [&](const ImplicitConversionSequence &ICS) {
if (!S.getLangOpts().CPlusPlus)
return ICS.isStandard() &&
ICS.Standard.Second == ICK_Incompatible_Pointer_Conversion;
return S.getLangOpts().CPlusPlus11 && !S.getLangOpts().WritableStrings &&
hasDeprecatedStringLiteralToCharPtrConversion(ICS);
};
unsigned NumArgs = Cand1.Conversions.size();
assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch");
bool HasBetterConversion = false;
for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
bool Cand1Bad = IsIllFormedConversion(Cand1.Conversions[ArgIdx]);
bool Cand2Bad = IsIllFormedConversion(Cand2.Conversions[ArgIdx]);
if (Cand1Bad != Cand2Bad) {
if (Cand1Bad)
return false;
HasBetterConversion = true;
}
}
if (HasBetterConversion)
return true;
bool HasWorseConversion = false;
for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
switch (CompareImplicitConversionSequences(S, Loc,
Cand1.Conversions[ArgIdx],
Cand2.Conversions[ArgIdx])) {
case ImplicitConversionSequence::Better:
HasBetterConversion = true;
break;
case ImplicitConversionSequence::Worse:
if (Cand1.Function && Cand2.Function &&
Cand1.isReversed() != Cand2.isReversed() &&
allowAmbiguity(S.Context, Cand1.Function, Cand2.Function)) {
HasWorseConversion = true;
break;
}
return false;
case ImplicitConversionSequence::Indistinguishable:
break;
}
}
if (HasBetterConversion && !HasWorseConversion)
return true;
if (Kind == OverloadCandidateSet::CSK_InitByUserDefinedConversion &&
Cand1.Function && Cand2.Function &&
isa<CXXConversionDecl>(Cand1.Function) &&
isa<CXXConversionDecl>(Cand2.Function)) {
ImplicitConversionSequence::CompareKind Result =
compareConversionFunctions(S, Cand1.Function, Cand2.Function);
if (Result == ImplicitConversionSequence::Indistinguishable)
Result = CompareStandardConversionSequences(S, Loc,
Cand1.FinalConversion,
Cand2.FinalConversion);
if (Result != ImplicitConversionSequence::Indistinguishable)
return Result == ImplicitConversionSequence::Better;
}
if (Kind == OverloadCandidateSet::CSK_InitByConstructor && NumArgs == 1 &&
Cand1.Function && Cand2.Function &&
isa<CXXConstructorDecl>(Cand1.Function) !=
isa<CXXConstructorDecl>(Cand2.Function))
return isa<CXXConstructorDecl>(Cand1.Function);
bool Cand1IsSpecialization = Cand1.Function &&
Cand1.Function->getPrimaryTemplate();
bool Cand2IsSpecialization = Cand2.Function &&
Cand2.Function->getPrimaryTemplate();
if (Cand1IsSpecialization != Cand2IsSpecialization)
return Cand2IsSpecialization;
if (Cand1IsSpecialization && Cand2IsSpecialization) {
const auto *Obj1Context =
dyn_cast<CXXRecordDecl>(Cand1.FoundDecl->getDeclContext());
const auto *Obj2Context =
dyn_cast<CXXRecordDecl>(Cand2.FoundDecl->getDeclContext());
if (FunctionTemplateDecl *BetterTemplate = S.getMoreSpecializedTemplate(
Cand1.Function->getPrimaryTemplate(),
Cand2.Function->getPrimaryTemplate(), Loc,
isa<CXXConversionDecl>(Cand1.Function) ? TPOC_Conversion
: TPOC_Call,
Cand1.ExplicitCallArguments,
Obj1Context ? QualType(Obj1Context->getTypeForDecl(), 0)
: QualType{},
Obj2Context ? QualType(Obj2Context->getTypeForDecl(), 0)
: QualType{},
Cand1.isReversed() ^ Cand2.isReversed())) {
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
}
if (!Cand1IsSpecialization && !Cand2IsSpecialization &&
sameFunctionParameterTypeLists(S, Cand1, Cand2) &&
S.getMoreConstrainedFunction(Cand1.Function, Cand2.Function) ==
Cand1.Function)
return true;
bool Cand1IsInherited =
isa_and_nonnull<ConstructorUsingShadowDecl>(Cand1.FoundDecl.getDecl());
bool Cand2IsInherited =
isa_and_nonnull<ConstructorUsingShadowDecl>(Cand2.FoundDecl.getDecl());
if (Cand1IsInherited != Cand2IsInherited)
return Cand2IsInherited;
else if (Cand1IsInherited) {
assert(Cand2IsInherited);
auto *Cand1Class = cast<CXXRecordDecl>(Cand1.Function->getDeclContext());
auto *Cand2Class = cast<CXXRecordDecl>(Cand2.Function->getDeclContext());
if (Cand1Class->isDerivedFrom(Cand2Class))
return true;
if (Cand2Class->isDerivedFrom(Cand1Class))
return false;
}
if (Cand1.RewriteKind != Cand2.RewriteKind)
return Cand1.RewriteKind < Cand2.RewriteKind;
{
auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);
auto *Guide2 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand2.Function);
if (Guide1 && Guide2) {
if (Guide1->isImplicit() != Guide2->isImplicit())
return Guide2->isImplicit();
if (Guide1->getDeductionCandidateKind() == DeductionCandidate::Copy)
return true;
if (Guide2->getDeductionCandidateKind() == DeductionCandidate::Copy)
return false;
const auto *Constructor1 = Guide1->getCorrespondingConstructor();
const auto *Constructor2 = Guide2->getCorrespondingConstructor();
if (Constructor1 && Constructor2) {
bool isC1Templated = Constructor1->getTemplatedKind() !=
FunctionDecl::TemplatedKind::TK_NonTemplate;
bool isC2Templated = Constructor2->getTemplatedKind() !=
FunctionDecl::TemplatedKind::TK_NonTemplate;
if (isC1Templated != isC2Templated)
return isC2Templated;
}
}
}
if (Cand1.Function && Cand2.Function) {
Comparison Cmp = compareEnableIfAttrs(S, Cand1.Function, Cand2.Function);
if (Cmp != Comparison::Equal)
return Cmp == Comparison::Better;
}
bool HasPS1 = Cand1.Function != nullptr &&
functionHasPassObjectSizeParams(Cand1.Function);
bool HasPS2 = Cand2.Function != nullptr &&
functionHasPassObjectSizeParams(Cand2.Function);
if (HasPS1 != HasPS2 && HasPS1)
return true;
auto MV = isBetterMultiversionCandidate(Cand1, Cand2);
if (MV == Comparison::Better)
return true;
if (MV == Comparison::Worse)
return false;
if (S.getLangOpts().CUDA && Cand1.Function && Cand2.Function) {
FunctionDecl *Caller = S.getCurFunctionDecl(true);
return S.CUDA().IdentifyPreference(Caller, Cand1.Function) >
S.CUDA().IdentifyPreference(Caller, Cand2.Function);
}
const auto *CD1 = dyn_cast_or_null<CXXConstructorDecl>(Cand1.Function);
const auto *CD2 = dyn_cast_or_null<CXXConstructorDecl>(Cand2.Function);
if (CD1 && CD2) {
LangAS AS1 = CD1->getMethodQualifiers().getAddressSpace();
LangAS AS2 = CD2->getMethodQualifiers().getAddressSpace();
if (AS1 != AS2) {
if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1))
return true;
if (Qualifiers::isAddressSpaceSupersetOf(AS1, AS2))
return false;
}
}
return false;
}
bool Sema::isEquivalentInternalLinkageDeclaration(const NamedDecl *A,
const NamedDecl *B) {
auto *VA = dyn_cast_or_null<ValueDecl>(A);
auto *VB = dyn_cast_or_null<ValueDecl>(B);
if (!VA || !VB)
return false;
if (!VA->getDeclContext()->getRedeclContext()->Equals(
VB->getDeclContext()->getRedeclContext()) ||
getOwningModule(VA) == getOwningModule(VB) ||
VA->isExternallyVisible() || VB->isExternallyVisible())
return false;
if (Context.hasSameType(VA->getType(), VB->getType()))
return true;
if (auto *EA = dyn_cast<EnumConstantDecl>(VA)) {
if (auto *EB = dyn_cast<EnumConstantDecl>(VB)) {
auto *EnumA = cast<EnumDecl>(EA->getDeclContext());
auto *EnumB = cast<EnumDecl>(EB->getDeclContext());
if (EnumA->hasNameForLinkage() || EnumB->hasNameForLinkage() ||
!Context.hasSameType(EnumA->getIntegerType(),
EnumB->getIntegerType()))
return false;
return llvm::APSInt::isSameValue(EA->getInitVal(), EB->getInitVal());
}
}
return false;
}
void Sema::diagnoseEquivalentInternalLinkageDeclarations(
SourceLocation Loc, const NamedDecl *D, ArrayRef<const NamedDecl *> Equiv) {
assert(D && "Unknown declaration");
Diag(Loc, diag::ext_equivalent_internal_linkage_decl_in_modules) << D;
Module *M = getOwningModule(D);
Diag(D->getLocation(), diag::note_equivalent_internal_linkage_decl)
<< !M << (M ? M->getFullModuleName() : "");
for (auto *E : Equiv) {
Module *M = getOwningModule(E);
Diag(E->getLocation(), diag::note_equivalent_internal_linkage_decl)
<< !M << (M ? M->getFullModuleName() : "");
}
}
bool OverloadCandidate::NotValidBecauseConstraintExprHasError() const {
return FailureKind == ovl_fail_bad_deduction &&
static_cast<TemplateDeductionResult>(DeductionFailure.Result) ==
TemplateDeductionResult::ConstraintsNotSatisfied &&
static_cast<CNSInfo *>(DeductionFailure.Data)
->Satisfaction.ContainsErrors;
}
OverloadingResult
OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
iterator &Best) {
llvm::SmallVector<OverloadCandidate *, 16> Candidates;
std::transform(begin(), end(), std::back_inserter(Candidates),
[](OverloadCandidate &Cand) { return &Cand; });
if (S.getLangOpts().CUDA && !S.getLangOpts().GPUExcludeWrongSideOverloads) {
const FunctionDecl *Caller = S.getCurFunctionDecl(true);
bool ContainsSameSideCandidate =
llvm::any_of(Candidates, [&](OverloadCandidate *Cand) {
return Cand->Viable && Cand->Function &&
S.CUDA().IdentifyPreference(Caller, Cand->Function) ==
SemaCUDA::CFP_SameSide;
});
if (ContainsSameSideCandidate) {
auto IsWrongSideCandidate = [&](OverloadCandidate *Cand) {
return Cand->Viable && Cand->Function &&
S.CUDA().IdentifyPreference(Caller, Cand->Function) ==
SemaCUDA::CFP_WrongSide;
};
llvm::erase_if(Candidates, IsWrongSideCandidate);
}
}
Best = end();
for (auto *Cand : Candidates) {
Cand->Best = false;
if (Cand->Viable) {
if (Best == end() ||
isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind))
Best = Cand;
} else if (Cand->NotValidBecauseConstraintExprHasError()) {
Best = end();
return OR_No_Viable_Function;
}
}
if (Best == end())
return OR_No_Viable_Function;
llvm::SmallVector<const NamedDecl *, 4> EquivalentCands;
llvm::SmallVector<OverloadCandidate*, 4> PendingBest;
PendingBest.push_back(&*Best);
Best->Best = true;
while (!PendingBest.empty()) {
auto *Curr = PendingBest.pop_back_val();
for (auto *Cand : Candidates) {
if (Cand->Viable && !Cand->Best &&
!isBetterOverloadCandidate(S, *Curr, *Cand, Loc, Kind)) {
PendingBest.push_back(Cand);
Cand->Best = true;
if (S.isEquivalentInternalLinkageDeclaration(Cand->Function,
Curr->Function))
EquivalentCands.push_back(Cand->Function);
else
Best = end();
}
}
}
if (Best == end())
return OR_Ambiguous;
if (Best->Function && Best->Function->isDeleted())
return OR_Deleted;
if (auto *M = dyn_cast_or_null<CXXMethodDecl>(Best->Function);
Kind == CSK_AddressOfOverloadSet && M &&
M->isImplicitObjectMemberFunction()) {
return OR_No_Viable_Function;
}
if (!EquivalentCands.empty())
S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function,
EquivalentCands);
return OR_Success;
}
namespace {
enum OverloadCandidateKind {
oc_function,
oc_method,
oc_reversed_binary_operator,
oc_constructor,
oc_implicit_default_constructor,
oc_implicit_copy_constructor,
oc_implicit_move_constructor,
oc_implicit_copy_assignment,
oc_implicit_move_assignment,
oc_implicit_equality_comparison,
oc_inherited_constructor
};
enum OverloadCandidateSelect {
ocs_non_template,
ocs_template,
ocs_described_template,
};
static std::pair<OverloadCandidateKind, OverloadCandidateSelect>
ClassifyOverloadCandidate(Sema &S, const NamedDecl *Found,
const FunctionDecl *Fn,
OverloadCandidateRewriteKind CRK,
std::string &Description) {
bool isTemplate = Fn->isTemplateDecl() || Found->isTemplateDecl();
if (FunctionTemplateDecl *FunTmpl = Fn->getPrimaryTemplate()) {
isTemplate = true;
Description = S.getTemplateArgumentBindingsText(
FunTmpl->getTemplateParameters(), *Fn->getTemplateSpecializationArgs());
}
OverloadCandidateSelect Select = [&]() {
if (!Description.empty())
return ocs_described_template;
return isTemplate ? ocs_template : ocs_non_template;
}();
OverloadCandidateKind Kind = [&]() {
if (Fn->isImplicit() && Fn->getOverloadedOperator() == OO_EqualEqual)
return oc_implicit_equality_comparison;
if (CRK & CRK_Reversed)
return oc_reversed_binary_operator;
if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) {
if (!Ctor->isImplicit()) {
if (isa<ConstructorUsingShadowDecl>(Found))
return oc_inherited_constructor;
else
return oc_constructor;
}
if (Ctor->isDefaultConstructor())
return oc_implicit_default_constructor;
if (Ctor->isMoveConstructor())
return oc_implicit_move_constructor;
assert(Ctor->isCopyConstructor() &&
"unexpected sort of implicit constructor");
return oc_implicit_copy_constructor;
}
if (const auto *Meth = dyn_cast<CXXMethodDecl>(Fn)) {
if (!Meth->isImplicit())
return oc_method;
if (Meth->isMoveAssignmentOperator())
return oc_implicit_move_assignment;
if (Meth->isCopyAssignmentOperator())
return oc_implicit_copy_assignment;
assert(isa<CXXConversionDecl>(Meth) && "expected conversion");
return oc_method;
}
return oc_function;
}();
return std::make_pair(Kind, Select);
}
void MaybeEmitInheritedConstructorNote(Sema &S, const Decl *FoundDecl) {
if (const auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl))
S.Diag(FoundDecl->getLocation(),
diag::note_ovl_candidate_inherited_constructor)
<< Shadow->getNominatedBaseClass();
}
}
static bool isFunctionAlwaysEnabled(const ASTContext &Ctx,
const FunctionDecl *FD) {
for (auto *EnableIf : FD->specific_attrs<EnableIfAttr>()) {
bool AlwaysTrue;
if (EnableIf->getCond()->isValueDependent() ||
!EnableIf->getCond()->EvaluateAsBooleanCondition(AlwaysTrue, Ctx))
return false;
if (!AlwaysTrue)
return false;
}
return true;
}
static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD,
bool Complain,
bool InOverloadResolution,
SourceLocation Loc) {
if (!isFunctionAlwaysEnabled(S.Context, FD)) {
if (Complain) {
if (InOverloadResolution)
S.Diag(FD->getBeginLoc(),
diag::note_addrof_ovl_candidate_disabled_by_enable_if_attr);
else
S.Diag(Loc, diag::err_addrof_function_disabled_by_enable_if_attr) << FD;
}
return false;
}
if (FD->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
if (S.CheckFunctionConstraints(FD, Satisfaction, Loc))
return false;
if (!Satisfaction.IsSatisfied) {
if (Complain) {
if (InOverloadResolution) {
SmallString<128> TemplateArgString;
if (FunctionTemplateDecl *FunTmpl = FD->getPrimaryTemplate()) {
TemplateArgString += " ";
TemplateArgString += S.getTemplateArgumentBindingsText(
FunTmpl->getTemplateParameters(),
*FD->getTemplateSpecializationArgs());
}
S.Diag(FD->getBeginLoc(),
diag::note_ovl_candidate_unsatisfied_constraints)
<< TemplateArgString;
} else
S.Diag(Loc, diag::err_addrof_function_constraints_not_satisfied)
<< FD;
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
}
return false;
}
}
auto I = llvm::find_if(FD->parameters(), [](const ParmVarDecl *P) {
return P->hasAttr<PassObjectSizeAttr>();
});
if (I == FD->param_end())
return true;
if (Complain) {
unsigned ParamNo = std::distance(FD->param_begin(), I) + 1;
if (InOverloadResolution)
S.Diag(FD->getLocation(),
diag::note_ovl_candidate_has_pass_object_size_params)
<< ParamNo;
else
S.Diag(Loc, diag::err_address_of_function_with_pass_object_size_params)
<< FD << ParamNo;
}
return false;
}
static bool checkAddressOfCandidateIsAvailable(Sema &S,
const FunctionDecl *FD) {
return checkAddressOfFunctionIsAvailable(S, FD, true,
true,
SourceLocation());
}
bool Sema::checkAddressOfFunctionIsAvailable(const FunctionDecl *Function,
bool Complain,
SourceLocation Loc) {
return ::checkAddressOfFunctionIsAvailable(*this, Function, Complain,
false,
Loc);
}
static bool shouldSkipNotingLambdaConversionDecl(const FunctionDecl *Fn) {
const auto *ConvD = dyn_cast<CXXConversionDecl>(Fn);
if (!ConvD)
return false;
const auto *RD = cast<CXXRecordDecl>(Fn->getParent());
if (!RD->isLambda())
return false;
CXXMethodDecl *CallOp = RD->getLambdaCallOperator();
CallingConv CallOpCC =
CallOp->getType()->castAs<FunctionType>()->getCallConv();
QualType ConvRTy = ConvD->getType()->castAs<FunctionType>()->getReturnType();
CallingConv ConvToCC =
ConvRTy->getPointeeType()->castAs<FunctionType>()->getCallConv();
return ConvToCC != CallOpCC;
}
void Sema::NoteOverloadCandidate(const NamedDecl *Found, const FunctionDecl *Fn,
OverloadCandidateRewriteKind RewriteKind,
QualType DestType, bool TakingAddress) {
if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn))
return;
if (Fn->isMultiVersion() && Fn->hasAttr<TargetAttr>() &&
!Fn->getAttr<TargetAttr>()->isDefaultVersion())
return;
if (Fn->isMultiVersion() && Fn->hasAttr<TargetVersionAttr>() &&
!Fn->getAttr<TargetVersionAttr>()->isDefaultVersion())
return;
if (shouldSkipNotingLambdaConversionDecl(Fn))
return;
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> KSPair =
ClassifyOverloadCandidate(*this, Found, Fn, RewriteKind, FnDesc);
PartialDiagnostic PD = PDiag(diag::note_ovl_candidate)
<< (unsigned)KSPair.first << (unsigned)KSPair.second
<< Fn << FnDesc;
HandleFunctionTypeMismatch(PD, Fn->getType(), DestType);
Diag(Fn->getLocation(), PD);
MaybeEmitInheritedConstructorNote(*this, Found);
}
static void
MaybeDiagnoseAmbiguousConstraints(Sema &S, ArrayRef<OverloadCandidate> Cands) {
SmallVector<const Expr *, 3> FirstAC, SecondAC;
FunctionDecl *FirstCand = nullptr, *SecondCand = nullptr;
for (auto I = Cands.begin(), E = Cands.end(); I != E; ++I) {
if (!I->Function)
continue;
SmallVector<const Expr *, 3> AC;
if (auto *Template = I->Function->getPrimaryTemplate())
Template->getAssociatedConstraints(AC);
else
I->Function->getAssociatedConstraints(AC);
if (AC.empty())
continue;
if (FirstCand == nullptr) {
FirstCand = I->Function;
FirstAC = AC;
} else if (SecondCand == nullptr) {
SecondCand = I->Function;
SecondAC = AC;
} else {
return;
}
}
if (!SecondCand)
return;
if (S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(FirstCand, FirstAC,
SecondCand, SecondAC))
return;
}
void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType,
bool TakingAddress) {
assert(OverloadedExpr->getType() == Context.OverloadTy);
OverloadExpr::FindResult Ovl = OverloadExpr::find(OverloadedExpr);
OverloadExpr *OvlExpr = Ovl.Expression;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
IEnd = OvlExpr->decls_end();
I != IEnd; ++I) {
if (FunctionTemplateDecl *FunTmpl =
dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) {
NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), CRK_None, DestType,
TakingAddress);
} else if (FunctionDecl *Fun
= dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) {
NoteOverloadCandidate(*I, Fun, CRK_None, DestType, TakingAddress);
}
}
}
void ImplicitConversionSequence::DiagnoseAmbiguousConversion(
Sema &S,
SourceLocation CaretLoc,
const PartialDiagnostic &PDiag) const {
S.Diag(CaretLoc, PDiag)
<< Ambiguous.getFromType() << Ambiguous.getToType();
unsigned CandsShown = 0;
AmbiguousConversionSequence::const_iterator I, E;
for (I = Ambiguous.begin(), E = Ambiguous.end(); I != E; ++I) {
if (CandsShown >= S.Diags.getNumOverloadCandidatesToShow())
break;
++CandsShown;
S.NoteOverloadCandidate(I->first, I->second);
}
S.Diags.overloadCandidatesShown(CandsShown);
if (I != E)
S.Diag(SourceLocation(), diag::note_ovl_too_many_candidates) << int(E - I);
}
static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
unsigned I, bool TakingCandidateAddress) {
const ImplicitConversionSequence &Conv = Cand->Conversions[I];
assert(Conv.isBad());
assert(Cand->Function && "for now, candidate must be a function");
FunctionDecl *Fn = Cand->Function;
bool isObjectArgument = false;
if (isa<CXXMethodDecl>(Fn) && !isa<CXXConstructorDecl>(Fn)) {
if (I == 0)
isObjectArgument = true;
else
I--;
}
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->getRewriteKind(),
FnDesc);
Expr *FromExpr = Conv.Bad.FromExpr;
QualType FromTy = Conv.Bad.getFromType();
QualType ToTy = Conv.Bad.getToType();
SourceRange ToParamRange;
bool HasParamPack =
llvm::any_of(Fn->parameters().take_front(I), [](const ParmVarDecl *Parm) {
return Parm->isParameterPack();
});
if (!isObjectArgument && !HasParamPack)
ToParamRange = Fn->getParamDecl(I)->getSourceRange();
if (FromTy == S.Context.OverloadTy) {
assert(FromExpr && "overload set argument came from implicit argument?");
Expr *E = FromExpr->IgnoreParens();
if (isa<UnaryOperator>(E))
E = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
DeclarationName Name = cast<OverloadExpr>(E)->getName();
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_overload)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< ToParamRange << ToTy << Name << I + 1;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
CanQualType CFromTy = S.Context.getCanonicalType(FromTy);
CanQualType CToTy = S.Context.getCanonicalType(ToTy);
if (CanQual<ReferenceType> RT = CToTy->getAs<ReferenceType>())
CToTy = RT->getPointeeType();
else {
if (CanQual<PointerType> FromPT = CFromTy->getAs<PointerType>())
if (CanQual<PointerType> ToPT = CToTy->getAs<PointerType>()) {
CFromTy = FromPT->getPointeeType();
CToTy = ToPT->getPointeeType();
}
}
if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() &&
!CToTy.isAtLeastAsQualifiedAs(CFromTy)) {
Qualifiers FromQs = CFromTy.getQualifiers();
Qualifiers ToQs = CToTy.getQualifiers();
if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) {
if (isObjectArgument)
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace_this)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
<< FnDesc << FromQs.getAddressSpace() << ToQs.getAddressSpace();
else
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
<< FnDesc << ToParamRange << FromQs.getAddressSpace()
<< ToQs.getAddressSpace() << ToTy->isReferenceType() << I + 1;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ownership)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< ToParamRange << FromTy << FromQs.getObjCLifetime()
<< ToQs.getObjCLifetime() << (unsigned)isObjectArgument << I + 1;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< ToParamRange << FromTy << FromQs.getObjCGCAttr()
<< ToQs.getObjCGCAttr() << (unsigned)isObjectArgument << I + 1;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers();
assert(CVR && "expected qualifiers mismatch");
if (isObjectArgument) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr_this)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< FromTy << (CVR - 1);
} else {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< ToParamRange << FromTy << (CVR - 1) << I + 1;
}
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
if (Conv.Bad.Kind == BadConversionSequence::lvalue_ref_to_rvalue ||
Conv.Bad.Kind == BadConversionSequence::rvalue_ref_to_lvalue) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_value_category)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< (unsigned)isObjectArgument << I + 1
<< (Conv.Bad.Kind == BadConversionSequence::rvalue_ref_to_lvalue)
<< ToParamRange;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
if (FromExpr && isa<InitListExpr>(FromExpr)) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_list_argument)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument << I + 1
<< (Conv.Bad.Kind == BadConversionSequence::too_few_initializers ? 1
: Conv.Bad.Kind == BadConversionSequence::too_many_initializers
? 2
: 0);
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
QualType TempFromTy = FromTy.getNonReferenceType();
if (const PointerType *PTy = TempFromTy->getAs<PointerType>())
TempFromTy = PTy->getPointeeType();
if (TempFromTy->isIncompleteType()) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument << I + 1
<< (unsigned)(Cand->Fix.Kind);
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
unsigned BaseToDerivedConversion = 0;
if (const PointerType *FromPtrTy = FromTy->getAs<PointerType>()) {
if (const PointerType *ToPtrTy = ToTy->getAs<PointerType>()) {
if (ToPtrTy->getPointeeType().isAtLeastAsQualifiedAs(
FromPtrTy->getPointeeType()) &&
!FromPtrTy->getPointeeType()->isIncompleteType() &&
!ToPtrTy->getPointeeType()->isIncompleteType() &&
S.IsDerivedFrom(SourceLocation(), ToPtrTy->getPointeeType(),
FromPtrTy->getPointeeType()))
BaseToDerivedConversion = 1;
}
} else if (const ObjCObjectPointerType *FromPtrTy
= FromTy->getAs<ObjCObjectPointerType>()) {
if (const ObjCObjectPointerType *ToPtrTy
= ToTy->getAs<ObjCObjectPointerType>())
if (const ObjCInterfaceDecl *FromIface = FromPtrTy->getInterfaceDecl())
if (const ObjCInterfaceDecl *ToIface = ToPtrTy->getInterfaceDecl())
if (ToPtrTy->getPointeeType().isAtLeastAsQualifiedAs(
FromPtrTy->getPointeeType()) &&
FromIface->isSuperClassOf(ToIface))
BaseToDerivedConversion = 2;
} else if (const ReferenceType *ToRefTy = ToTy->getAs<ReferenceType>()) {
if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy) &&
!FromTy->isIncompleteType() &&
!ToRefTy->getPointeeType()->isIncompleteType() &&
S.IsDerivedFrom(SourceLocation(), ToRefTy->getPointeeType(), FromTy)) {
BaseToDerivedConversion = 3;
}
}
if (BaseToDerivedConversion) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_base_to_derived_conv)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< ToParamRange << (BaseToDerivedConversion - 1) << FromTy << ToTy
<< I + 1;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
if (isa<ObjCObjectPointerType>(CFromTy) &&
isa<PointerType>(CToTy)) {
Qualifiers FromQs = CFromTy.getQualifiers();
Qualifiers ToQs = CToTy.getQualifiers();
if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_arc_conv)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument
<< I + 1;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
}
if (TakingCandidateAddress &&
!checkAddressOfCandidateIsAvailable(S, Cand->Function))
return;
PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv);
FDiag << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument << I + 1
<< (unsigned)(Cand->Fix.Kind);
if (!S.SourceMgr.isInSystemHeader(Fn->getLocation())) {
for (const FixItHint &HI : Cand->Fix.Hints)
FDiag << HI;
}
S.Diag(Fn->getLocation(), FDiag);
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
}
static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned NumArgs, bool IsAddressOf = false) {
FunctionDecl *Fn = Cand->Function;
unsigned MinParams = Fn->getMinRequiredExplicitArguments() +
((IsAddressOf && !Fn->isStatic()) ? 1 : 0);
if (Fn->isInvalidDecl() &&
Fn->getDeclName().getNameKind() == DeclarationName::CXXOperatorName)
return true;
if (NumArgs < MinParams) {
assert((Cand->FailureKind == ovl_fail_too_few_arguments) ||
(Cand->FailureKind == ovl_fail_bad_deduction &&
Cand->DeductionFailure.getResult() ==
TemplateDeductionResult::TooFewArguments));
} else {
assert((Cand->FailureKind == ovl_fail_too_many_arguments) ||
(Cand->FailureKind == ovl_fail_bad_deduction &&
Cand->DeductionFailure.getResult() ==
TemplateDeductionResult::TooManyArguments));
}
return false;
}
static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
unsigned NumFormalArgs,
bool IsAddressOf = false) {
assert(isa<FunctionDecl>(D) &&
"The templated declaration should at least be a function"
" when diagnosing bad template argument deduction due to too many"
" or too few arguments");
FunctionDecl *Fn = cast<FunctionDecl>(D);
const auto *FnTy = Fn->getType()->castAs<FunctionProtoType>();
unsigned MinParams = Fn->getMinRequiredExplicitArguments() +
((IsAddressOf && !Fn->isStatic()) ? 1 : 0);
bool HasExplicitObjectParam =
!IsAddressOf && Fn->hasCXXExplicitFunctionObjectParameter();
unsigned ParamCount =
Fn->getNumNonObjectParams() + ((IsAddressOf && !Fn->isStatic()) ? 1 : 0);
unsigned mode, modeCount;
if (NumFormalArgs < MinParams) {
if (MinParams != ParamCount || FnTy->isVariadic() ||
FnTy->isTemplateVariadic())
mode = 0;
else
mode = 2;
modeCount = MinParams;
} else {
if (MinParams != ParamCount)
mode = 1;
else
mode = 2;
modeCount = ParamCount;
}
std::string Description;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
ClassifyOverloadCandidate(S, Found, Fn, CRK_None, Description);
if (modeCount == 1 && !IsAddressOf &&
Fn->getParamDecl(HasExplicitObjectParam ? 1 : 0)->getDeclName())
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
<< Description << mode
<< Fn->getParamDecl(HasExplicitObjectParam ? 1 : 0) << NumFormalArgs
<< HasExplicitObjectParam << Fn->getParametersSourceRange();
else
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
<< Description << mode << modeCount << NumFormalArgs
<< HasExplicitObjectParam << Fn->getParametersSourceRange();
MaybeEmitInheritedConstructorNote(S, Found);
}
static void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned NumFormalArgs) {
if (!CheckArityMismatch(S, Cand, NumFormalArgs, Cand->TookAddressOfOverload))
DiagnoseArityMismatch(S, Cand->FoundDecl, Cand->Function, NumFormalArgs,
Cand->TookAddressOfOverload);
}
static TemplateDecl *getDescribedTemplate(Decl *Templated) {
if (TemplateDecl *TD = Templated->getDescribedTemplate())
return TD;
llvm_unreachable("Unsupported: Getting the described template declaration"
" for bad deduction diagnosis");
}
static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
DeductionFailureInfo &DeductionFailure,
unsigned NumArgs,
bool TakingCandidateAddress) {
TemplateParameter Param = DeductionFailure.getTemplateParameter();
NamedDecl *ParamD;
(ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
(ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) ||
(ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>());
switch (DeductionFailure.getResult()) {
case TemplateDeductionResult::Success:
llvm_unreachable(
"TemplateDeductionResult::Success while diagnosing bad deduction");
case TemplateDeductionResult::NonDependentConversionFailure:
llvm_unreachable("TemplateDeductionResult::NonDependentConversionFailure "
"while diagnosing bad deduction");
case TemplateDeductionResult::Invalid:
case TemplateDeductionResult::AlreadyDiagnosed:
return;
case TemplateDeductionResult::Incomplete: {
assert(ParamD && "no parameter found for incomplete deduction result");
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_incomplete_deduction)
<< ParamD->getDeclName();
MaybeEmitInheritedConstructorNote(S, Found);
return;
}
case TemplateDeductionResult::IncompletePack: {
assert(ParamD && "no parameter found for incomplete deduction result");
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_incomplete_deduction_pack)
<< ParamD->getDeclName()
<< (DeductionFailure.getFirstArg()->pack_size() + 1)
<< *DeductionFailure.getFirstArg();
MaybeEmitInheritedConstructorNote(S, Found);
return;
}
case TemplateDeductionResult::Underqualified: {
assert(ParamD && "no parameter found for bad qualifiers deduction result");
TemplateTypeParmDecl *TParam = cast<TemplateTypeParmDecl>(ParamD);
QualType Param = DeductionFailure.getFirstArg()->getAsType();
QualifierCollector Qs;
Qs.strip(Param);
QualType NonCanonParam = Qs.apply(S.Context, TParam->getTypeForDecl());
assert(S.Context.hasSameType(Param, NonCanonParam));
QualType Arg = DeductionFailure.getSecondArg()->getAsType();
S.Diag(Templated->getLocation(), diag::note_ovl_candidate_underqualified)
<< ParamD->getDeclName() << Arg << NonCanonParam;
MaybeEmitInheritedConstructorNote(S, Found);
return;
}
case TemplateDeductionResult::Inconsistent: {
assert(ParamD && "no parameter found for inconsistent deduction result");
int which = 0;
if (isa<TemplateTypeParmDecl>(ParamD))
which = 0;
else if (isa<NonTypeTemplateParmDecl>(ParamD)) {
QualType T1 =
DeductionFailure.getFirstArg()->getNonTypeTemplateArgumentType();
QualType T2 =
DeductionFailure.getSecondArg()->getNonTypeTemplateArgumentType();
if (!T1.isNull() && !T2.isNull() && !S.Context.hasSameType(T1, T2)) {
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_inconsistent_deduction_types)
<< ParamD->getDeclName() << *DeductionFailure.getFirstArg() << T1
<< *DeductionFailure.getSecondArg() << T2;
MaybeEmitInheritedConstructorNote(S, Found);
return;
}
which = 1;
} else {
which = 2;
}
if (DeductionFailure.getFirstArg()->getKind() == TemplateArgument::Pack &&
DeductionFailure.getSecondArg()->getKind() == TemplateArgument::Pack &&
DeductionFailure.getFirstArg()->pack_size() !=
DeductionFailure.getSecondArg()->pack_size()) {
which = 3;
}
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_inconsistent_deduction)
<< which << ParamD->getDeclName() << *DeductionFailure.getFirstArg()
<< *DeductionFailure.getSecondArg();
MaybeEmitInheritedConstructorNote(S, Found);
return;
}
case TemplateDeductionResult::InvalidExplicitArguments:
assert(ParamD && "no parameter found for invalid explicit arguments");
if (ParamD->getDeclName())
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_explicit_arg_mismatch_named)
<< ParamD->getDeclName();
else {
int index = 0;
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ParamD))
index = TTP->getIndex();
else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(ParamD))
index = NTTP->getIndex();
else
index = cast<TemplateTemplateParmDecl>(ParamD)->getIndex();
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_explicit_arg_mismatch_unnamed)
<< (index + 1);
}
MaybeEmitInheritedConstructorNote(S, Found);
return;
case TemplateDeductionResult::ConstraintsNotSatisfied: {
SmallString<128> TemplateArgString;
TemplateArgumentList *Args = DeductionFailure.getTemplateArgumentList();
TemplateArgString = " ";
TemplateArgString += S.getTemplateArgumentBindingsText(
getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
if (TemplateArgString.size() == 1)
TemplateArgString.clear();
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_unsatisfied_constraints)
<< TemplateArgString;
S.DiagnoseUnsatisfiedConstraint(
static_cast<CNSInfo*>(DeductionFailure.Data)->Satisfaction);
return;
}
case TemplateDeductionResult::TooManyArguments:
case TemplateDeductionResult::TooFewArguments:
DiagnoseArityMismatch(S, Found, Templated, NumArgs);
return;
case TemplateDeductionResult::InstantiationDepth:
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_instantiation_depth);
MaybeEmitInheritedConstructorNote(S, Found);
return;
case TemplateDeductionResult::SubstitutionFailure: {
SmallString<128> TemplateArgString;
if (TemplateArgumentList *Args =
DeductionFailure.getTemplateArgumentList()) {
TemplateArgString = " ";
TemplateArgString += S.getTemplateArgumentBindingsText(
getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
if (TemplateArgString.size() == 1)
TemplateArgString.clear();
}
PartialDiagnosticAt *PDiag = DeductionFailure.getSFINAEDiagnostic();
if (PDiag && PDiag->second.getDiagID() ==
diag::err_typename_nested_not_found_enable_if) {
S.Diag(PDiag->first, diag::note_ovl_candidate_disabled_by_enable_if)
<< "'enable_if'" << TemplateArgString;
return;
}
if (PDiag && PDiag->second.getDiagID() ==
diag::err_typename_nested_not_found_requirement) {
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_disabled_by_requirement)
<< PDiag->second.getStringArg(0) << TemplateArgString;
return;
}
SmallString<128> SFINAEArgString;
SourceRange R;
if (PDiag) {
SFINAEArgString = ": ";
R = SourceRange(PDiag->first, PDiag->first);
PDiag->second.EmitToString(S.getDiagnostics(), SFINAEArgString);
}
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_substitution_failure)
<< TemplateArgString << SFINAEArgString << R;
MaybeEmitInheritedConstructorNote(S, Found);
return;
}
case TemplateDeductionResult::DeducedMismatch:
case TemplateDeductionResult::DeducedMismatchNested: {
SmallString<128> TemplateArgString;
if (TemplateArgumentList *Args =
DeductionFailure.getTemplateArgumentList()) {
TemplateArgString = " ";
TemplateArgString += S.getTemplateArgumentBindingsText(
getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
if (TemplateArgString.size() == 1)
TemplateArgString.clear();
}
S.Diag(Templated->getLocation(), diag::note_ovl_candidate_deduced_mismatch)
<< (*DeductionFailure.getCallArgIndex() + 1)
<< *DeductionFailure.getFirstArg() << *DeductionFailure.getSecondArg()
<< TemplateArgString
<< (DeductionFailure.getResult() ==
TemplateDeductionResult::DeducedMismatchNested);
break;
}
case TemplateDeductionResult::NonDeducedMismatch: {
TemplateArgument FirstTA = *DeductionFailure.getFirstArg();
TemplateArgument SecondTA = *DeductionFailure.getSecondArg();
if (FirstTA.getKind() == TemplateArgument::Template &&
SecondTA.getKind() == TemplateArgument::Template) {
TemplateName FirstTN = FirstTA.getAsTemplate();
TemplateName SecondTN = SecondTA.getAsTemplate();
if (FirstTN.getKind() == TemplateName::Template &&
SecondTN.getKind() == TemplateName::Template) {
if (FirstTN.getAsTemplateDecl()->getName() ==
SecondTN.getAsTemplateDecl()->getName()) {
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_non_deduced_mismatch_qualified)
<< FirstTN.getAsTemplateDecl() << SecondTN.getAsTemplateDecl();
return;
}
}
}
if (TakingCandidateAddress && isa<FunctionDecl>(Templated) &&
!checkAddressOfCandidateIsAvailable(S, cast<FunctionDecl>(Templated)))
return;
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_non_deduced_mismatch)
<< FirstTA << SecondTA;
return;
}
case TemplateDeductionResult::MiscellaneousDeductionFailure:
S.Diag(Templated->getLocation(), diag::note_ovl_candidate_bad_deduction);
MaybeEmitInheritedConstructorNote(S, Found);
return;
case TemplateDeductionResult::CUDATargetMismatch:
S.Diag(Templated->getLocation(),
diag::note_cuda_ovl_candidate_target_mismatch);
return;
}
}
static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
unsigned NumArgs,
bool TakingCandidateAddress) {
TemplateDeductionResult TDK = Cand->DeductionFailure.getResult();
if (TDK == TemplateDeductionResult::TooFewArguments ||
TDK == TemplateDeductionResult::TooManyArguments) {
if (CheckArityMismatch(S, Cand, NumArgs))
return;
}
DiagnoseBadDeduction(S, Cand->FoundDecl, Cand->Function,
Cand->DeductionFailure, NumArgs, TakingCandidateAddress);
}
static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
FunctionDecl *Caller = S.getCurFunctionDecl(true);
FunctionDecl *Callee = Cand->Function;
CUDAFunctionTarget CallerTarget = S.CUDA().IdentifyTarget(Caller),
CalleeTarget = S.CUDA().IdentifyTarget(Callee);
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee,
Cand->getRewriteKind(), FnDesc);
S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target)
<< (unsigned)FnKindPair.first << (unsigned)ocs_non_template
<< FnDesc
<< llvm::to_underlying(CalleeTarget) << llvm::to_underlying(CallerTarget);
CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Callee);
if (Meth != nullptr && Meth->isImplicit()) {
CXXRecordDecl *ParentClass = Meth->getParent();
CXXSpecialMemberKind CSM;
switch (FnKindPair.first) {
default:
return;
case oc_implicit_default_constructor:
CSM = CXXSpecialMemberKind::DefaultConstructor;
break;
case oc_implicit_copy_constructor:
CSM = CXXSpecialMemberKind::CopyConstructor;
break;
case oc_implicit_move_constructor:
CSM = CXXSpecialMemberKind::MoveConstructor;
break;
case oc_implicit_copy_assignment:
CSM = CXXSpecialMemberKind::CopyAssignment;
break;
case oc_implicit_move_assignment:
CSM = CXXSpecialMemberKind::MoveAssignment;
break;
};
bool ConstRHS = false;
if (Meth->getNumParams()) {
if (const ReferenceType *RT =
Meth->getParamDecl(0)->getType()->getAs<ReferenceType>()) {
ConstRHS = RT->getPointeeType().isConstQualified();
}
}
S.CUDA().inferTargetForImplicitSpecialMember(ParentClass, CSM, Meth,
ConstRHS,
true);
}
}
static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
FunctionDecl *Callee = Cand->Function;
EnableIfAttr *Attr = static_cast<EnableIfAttr*>(Cand->DeductionFailure.Data);
S.Diag(Callee->getLocation(),
diag::note_ovl_candidate_disabled_by_function_cond_attr)
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
}
static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Cand->Function);
assert(ES.isExplicit() && "not an explicit candidate");
unsigned Kind;
switch (Cand->Function->getDeclKind()) {
case Decl::Kind::CXXConstructor:
Kind = 0;
break;
case Decl::Kind::CXXConversion:
Kind = 1;
break;
case Decl::Kind::CXXDeductionGuide:
Kind = Cand->Function->isImplicit() ? 0 : 2;
break;
default:
llvm_unreachable("invalid Decl");
}
FunctionDecl *First = Cand->Function->getFirstDecl();
if (FunctionDecl *Pattern = First->getTemplateInstantiationPattern())
First = Pattern->getFirstDecl();
S.Diag(First->getLocation(),
diag::note_ovl_candidate_explicit)
<< Kind << (ES.getExpr() ? 1 : 0)
<< (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange());
}
static void NoteImplicitDeductionGuide(Sema &S, FunctionDecl *Fn) {
auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
if (!DG)
return;
TemplateDecl *OriginTemplate =
DG->getDeclName().getCXXDeductionGuideTemplate();
if (!(DG->isImplicit() || (OriginTemplate && OriginTemplate->isTypeAlias())))
return;
std::string FunctionProto;
llvm::raw_string_ostream OS(FunctionProto);
FunctionTemplateDecl *Template = DG->getDescribedFunctionTemplate();
if (!Template) {
FunctionDecl *Pattern =
DG->getTemplateInstantiationPattern(false);
if (!Pattern) {
assert(OriginTemplate->isTypeAlias() &&
"Non-template implicit deduction guides are only possible for "
"type aliases");
DG->print(OS);
S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
<< FunctionProto;
return;
}
Template = Pattern->getDescribedFunctionTemplate();
assert(Template && "Cannot find the associated function template of "
"CXXDeductionGuideDecl?");
}
Template->print(OS);
S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
<< FunctionProto;
}
static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
unsigned NumArgs,
bool TakingCandidateAddress,
LangAS CtorDestAS = LangAS::Default) {
FunctionDecl *Fn = Cand->Function;
if (shouldSkipNotingLambdaConversionDecl(Fn))
return;
if (S.getLangOpts().OpenCL && Fn->isImplicit() &&
Cand->FailureKind != ovl_fail_bad_conversion)
return;
if (Cand->TookAddressOfOverload &&
!Cand->Function->hasCXXExplicitFunctionObjectParameter() &&
!Cand->Function->isStatic())
return;
if (Cand->Viable) {
if (Fn->isDeleted()) {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn,
Cand->getRewriteKind(), FnDesc);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< (Fn->isDeleted() ? (Fn->isDeletedAsWritten() ? 1 : 2) : 0);
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind());
return;
}
auto _ = llvm::make_scope_exit([&] { NoteImplicitDeductionGuide(S, Fn); });
switch (Cand->FailureKind) {
case ovl_fail_too_many_arguments:
case ovl_fail_too_few_arguments:
return DiagnoseArityMismatch(S, Cand, NumArgs);
case ovl_fail_bad_deduction:
return DiagnoseBadDeduction(S, Cand, NumArgs,
TakingCandidateAddress);
case ovl_fail_illegal_constructor: {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_illegal_constructor)
<< (Fn->getPrimaryTemplate() ? 1 : 0);
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
case ovl_fail_object_addrspace_mismatch: {
Qualifiers QualsForPrinting;
QualsForPrinting.setAddressSpace(CtorDestAS);
S.Diag(Fn->getLocation(),
diag::note_ovl_candidate_illegal_constructor_adrspace_mismatch)
<< QualsForPrinting;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
case ovl_fail_final_conversion_not_exact:
return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind());
case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
for (unsigned N = Cand->Conversions.size(); I != N; ++I)
if (Cand->Conversions[I].isInitialized() && Cand->Conversions[I].isBad())
return DiagnoseBadConversion(S, Cand, I, TakingCandidateAddress);
return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind());
}
case ovl_fail_bad_target:
return DiagnoseBadTarget(S, Cand);
case ovl_fail_enable_if:
return DiagnoseFailedEnableIfAttr(S, Cand);
case ovl_fail_explicit:
return DiagnoseFailedExplicitSpec(S, Cand);
case ovl_fail_inhctor_slice:
if (cast<CXXConstructorDecl>(Fn)->isCopyOrMoveConstructor())
return;
S.Diag(Fn->getLocation(),
diag::note_ovl_candidate_inherited_constructor_slice)
<< (Fn->getPrimaryTemplate() ? 1 : 0)
<< Fn->getParamDecl(0)->getType()->isRValueReferenceType();
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
case ovl_fail_addr_not_available: {
bool Available = checkAddressOfCandidateIsAvailable(S, Cand->Function);
(void)Available;
assert(!Available);
break;
}
case ovl_non_default_multiversion_function:
break;
case ovl_fail_constraints_not_satisfied: {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn,
Cand->getRewriteKind(), FnDesc);
S.Diag(Fn->getLocation(),
diag::note_ovl_candidate_constraints_not_satisfied)
<< (unsigned)FnKindPair.first << (unsigned)ocs_non_template
<< FnDesc ;
ConstraintSatisfaction Satisfaction;
if (S.CheckFunctionConstraints(Fn, Satisfaction))
break;
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
}
}
}
static void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
if (shouldSkipNotingLambdaConversionDecl(Cand->Surrogate))
return;
QualType FnType = Cand->Surrogate->getConversionType();
bool isLValueReference = false;
bool isRValueReference = false;
bool isPointer = false;
if (const LValueReferenceType *FnTypeRef =
FnType->getAs<LValueReferenceType>()) {
FnType = FnTypeRef->getPointeeType();
isLValueReference = true;
} else if (const RValueReferenceType *FnTypeRef =
FnType->getAs<RValueReferenceType>()) {
FnType = FnTypeRef->getPointeeType();
isRValueReference = true;
}
if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) {
FnType = FnTypePtr->getPointeeType();
isPointer = true;
}
FnType = QualType(FnType->getAs<FunctionType>(), 0);
if (isPointer) FnType = S.Context.getPointerType(FnType);
if (isRValueReference) FnType = S.Context.getRValueReferenceType(FnType);
if (isLValueReference) FnType = S.Context.getLValueReferenceType(FnType);
if (!Cand->Viable &&
Cand->FailureKind == ovl_fail_constraints_not_satisfied) {
S.Diag(Cand->Surrogate->getLocation(),
diag::note_ovl_surrogate_constraints_not_satisfied)
<< Cand->Surrogate;
ConstraintSatisfaction Satisfaction;
if (S.CheckFunctionConstraints(Cand->Surrogate, Satisfaction))
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
} else {
S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand)
<< FnType;
}
}
static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
SourceLocation OpLoc,
OverloadCandidate *Cand) {
assert(Cand->Conversions.size() <= 2 && "builtin operator is not binary");
std::string TypeStr("operator");
TypeStr += Opc;
TypeStr += "(";
TypeStr += Cand->BuiltinParamTypes[0].getAsString();
if (Cand->Conversions.size() == 1) {
TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_candidate) << TypeStr;
} else {
TypeStr += ", ";
TypeStr += Cand->BuiltinParamTypes[1].getAsString();
TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_candidate) << TypeStr;
}
}
static void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
OverloadCandidate *Cand) {
for (const ImplicitConversionSequence &ICS : Cand->Conversions) {
if (ICS.isBad()) break;
if (!ICS.isAmbiguous()) continue;
ICS.DiagnoseAmbiguousConversion(
S, OpLoc, S.PDiag(diag::note_ambiguous_type_conversion));
}
}
static SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) {
if (Cand->Function)
return Cand->Function->getLocation();
if (Cand->IsSurrogate)
return Cand->Surrogate->getLocation();
return SourceLocation();
}
static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
switch (static_cast<TemplateDeductionResult>(DFI.Result)) {
case TemplateDeductionResult::Success:
case TemplateDeductionResult::NonDependentConversionFailure:
case TemplateDeductionResult::AlreadyDiagnosed:
llvm_unreachable("non-deduction failure while diagnosing bad deduction");
case TemplateDeductionResult::Invalid:
case TemplateDeductionResult::Incomplete:
case TemplateDeductionResult::IncompletePack:
return 1;
case TemplateDeductionResult::Underqualified:
case TemplateDeductionResult::Inconsistent:
return 2;
case TemplateDeductionResult::SubstitutionFailure:
case TemplateDeductionResult::DeducedMismatch:
case TemplateDeductionResult::ConstraintsNotSatisfied:
case TemplateDeductionResult::DeducedMismatchNested:
case TemplateDeductionResult::NonDeducedMismatch:
case TemplateDeductionResult::MiscellaneousDeductionFailure:
case TemplateDeductionResult::CUDATargetMismatch:
return 3;
case TemplateDeductionResult::InstantiationDepth:
return 4;
case TemplateDeductionResult::InvalidExplicitArguments:
return 5;
case TemplateDeductionResult::TooManyArguments:
case TemplateDeductionResult::TooFewArguments:
return 6;
}
llvm_unreachable("Unhandled deduction result");
}
namespace {
struct CompareOverloadCandidatesForDisplay {
Sema &S;
SourceLocation Loc;
size_t NumArgs;
OverloadCandidateSet::CandidateSetKind CSK;
CompareOverloadCandidatesForDisplay(
Sema &S, SourceLocation Loc, size_t NArgs,
OverloadCandidateSet::CandidateSetKind CSK)
: S(S), NumArgs(NArgs), CSK(CSK) {}
OverloadFailureKind EffectiveFailureKind(const OverloadCandidate *C) const {
if (C->FailureKind == ovl_fail_too_many_arguments ||
C->FailureKind == ovl_fail_too_few_arguments)
return static_cast<OverloadFailureKind>(C->FailureKind);
if (C->Function) {
if (NumArgs > C->Function->getNumParams() && !C->Function->isVariadic())
return ovl_fail_too_many_arguments;
if (NumArgs < C->Function->getMinRequiredArguments())
return ovl_fail_too_few_arguments;
}
return static_cast<OverloadFailureKind>(C->FailureKind);
}
bool operator()(const OverloadCandidate *L,
const OverloadCandidate *R) {
if (L == R) return false;
if (L->Viable) {
if (!R->Viable) return true;
if (int Ord = CompareConversions(*L, *R))
return Ord < 0;
} else if (R->Viable)
return false;
assert(L->Viable == R->Viable);
if (!L->Viable) {
OverloadFailureKind LFailureKind = EffectiveFailureKind(L);
OverloadFailureKind RFailureKind = EffectiveFailureKind(R);
if (LFailureKind == ovl_fail_too_many_arguments ||
LFailureKind == ovl_fail_too_few_arguments) {
if (RFailureKind == ovl_fail_too_many_arguments ||
RFailureKind == ovl_fail_too_few_arguments) {
int LDist = std::abs((int)L->getNumParams() - (int)NumArgs);
int RDist = std::abs((int)R->getNumParams() - (int)NumArgs);
if (LDist == RDist) {
if (LFailureKind == RFailureKind)
return !L->IsSurrogate && R->IsSurrogate;
return LFailureKind == ovl_fail_too_many_arguments;
}
return LDist < RDist;
}
return false;
}
if (RFailureKind == ovl_fail_too_many_arguments ||
RFailureKind == ovl_fail_too_few_arguments)
return true;
if (LFailureKind == ovl_fail_bad_conversion) {
if (RFailureKind != ovl_fail_bad_conversion)
return true;
unsigned numLFixes = L->Fix.NumConversionsFixed;
unsigned numRFixes = R->Fix.NumConversionsFixed;
numLFixes = (numLFixes == 0) ? UINT_MAX : numLFixes;
numRFixes = (numRFixes == 0) ? UINT_MAX : numRFixes;
if (numLFixes != numRFixes) {
return numLFixes < numRFixes;
}
if (int Ord = CompareConversions(*L, *R))
return Ord < 0;
} else if (RFailureKind == ovl_fail_bad_conversion)
return false;
if (LFailureKind == ovl_fail_bad_deduction) {
if (RFailureKind != ovl_fail_bad_deduction)
return true;
if (L->DeductionFailure.Result != R->DeductionFailure.Result) {
unsigned LRank = RankDeductionFailure(L->DeductionFailure);
unsigned RRank = RankDeductionFailure(R->DeductionFailure);
if (LRank != RRank)
return LRank < RRank;
}
} else if (RFailureKind == ovl_fail_bad_deduction)
return false;
}
SourceLocation LLoc = GetLocationForCandidate(L);
SourceLocation RLoc = GetLocationForCandidate(R);
if (LLoc.isValid() && RLoc.isValid())
return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc);
if (LLoc.isValid() && !RLoc.isValid())
return true;
if (RLoc.isValid() && !LLoc.isValid())
return false;
assert(!LLoc.isValid() && !RLoc.isValid());
return L < R;
}
private:
struct ConversionSignals {
unsigned KindRank = 0;
ImplicitConversionRank Rank = ICR_Exact_Match;
static ConversionSignals ForSequence(ImplicitConversionSequence &Seq) {
ConversionSignals Sig;
Sig.KindRank = Seq.getKindRank();
if (Seq.isStandard())
Sig.Rank = Seq.Standard.getRank();
else if (Seq.isUserDefined())
Sig.Rank = Seq.UserDefined.After.getRank();
return Sig;
}
static ConversionSignals ForObjectArgument() {
return {};
}
};
int CompareConversions(const OverloadCandidate &L,
const OverloadCandidate &R) {
assert(L.Conversions.size() == R.Conversions.size());
for (unsigned I = 0, N = L.Conversions.size(); I != N; ++I) {
auto LS = L.IgnoreObjectArgument && I == 0
? ConversionSignals::ForObjectArgument()
: ConversionSignals::ForSequence(L.Conversions[I]);
auto RS = R.IgnoreObjectArgument
? ConversionSignals::ForObjectArgument()
: ConversionSignals::ForSequence(R.Conversions[I]);
if (std::tie(LS.KindRank, LS.Rank) != std::tie(RS.KindRank, RS.Rank))
return std::tie(LS.KindRank, LS.Rank) < std::tie(RS.KindRank, RS.Rank)
? -1
: 1;
}
return 0;
}
};
}
static void
CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
ArrayRef<Expr *> Args,
OverloadCandidateSet::CandidateSetKind CSK) {
assert(!Cand->Viable);
if (Cand->FailureKind != ovl_fail_bad_conversion)
return;
bool Unfixable = false;
Cand->Fix.setConversionChecker(TryCopyInitialization);
unsigned ConvCount = Cand->Conversions.size();
for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); ;
++ConvIdx) {
assert(ConvIdx != ConvCount && "no bad conversion in candidate");
if (Cand->Conversions[ConvIdx].isInitialized() &&
Cand->Conversions[ConvIdx].isBad()) {
Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
break;
}
}
bool SuppressUserConversions = false;
unsigned ConvIdx = 0;
unsigned ArgIdx = 0;
ArrayRef<QualType> ParamTypes;
bool Reversed = Cand->isReversed();
if (Cand->IsSurrogate) {
QualType ConvType
= Cand->Surrogate->getConversionType().getNonReferenceType();
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
ConvType = ConvPtrType->getPointeeType();
ParamTypes = ConvType->castAs<FunctionProtoType>()->getParamTypes();
ConvIdx = 1;
} else if (Cand->Function) {
ParamTypes =
Cand->Function->getType()->castAs<FunctionProtoType>()->getParamTypes();
if (isa<CXXMethodDecl>(Cand->Function) &&
!isa<CXXConstructorDecl>(Cand->Function) && !Reversed) {
ConvIdx = 1;
if (CSK == OverloadCandidateSet::CSK_Operator &&
Cand->Function->getDeclName().getCXXOverloadedOperator() != OO_Call &&
Cand->Function->getDeclName().getCXXOverloadedOperator() !=
OO_Subscript)
ArgIdx = 1;
}
} else {
assert(ConvCount <= 3);
ParamTypes = Cand->BuiltinParamTypes;
}
for (unsigned ParamIdx = Reversed ? ParamTypes.size() - 1 : 0;
ConvIdx != ConvCount;
++ConvIdx, ++ArgIdx, ParamIdx += (Reversed ? -1 : 1)) {
assert(ArgIdx < Args.size() && "no argument for this arg conversion");
if (Cand->Conversions[ConvIdx].isInitialized()) {
} else if (ParamIdx < ParamTypes.size()) {
if (ParamTypes[ParamIdx]->isDependentType())
Cand->Conversions[ConvIdx].setAsIdentityConversion(
Args[ArgIdx]->getType());
else {
Cand->Conversions[ConvIdx] =
TryCopyInitialization(S, Args[ArgIdx], ParamTypes[ParamIdx],
SuppressUserConversions,
true,
S.getLangOpts().ObjCAutoRefCount);
if (!Unfixable && Cand->Conversions[ConvIdx].isBad())
Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
}
} else
Cand->Conversions[ConvIdx].setEllipsis();
}
}
SmallVector<OverloadCandidate *, 32> OverloadCandidateSet::CompleteCandidates(
Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args,
SourceLocation OpLoc,
llvm::function_ref<bool(OverloadCandidate &)> Filter) {
SmallVector<OverloadCandidate*, 32> Cands;
if (OCD == OCD_AllCandidates) Cands.reserve(size());
for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) {
if (!Filter(*Cand))
continue;
switch (OCD) {
case OCD_AllCandidates:
if (!Cand->Viable) {
if (!Cand->Function && !Cand->IsSurrogate) {
continue;
}
CompleteNonViableCandidate(S, Cand, Args, Kind);
}
break;
case OCD_ViableCandidates:
if (!Cand->Viable)
continue;
break;
case OCD_AmbiguousCandidates:
if (!Cand->Best)
continue;
break;
}
Cands.push_back(Cand);
}
llvm::stable_sort(
Cands, CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind));
return Cands;
}
bool OverloadCandidateSet::shouldDeferDiags(Sema &S, ArrayRef<Expr *> Args,
SourceLocation OpLoc) {
bool DeferHint = false;
if (S.getLangOpts().CUDA && S.getLangOpts().GPUDeferDiag) {
auto WrongSidedCands =
CompleteCandidates(S, OCD_AllCandidates, Args, OpLoc, [](auto &Cand) {
return (Cand.Viable == false &&
Cand.FailureKind == ovl_fail_bad_target) ||
(Cand.Function &&
Cand.Function->template hasAttr<CUDAHostAttr>() &&
Cand.Function->template hasAttr<CUDADeviceAttr>());
});
DeferHint = !WrongSidedCands.empty();
}
return DeferHint;
}
void OverloadCandidateSet::NoteCandidates(
PartialDiagnosticAt PD, Sema &S, OverloadCandidateDisplayKind OCD,
ArrayRef<Expr *> Args, StringRef Opc, SourceLocation OpLoc,
llvm::function_ref<bool(OverloadCandidate &)> Filter) {
auto Cands = CompleteCandidates(S, OCD, Args, OpLoc, Filter);
S.Diag(PD.first, PD.second, shouldDeferDiags(S, Args, OpLoc));
bool NoteCands = true;
for (const Expr *Arg : Args) {
if (Arg->getType()->isWebAssemblyTableType())
NoteCands = false;
}
if (NoteCands)
NoteCandidates(S, Args, Cands, Opc, OpLoc);
if (OCD == OCD_AmbiguousCandidates)
MaybeDiagnoseAmbiguousConstraints(S, {begin(), end()});
}
void OverloadCandidateSet::NoteCandidates(Sema &S, ArrayRef<Expr *> Args,
ArrayRef<OverloadCandidate *> Cands,
StringRef Opc, SourceLocation OpLoc) {
bool ReportedAmbiguousConversions = false;
const OverloadsShown ShowOverloads = S.Diags.getShowOverloads();
unsigned CandsShown = 0;
auto I = Cands.begin(), E = Cands.end();
for (; I != E; ++I) {
OverloadCandidate *Cand = *I;
if (CandsShown >= S.Diags.getNumOverloadCandidatesToShow() &&
ShowOverloads == Ovl_Best) {
break;
}
++CandsShown;
if (Cand->Function)
NoteFunctionCandidate(S, Cand, Args.size(),
false, DestAS);
else if (Cand->IsSurrogate)
NoteSurrogateCandidate(S, Cand);
else {
assert(Cand->Viable &&
"Non-viable built-in candidates are not added to Cands.");
if (!ReportedAmbiguousConversions) {
NoteAmbiguousUserConversions(S, OpLoc, Cand);
ReportedAmbiguousConversions = true;
}
NoteBuiltinOperatorCandidate(S, Opc, OpLoc, Cand);
}
}
S.Diags.overloadCandidatesShown(CandsShown);
if (I != E)
S.Diag(OpLoc, diag::note_ovl_too_many_candidates,
shouldDeferDiags(S, Args, OpLoc))
<< int(E - I);
}
static SourceLocation
GetLocationForCandidate(const TemplateSpecCandidate *Cand) {
return Cand->Specialization ? Cand->Specialization->getLocation()
: SourceLocation();
}
namespace {
struct CompareTemplateSpecCandidatesForDisplay {
Sema &S;
CompareTemplateSpecCandidatesForDisplay(Sema &S) : S(S) {}
bool operator()(const TemplateSpecCandidate *L,
const TemplateSpecCandidate *R) {
if (L == R)
return false;
if (L->DeductionFailure.Result != R->DeductionFailure.Result)
return RankDeductionFailure(L->DeductionFailure) <
RankDeductionFailure(R->DeductionFailure);
SourceLocation LLoc = GetLocationForCandidate(L);
SourceLocation RLoc = GetLocationForCandidate(R);
if (LLoc.isInvalid())
return false;
if (RLoc.isInvalid())
return true;
return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc);
}
};
}
void TemplateSpecCandidate::NoteDeductionFailure(Sema &S,
bool ForTakingAddress) {
DiagnoseBadDeduction(S, FoundDecl, Specialization,
DeductionFailure, 0, ForTakingAddress);
}
void TemplateSpecCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
i->DeductionFailure.Destroy();
}
}
void TemplateSpecCandidateSet::clear() {
destroyCandidates();
Candidates.clear();
}
void TemplateSpecCandidateSet::NoteCandidates(Sema &S, SourceLocation Loc) {
SmallVector<TemplateSpecCandidate *, 32> Cands;
Cands.reserve(size());
for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) {
if (Cand->Specialization)
Cands.push_back(Cand);
}
llvm::sort(Cands, CompareTemplateSpecCandidatesForDisplay(S));
const OverloadsShown ShowOverloads = S.Diags.getShowOverloads();
SmallVectorImpl<TemplateSpecCandidate *>::iterator I, E;
unsigned CandsShown = 0;
for (I = Cands.begin(), E = Cands.end(); I != E; ++I) {
TemplateSpecCandidate *Cand = *I;
if (CandsShown >= 4 && ShowOverloads == Ovl_Best)
break;
++CandsShown;
assert(Cand->Specialization &&
"Non-matching built-in candidates are not added to Cands.");
Cand->NoteDeductionFailure(S, ForTakingAddress);
}
if (I != E)
S.Diag(Loc, diag::note_ovl_too_many_candidates) << int(E - I);
}
QualType Sema::ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType) {
QualType Ret = PossiblyAFunctionType;
if (const PointerType *ToTypePtr =
PossiblyAFunctionType->getAs<PointerType>())
Ret = ToTypePtr->getPointeeType();
else if (const ReferenceType *ToTypeRef =
PossiblyAFunctionType->getAs<ReferenceType>())
Ret = ToTypeRef->getPointeeType();
else if (const MemberPointerType *MemTypePtr =
PossiblyAFunctionType->getAs<MemberPointerType>())
Ret = MemTypePtr->getPointeeType();
Ret =
Context.getCanonicalType(Ret).getUnqualifiedType();
return Ret;
}
static bool completeFunctionType(Sema &S, FunctionDecl *FD, SourceLocation Loc,
bool Complain = true) {
if (S.getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() &&
S.DeduceReturnType(FD, Loc, Complain))
return true;
auto *FPT = FD->getType()->castAs<FunctionProtoType>();
if (S.getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
!S.ResolveExceptionSpec(Loc, FPT))
return true;
return false;
}
namespace {
class AddressOfFunctionResolver {
Sema& S;
Expr* SourceExpr;
const QualType& TargetType;
QualType TargetFunctionType;
bool Complain;
ASTContext& Context;
bool TargetTypeIsNonStaticMemberFunction;
bool FoundNonTemplateFunction;
bool StaticMemberFunctionFromBoundPointer;
bool HasComplained;
OverloadExpr::FindResult OvlExprInfo;
OverloadExpr *OvlExpr;
TemplateArgumentListInfo OvlExplicitTemplateArgs;
SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
TemplateSpecCandidateSet FailedCandidates;
public:
AddressOfFunctionResolver(Sema &S, Expr *SourceExpr,
const QualType &TargetType, bool Complain)
: S(S), SourceExpr(SourceExpr), TargetType(TargetType),
Complain(Complain), Context(S.getASTContext()),
TargetTypeIsNonStaticMemberFunction(
!!TargetType->getAs<MemberPointerType>()),
FoundNonTemplateFunction(false),
StaticMemberFunctionFromBoundPointer(false),
HasComplained(false),
OvlExprInfo(OverloadExpr::find(SourceExpr)),
OvlExpr(OvlExprInfo.Expression),
FailedCandidates(OvlExpr->getNameLoc(), true) {
ExtractUnqualifiedFunctionTypeFromTargetType();
if (TargetFunctionType->isFunctionType()) {
if (UnresolvedMemberExpr *UME = dyn_cast<UnresolvedMemberExpr>(OvlExpr))
if (!UME->isImplicitAccess() &&
!S.ResolveSingleFunctionTemplateSpecialization(UME))
StaticMemberFunctionFromBoundPointer = true;
} else if (OvlExpr->hasExplicitTemplateArgs()) {
DeclAccessPair dap;
if (FunctionDecl *Fn = S.ResolveSingleFunctionTemplateSpecialization(
OvlExpr, false, &dap)) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
if (!Method->isStatic()) {
TargetTypeIsNonStaticMemberFunction = true;
if (!OvlExprInfo.HasFormOfMemberPointer)
return;
}
Matches.push_back(std::make_pair(dap, Fn));
}
return;
}
if (OvlExpr->hasExplicitTemplateArgs())
OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs);
if (FindAllFunctionsThatMatchTargetTypeExactly()) {
if (Matches.size() > 1 && !eliminiateSuboptimalOverloadCandidates()) {
if (FoundNonTemplateFunction)
EliminateAllTemplateMatches();
else
EliminateAllExceptMostSpecializedTemplate();
}
}
if (S.getLangOpts().CUDA && Matches.size() > 1)
EliminateSuboptimalCudaMatches();
}
bool hasComplained() const { return HasComplained; }
private:
bool candidateHasExactlyCorrectType(const FunctionDecl *FD) {
QualType Discard;
return Context.hasSameUnqualifiedType(TargetFunctionType, FD->getType()) ||
S.IsFunctionConversion(FD->getType(), TargetFunctionType, Discard);
}
bool isBetterCandidate(const FunctionDecl *A, const FunctionDecl *B) {
return candidateHasExactlyCorrectType(A) &&
(!candidateHasExactlyCorrectType(B) ||
compareEnableIfAttrs(S, A, B) == Comparison::Better);
}
bool eliminiateSuboptimalOverloadCandidates() {
auto Best = Matches.begin();
for (auto I = Matches.begin()+1, E = Matches.end(); I != E; ++I)
if (isBetterCandidate(I->second, Best->second))
Best = I;
const FunctionDecl *BestFn = Best->second;
auto IsBestOrInferiorToBest = [this, BestFn](
const std::pair<DeclAccessPair, FunctionDecl *> &Pair) {
return BestFn == Pair.second || isBetterCandidate(BestFn, Pair.second);
};
if (!llvm::all_of(Matches, IsBestOrInferiorToBest))
return false;
Matches[0] = *Best;
Matches.resize(1);
return true;
}
bool isTargetTypeAFunction() const {
return TargetFunctionType->isFunctionType();
}
void inline ExtractUnqualifiedFunctionTypeFromTargetType() {
TargetFunctionType = S.ExtractUnqualifiedFunctionType(TargetType);
}
bool AddMatchingTemplateFunction(FunctionTemplateDecl* FunctionTemplate,
const DeclAccessPair& CurAccessFunPair) {
if (CXXMethodDecl *Method
= dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) {
bool CanConvertToFunctionPointer =
Method->isStatic() || Method->isExplicitObjectMemberFunction();
if (CanConvertToFunctionPointer == TargetTypeIsNonStaticMemberFunction)
return false;
}
else if (TargetTypeIsNonStaticMemberFunction)
return false;
FunctionDecl *Specialization = nullptr;
TemplateDeductionInfo Info(FailedCandidates.getLocation());
if (TemplateDeductionResult Result = S.DeduceTemplateArguments(
FunctionTemplate, &OvlExplicitTemplateArgs, TargetFunctionType,
Specialization, Info, true);
Result != TemplateDeductionResult::Success) {
FailedCandidates.addCandidate()
.set(CurAccessFunPair, FunctionTemplate->getTemplatedDecl(),
MakeDeductionFailureInfo(Context, Result, Info));
return false;
}
assert(S.isSameOrCompatibleFunctionType(
Context.getCanonicalType(Specialization->getType()),
Context.getCanonicalType(TargetFunctionType)));
if (!S.checkAddressOfFunctionIsAvailable(Specialization))
return false;
Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
return true;
}
bool AddMatchingNonTemplateFunction(NamedDecl* Fn,
const DeclAccessPair& CurAccessFunPair) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
bool CanConvertToFunctionPointer =
Method->isStatic() || Method->isExplicitObjectMemberFunction();
if (CanConvertToFunctionPointer == TargetTypeIsNonStaticMemberFunction)
return false;
}
else if (TargetTypeIsNonStaticMemberFunction)
return false;
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) {
if (S.getLangOpts().CUDA) {
FunctionDecl *Caller = S.getCurFunctionDecl(true);
if (!(Caller && Caller->isImplicit()) &&
!S.CUDA().IsAllowedCall(Caller, FunDecl))
return false;
}
if (FunDecl->isMultiVersion()) {
const auto *TA = FunDecl->getAttr<TargetAttr>();
if (TA && !TA->isDefaultVersion())
return false;
const auto *TVA = FunDecl->getAttr<TargetVersionAttr>();
if (TVA && !TVA->isDefaultVersion())
return false;
}
if (completeFunctionType(S, FunDecl, SourceExpr->getBeginLoc(),
Complain)) {
HasComplained |= Complain;
return false;
}
if (!S.checkAddressOfFunctionIsAvailable(FunDecl))
return false;
if (!S.getLangOpts().CPlusPlus ||
candidateHasExactlyCorrectType(FunDecl)) {
Matches.push_back(std::make_pair(
CurAccessFunPair, cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
FoundNonTemplateFunction = true;
return true;
}
}
return false;
}
bool FindAllFunctionsThatMatchTargetTypeExactly() {
bool Ret = false;
if (IsInvalidFormOfPointerToMemberFunction())
return false;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
E = OvlExpr->decls_end();
I != E; ++I) {
NamedDecl *Fn = (*I)->getUnderlyingDecl();
if (FunctionTemplateDecl *FunctionTemplate
= dyn_cast<FunctionTemplateDecl>(Fn)) {
if (AddMatchingTemplateFunction(FunctionTemplate, I.getPair()))
Ret = true;
}
else if (!OvlExpr->hasExplicitTemplateArgs() &&
AddMatchingNonTemplateFunction(Fn, I.getPair()))
Ret = true;
}
assert(Ret || Matches.empty());
return Ret;
}
void EliminateAllExceptMostSpecializedTemplate() {
UnresolvedSet<4> MatchesCopy;
for (unsigned I = 0, E = Matches.size(); I != E; ++I)
MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess());
UnresolvedSetIterator Result = S.getMostSpecialized(
MatchesCopy.begin(), MatchesCopy.end(), FailedCandidates,
SourceExpr->getBeginLoc(), S.PDiag(),
S.PDiag(diag::err_addr_ovl_ambiguous)
<< Matches[0].second->getDeclName(),
S.PDiag(diag::note_ovl_candidate)
<< (unsigned)oc_function << (unsigned)ocs_described_template,
Complain, TargetFunctionType);
if (Result != MatchesCopy.end()) {
Matches[0].first = Matches[Result - MatchesCopy.begin()].first;
Matches[0].second = cast<FunctionDecl>(*Result);
Matches.resize(1);
} else
HasComplained |= Complain;
}
void EliminateAllTemplateMatches() {
for (unsigned I = 0, N = Matches.size(); I != N; ) {
if (Matches[I].second->getPrimaryTemplate() == nullptr)
++I;
else {
Matches[I] = Matches[--N];
Matches.resize(N);
}
}
}
void EliminateSuboptimalCudaMatches() {
S.CUDA().EraseUnwantedMatches(S.getCurFunctionDecl(true),
Matches);
}
public:
void ComplainNoMatchesFound() const {
assert(Matches.empty());
S.Diag(OvlExpr->getBeginLoc(), diag::err_addr_ovl_no_viable)
<< OvlExpr->getName() << TargetFunctionType
<< OvlExpr->getSourceRange();
if (FailedCandidates.empty())
S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType,
true);
else {
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
IEnd = OvlExpr->decls_end();
I != IEnd; ++I)
if (FunctionDecl *Fun =
dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
if (!functionHasPassObjectSizeParams(Fun))
S.NoteOverloadCandidate(*I, Fun, CRK_None, TargetFunctionType,
true);
FailedCandidates.NoteCandidates(S, OvlExpr->getBeginLoc());
}
}
bool IsInvalidFormOfPointerToMemberFunction() const {
return TargetTypeIsNonStaticMemberFunction &&
!OvlExprInfo.HasFormOfMemberPointer;
}
void ComplainIsInvalidFormOfPointerToMemberFunction() const {
S.Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier)
<< TargetType << OvlExpr->getSourceRange();
}
bool IsStaticMemberFunctionFromBoundPointer() const {
return StaticMemberFunctionFromBoundPointer;
}
void ComplainIsStaticMemberFunctionFromBoundPointer() const {
S.Diag(OvlExpr->getBeginLoc(),
diag::err_invalid_form_pointer_member_function)
<< OvlExpr->getSourceRange();
}
void ComplainOfInvalidConversion() const {
S.Diag(OvlExpr->getBeginLoc(), diag::err_addr_ovl_not_func_ptrref)
<< OvlExpr->getName() << TargetType;
}
void ComplainMultipleMatchesFound() const {
assert(Matches.size() > 1);
S.Diag(OvlExpr->getBeginLoc(), diag::err_addr_ovl_ambiguous)
<< OvlExpr->getName() << OvlExpr->getSourceRange();
S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType,
true);
}
bool hadMultipleCandidates() const { return (OvlExpr->getNumDecls() > 1); }
int getNumMatches() const { return Matches.size(); }
FunctionDecl* getMatchingFunctionDecl() const {
if (Matches.size() != 1) return nullptr;
return Matches[0].second;
}
const DeclAccessPair* getMatchingFunctionAccessPair() const {
if (Matches.size() != 1) return nullptr;
return &Matches[0].first;
}
};
}
FunctionDecl *
Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
QualType TargetType,
bool Complain,
DeclAccessPair &FoundResult,
bool *pHadMultipleCandidates) {
assert(AddressOfExpr->getType() == Context.OverloadTy);
AddressOfFunctionResolver Resolver(*this, AddressOfExpr, TargetType,
Complain);
int NumMatches = Resolver.getNumMatches();
FunctionDecl *Fn = nullptr;
bool ShouldComplain = Complain && !Resolver.hasComplained();
if (NumMatches == 0 && ShouldComplain) {
if (Resolver.IsInvalidFormOfPointerToMemberFunction())
Resolver.ComplainIsInvalidFormOfPointerToMemberFunction();
else
Resolver.ComplainNoMatchesFound();
}
else if (NumMatches > 1 && ShouldComplain)
Resolver.ComplainMultipleMatchesFound();
else if (NumMatches == 1) {
Fn = Resolver.getMatchingFunctionDecl();
assert(Fn);
if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>())
ResolveExceptionSpec(AddressOfExpr->getExprLoc(), FPT);
FoundResult = *Resolver.getMatchingFunctionAccessPair();
if (Complain) {
if (Resolver.IsStaticMemberFunctionFromBoundPointer())
Resolver.ComplainIsStaticMemberFunctionFromBoundPointer();
else
CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
}
}
if (pHadMultipleCandidates)
*pHadMultipleCandidates = Resolver.hadMultipleCandidates();
return Fn;
}
FunctionDecl *
Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
OverloadExpr::FindResult R = OverloadExpr::find(E);
OverloadExpr *Ovl = R.Expression;
bool IsResultAmbiguous = false;
FunctionDecl *Result = nullptr;
DeclAccessPair DAP;
SmallVector<FunctionDecl *, 2> AmbiguousDecls;
auto CheckCUDAPreference = [&](FunctionDecl *FD1, FunctionDecl *FD2) {
FunctionDecl *Caller = getCurFunctionDecl(true);
return static_cast<int>(CUDA().IdentifyPreference(Caller, FD1)) -
static_cast<int>(CUDA().IdentifyPreference(Caller, FD2));
};
for (auto I = Ovl->decls_begin(), E = Ovl->decls_end(); I != E; ++I) {
auto *FD = dyn_cast<FunctionDecl>(I->getUnderlyingDecl());
if (!FD)
return nullptr;
if (!checkAddressOfFunctionIsAvailable(FD))
continue;
auto FoundBetter = [&]() {
IsResultAmbiguous = false;
DAP = I.getPair();
Result = FD;
};
if (Result) {
if (getLangOpts().CUDA) {
int PreferenceByCUDA = CheckCUDAPreference(FD, Result);
if (PreferenceByCUDA != 0) {
if (PreferenceByCUDA > 0)
FoundBetter();
continue;
}
}
FunctionDecl *MoreConstrained = getMoreConstrainedFunction(FD, Result);
if (MoreConstrained != FD) {
if (!MoreConstrained) {
IsResultAmbiguous = true;
AmbiguousDecls.push_back(FD);
}
continue;
}
}
FoundBetter();
}
if (IsResultAmbiguous)
return nullptr;
if (Result) {
SmallVector<const Expr *, 1> ResultAC;
for (FunctionDecl *Skipped : AmbiguousDecls) {
if (getLangOpts().CUDA && CheckCUDAPreference(Skipped, Result) != 0)
continue;
if (!getMoreConstrainedFunction(Skipped, Result))
return nullptr;
}
Pair = DAP;
}
return Result;
}
bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
ExprResult &SrcExpr, bool DoFunctionPointerConversion) {
Expr *E = SrcExpr.get();
assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
DeclAccessPair DAP;
FunctionDecl *Found = resolveAddressOfSingleOverloadCandidate(E, DAP);
if (!Found || Found->isCPUDispatchMultiVersion() ||
Found->isCPUSpecificMultiVersion())
return false;
DiagnoseUseOfDecl(Found, E->getExprLoc());
CheckAddressOfMemberAccess(E, DAP);
ExprResult Res = FixOverloadedFunctionReference(E, DAP, Found);
if (Res.isInvalid())
return false;
Expr *Fixed = Res.get();
if (DoFunctionPointerConversion && Fixed->getType()->isFunctionType())
SrcExpr = DefaultFunctionArrayConversion(Fixed, false);
else
SrcExpr = Fixed;
return true;
}
FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(
OverloadExpr *ovl, bool Complain, DeclAccessPair *FoundResult,
TemplateSpecCandidateSet *FailedTSC) {
if (!ovl->hasExplicitTemplateArgs())
return nullptr;
TemplateArgumentListInfo ExplicitTemplateArgs;
ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs);
FunctionDecl *Matched = nullptr;
for (UnresolvedSetIterator I = ovl->decls_begin(),
E = ovl->decls_end(); I != E; ++I) {
FunctionTemplateDecl *FunctionTemplate
= cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl());
FunctionDecl *Specialization = nullptr;
TemplateDeductionInfo Info(ovl->getNameLoc());
if (TemplateDeductionResult Result = DeduceTemplateArguments(
FunctionTemplate, &ExplicitTemplateArgs, Specialization, Info,
true);
Result != TemplateDeductionResult::Success) {
if (FailedTSC)
FailedTSC->addCandidate().set(
I.getPair(), FunctionTemplate->getTemplatedDecl(),
MakeDeductionFailureInfo(Context, Result, Info));
continue;
}
assert(Specialization && "no specialization and no error?");
if (Matched) {
if (Complain) {
Diag(ovl->getExprLoc(), diag::err_addr_ovl_ambiguous)
<< ovl->getName();
NoteAllOverloadCandidates(ovl);
}
return nullptr;
}
Matched = Specialization;
if (FoundResult) *FoundResult = I.getPair();
}
if (Matched &&
completeFunctionType(*this, Matched, ovl->getExprLoc(), Complain))
return nullptr;
return Matched;
}
bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
ExprResult &SrcExpr, bool doFunctionPointerConversion, bool complain,
SourceRange OpRangeForComplaining, QualType DestTypeForComplaining,
unsigned DiagIDForComplaining) {
assert(SrcExpr.get()->getType() == Context.OverloadTy);
OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr.get());
DeclAccessPair found;
ExprResult SingleFunctionExpression;
if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization(
ovl.Expression, false, &found)) {
if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getBeginLoc())) {
SrcExpr = ExprError();
return true;
}
if (!ovl.HasFormOfMemberPointer &&
isa<CXXMethodDecl>(fn) &&
cast<CXXMethodDecl>(fn)->isInstance()) {
if (!complain) return false;
Diag(ovl.Expression->getExprLoc(),
diag::err_bound_member_function)
<< 0 << ovl.Expression->getSourceRange();
SrcExpr = ExprError();
return true;
}
SingleFunctionExpression =
FixOverloadedFunctionReference(SrcExpr.get(), found, fn);
if (doFunctionPointerConversion) {
SingleFunctionExpression =
DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.get());
if (SingleFunctionExpression.isInvalid()) {
SrcExpr = ExprError();
return true;
}
}
}
if (!SingleFunctionExpression.isUsable()) {
if (complain) {
Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining)
<< ovl.Expression->getName()
<< DestTypeForComplaining
<< OpRangeForComplaining
<< ovl.Expression->getQualifierLoc().getSourceRange();
NoteAllOverloadCandidates(SrcExpr.get());
SrcExpr = ExprError();
return true;
}
return false;
}
SrcExpr = SingleFunctionExpression;
return true;
}
static void AddOverloadedCallCandidate(Sema &S,
DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading,
bool KnownValid) {
NamedDecl *Callee = FoundDecl.getDecl();
if (isa<UsingShadowDecl>(Callee))
Callee = cast<UsingShadowDecl>(Callee)->getTargetDecl();
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
if (ExplicitTemplateArgs) {
assert(!KnownValid && "Explicit template arguments?");
return;
}
if (!isa<FunctionProtoType>(Func->getType()->getAs<FunctionType>()))
return;
S.AddOverloadCandidate(Func, FoundDecl, Args, CandidateSet,
false,
PartialOverloading);
return;
}
if (FunctionTemplateDecl *FuncTemplate
= dyn_cast<FunctionTemplateDecl>(Callee)) {
S.AddTemplateOverloadCandidate(FuncTemplate, FoundDecl,
ExplicitTemplateArgs, Args, CandidateSet,
false,
PartialOverloading);
return;
}
assert(!KnownValid && "unhandled case in overloaded call candidate");
}
void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading) {
#ifndef NDEBUG
if (ULE->requiresADL()) {
for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
E = ULE->decls_end(); I != E; ++I) {
assert(!(*I)->getDeclContext()->isRecord());
assert(isa<UsingShadowDecl>(*I) ||
!(*I)->getDeclContext()->isFunctionOrMethod());
assert((*I)->getUnderlyingDecl()->isFunctionOrFunctionTemplate());
}
}
#endif
TemplateArgumentListInfo TABuffer;
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr;
if (ULE->hasExplicitTemplateArgs()) {
ULE->copyTemplateArgumentsInto(TABuffer);
ExplicitTemplateArgs = &TABuffer;
}
for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
E = ULE->decls_end(); I != E; ++I)
AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs, Args,
CandidateSet, PartialOverloading,
true);
if (ULE->requiresADL())
AddArgumentDependentLookupCandidates(ULE->getName(), ULE->getExprLoc(),
Args, ExplicitTemplateArgs,
CandidateSet, PartialOverloading);
}
void Sema::AddOverloadedCallCandidates(
LookupResult &R, TemplateArgumentListInfo *ExplicitTemplateArgs,
ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet) {
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs, Args,
CandidateSet, false, false);
}
static bool canBeDeclaredInNamespace(const DeclarationName &Name) {
switch (Name.getCXXOverloadedOperator()) {
case OO_New: case OO_Array_New:
case OO_Delete: case OO_Array_Delete:
return false;
default:
return true;
}
}
static bool DiagnoseTwoPhaseLookup(
Sema &SemaRef, SourceLocation FnLoc, const CXXScopeSpec &SS,
LookupResult &R, OverloadCandidateSet::CandidateSetKind CSK,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
CXXRecordDecl **FoundInClass = nullptr) {
if (!SemaRef.inTemplateInstantiation() || !SS.isEmpty())
return false;
for (DeclContext *DC = SemaRef.CurContext; DC; DC = DC->getParent()) {
if (DC->isTransparentContext())
continue;
SemaRef.LookupQualifiedName(R, DC);
if (!R.empty()) {
R.suppressDiagnostics();
OverloadCandidateSet Candidates(FnLoc, CSK);
SemaRef.AddOverloadedCallCandidates(R, ExplicitTemplateArgs, Args,
Candidates);
OverloadCandidateSet::iterator Best;
OverloadingResult OR =
Candidates.BestViableFunction(SemaRef, FnLoc, Best);
if (auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
if (FoundInClass) {
*FoundInClass = RD;
if (OR == OR_Success) {
R.clear();
R.addDecl(Best->FoundDecl.getDecl(), Best->FoundDecl.getAccess());
R.resolveKind();
}
}
return false;
}
if (OR != OR_Success) {
return false;
}
Sema::AssociatedNamespaceSet AssociatedNamespaces;
Sema::AssociatedClassSet AssociatedClasses;
SemaRef.FindAssociatedClassesAndNamespaces(FnLoc, Args,
AssociatedNamespaces,
AssociatedClasses);
Sema::AssociatedNamespaceSet SuggestedNamespaces;
if (canBeDeclaredInNamespace(R.getLookupName())) {
DeclContext *Std = SemaRef.getStdNamespace();
for (Sema::AssociatedNamespaceSet::iterator
it = AssociatedNamespaces.begin(),
end = AssociatedNamespaces.end(); it != end; ++it) {
if (Std && Std->Encloses(*it))
continue;
NamespaceDecl *NS = dyn_cast<NamespaceDecl>(*it);
if (NS &&
NS->getQualifiedNameAsString().find("__") != std::string::npos)
continue;
SuggestedNamespaces.insert(*it);
}
}
SemaRef.Diag(R.getNameLoc(), diag::err_not_found_by_two_phase_lookup)
<< R.getLookupName();
if (SuggestedNamespaces.empty()) {
SemaRef.Diag(Best->Function->getLocation(),
diag::note_not_found_by_two_phase_lookup)
<< R.getLookupName() << 0;
} else if (SuggestedNamespaces.size() == 1) {
SemaRef.Diag(Best->Function->getLocation(),
diag::note_not_found_by_two_phase_lookup)
<< R.getLookupName() << 1 << *SuggestedNamespaces.begin();
} else {
SemaRef.Diag(Best->Function->getLocation(),
diag::note_not_found_by_two_phase_lookup)
<< R.getLookupName() << 2;
}
return true;
}
R.clear();
}
return false;
}
static bool
DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
SourceLocation OpLoc,
ArrayRef<Expr *> Args) {
DeclarationName OpName =
SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName);
return DiagnoseTwoPhaseLookup(SemaRef, OpLoc, CXXScopeSpec(), R,
OverloadCandidateSet::CSK_Operator,
nullptr, Args);
}
namespace {
class BuildRecoveryCallExprRAII {
Sema &SemaRef;
Sema::SatisfactionStackResetRAII SatStack;
public:
BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S), SatStack(S) {
assert(SemaRef.IsBuildingRecoveryCallExpr == false);
SemaRef.IsBuildingRecoveryCallExpr = true;
}
~BuildRecoveryCallExprRAII() { SemaRef.IsBuildingRecoveryCallExpr = false; }
};
}
static ExprResult
BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
MutableArrayRef<Expr *> Args,
SourceLocation RParenLoc,
bool EmptyLookup, bool AllowTypoCorrection) {
if (SemaRef.IsBuildingRecoveryCallExpr)
return ExprResult();
BuildRecoveryCallExprRAII RCE(SemaRef);
CXXScopeSpec SS;
SS.Adopt(ULE->getQualifierLoc());
SourceLocation TemplateKWLoc = ULE->getTemplateKeywordLoc();
TemplateArgumentListInfo TABuffer;
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr;
if (ULE->hasExplicitTemplateArgs()) {
ULE->copyTemplateArgumentsInto(TABuffer);
ExplicitTemplateArgs = &TABuffer;
}
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
CXXRecordDecl *FoundInClass = nullptr;
if (DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
OverloadCandidateSet::CSK_Normal,
ExplicitTemplateArgs, Args, &FoundInClass)) {
} else if (EmptyLookup) {
R.clear();
NoTypoCorrectionCCC NoTypoValidator{};
FunctionCallFilterCCC FunctionCallValidator(SemaRef, Args.size(),
ExplicitTemplateArgs != nullptr,
dyn_cast<MemberExpr>(Fn));
CorrectionCandidateCallback &Validator =
AllowTypoCorrection
? static_cast<CorrectionCandidateCallback &>(FunctionCallValidator)
: static_cast<CorrectionCandidateCallback &>(NoTypoValidator);
if (SemaRef.DiagnoseEmptyLookup(S, SS, R, Validator, ExplicitTemplateArgs,
Args))
return ExprError();
} else if (FoundInClass && SemaRef.getLangOpts().MSVCCompat) {
if (SemaRef.DiagnoseDependentMemberLookup(R))
return ExprError();
} else {
return ExprResult();
}
assert(!R.empty() && "lookup results empty despite recovery");
if (R.isAmbiguous()) {
R.suppressDiagnostics();
return ExprError();
}
ExprResult NewFn = ExprError();
if ((*R.begin())->isCXXClassMember())
NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R,
ExplicitTemplateArgs, S);
else if (ExplicitTemplateArgs || TemplateKWLoc.isValid())
NewFn = SemaRef.BuildTemplateIdExpr(SS, TemplateKWLoc, R, false,
ExplicitTemplateArgs);
else
NewFn = SemaRef.BuildDeclarationNameExpr(SS, R, false);
if (NewFn.isInvalid())
return ExprError();
return SemaRef.BuildCallExpr( nullptr, NewFn.get(), LParenLoc,
MultiExprArg(Args.data(), Args.size()),
RParenLoc);
}
bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
MultiExprArg Args,
SourceLocation RParenLoc,
OverloadCandidateSet *CandidateSet,
ExprResult *Result) {
#ifndef NDEBUG
if (ULE->requiresADL()) {
assert(!ULE->getQualifier() && "qualified name with ADL");
FunctionDecl *F;
if (ULE->decls_begin() != ULE->decls_end() &&
ULE->decls_begin() + 1 == ULE->decls_end() &&
(F = dyn_cast<FunctionDecl>(*ULE->decls_begin())) &&
F->getBuiltinID() && F->isImplicit())
llvm_unreachable("performing ADL for builtin");
assert(getLangOpts().CPlusPlus && "ADL enabled in C");
}
#endif
UnbridgedCastsSet UnbridgedCasts;
if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts)) {
*Result = ExprError();
return true;
}
AddOverloadedCallCandidates(ULE, Args, *CandidateSet);
if (getLangOpts().MSVCCompat &&
CurContext->isDependentContext() && !isSFINAEContext() &&
(isa<FunctionDecl>(CurContext) || isa<CXXRecordDecl>(CurContext))) {
OverloadCandidateSet::iterator Best;
if (CandidateSet->empty() ||
CandidateSet->BestViableFunction(*this, Fn->getBeginLoc(), Best) ==
OR_No_Viable_Function) {
CallExpr *CE =
CallExpr::Create(Context, Fn, Args, Context.DependentTy, VK_PRValue,
RParenLoc, CurFPFeatureOverrides());
CE->markDependentForPostponedNameLookup();
*Result = CE;
return true;
}
}
if (CandidateSet->empty())
return false;
UnbridgedCasts.restore();
return false;
}
static QualType chooseRecoveryType(OverloadCandidateSet &CS,
OverloadCandidateSet::iterator *Best) {
std::optional<QualType> Result;
auto ConsiderCandidate = [&](const OverloadCandidate &Candidate) {
if (!Candidate.Function)
return;
if (Candidate.Function->isInvalidDecl())
return;
QualType T = Candidate.Function->getReturnType();
if (T.isNull())
return;
if (!Result)
Result = T;
else if (Result != T)
Result = QualType();
};
if (Best && *Best != CS.end())
ConsiderCandidate(**Best);
if (!Result)
for (const auto &C : CS)
if (C.Viable)
ConsiderCandidate(C);
if (!Result)
for (const auto &C : CS)
ConsiderCandidate(C);
if (!Result)
return QualType();
auto Value = *Result;
if (Value.isNull() || Value->isUndeducedType())
return QualType();
return Value;
}
static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig,
OverloadCandidateSet *CandidateSet,
OverloadCandidateSet::iterator *Best,
OverloadingResult OverloadResult,
bool AllowTypoCorrection) {
switch (OverloadResult) {
case OR_Success: {
FunctionDecl *FDecl = (*Best)->Function;
SemaRef.CheckUnresolvedLookupAccess(ULE, (*Best)->FoundDecl);
if (SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc()))
return ExprError();
ExprResult Res =
SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
if (Res.isInvalid())
return ExprError();
return SemaRef.BuildResolvedCallExpr(
Res.get(), FDecl, LParenLoc, Args, RParenLoc, ExecConfig,
false, (*Best)->IsADLCandidate);
}
case OR_No_Viable_Function: {
if (*Best != CandidateSet->end() &&
CandidateSet->getKind() ==
clang::OverloadCandidateSet::CSK_AddressOfOverloadSet) {
if (CXXMethodDecl *M =
dyn_cast_if_present<CXXMethodDecl>((*Best)->Function);
M && M->isImplicitObjectMemberFunction()) {
CandidateSet->NoteCandidates(
PartialDiagnosticAt(
Fn->getBeginLoc(),
SemaRef.PDiag(diag::err_member_call_without_object) << 0 << M),
SemaRef, OCD_AmbiguousCandidates, Args);
return ExprError();
}
}
ExprResult Recovery = BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc,
Args, RParenLoc,
CandidateSet->empty(),
AllowTypoCorrection);
if (Recovery.isInvalid() || Recovery.isUsable())
return Recovery;
for (const Expr *Arg : Args) {
if (!Arg->getType()->isFunctionType())
continue;
if (auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenImpCasts())) {
auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl());
if (FD &&
!SemaRef.checkAddressOfFunctionIsAvailable(FD, true,
Arg->getExprLoc()))
return ExprError();
}
}
CandidateSet->NoteCandidates(
PartialDiagnosticAt(
Fn->getBeginLoc(),
SemaRef.PDiag(diag::err_ovl_no_viable_function_in_call)
<< ULE->getName() << Fn->getSourceRange()),
SemaRef, OCD_AllCandidates, Args);
break;
}
case OR_Ambiguous:
CandidateSet->NoteCandidates(
PartialDiagnosticAt(Fn->getBeginLoc(),
SemaRef.PDiag(diag::err_ovl_ambiguous_call)
<< ULE->getName() << Fn->getSourceRange()),
SemaRef, OCD_AmbiguousCandidates, Args);
break;
case OR_Deleted: {
FunctionDecl *FDecl = (*Best)->Function;
SemaRef.DiagnoseUseOfDeletedFunction(Fn->getBeginLoc(),
Fn->getSourceRange(), ULE->getName(),
*CandidateSet, FDecl, Args);
ExprResult Res =
SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
if (Res.isInvalid())
return ExprError();
return SemaRef.BuildResolvedCallExpr(
Res.get(), FDecl, LParenLoc, Args, RParenLoc, ExecConfig,
false, (*Best)->IsADLCandidate);
}
}
SmallVector<Expr *, 8> SubExprs = {Fn};
SubExprs.append(Args.begin(), Args.end());
return SemaRef.CreateRecoveryExpr(Fn->getBeginLoc(), RParenLoc, SubExprs,
chooseRecoveryType(*CandidateSet, Best));
}
static void markUnaddressableCandidatesUnviable(Sema &S,
OverloadCandidateSet &CS) {
for (auto I = CS.begin(), E = CS.end(); I != E; ++I) {
if (I->Viable &&
!S.checkAddressOfFunctionIsAvailable(I->Function, false)) {
I->Viable = false;
I->FailureKind = ovl_fail_addr_not_available;
}
}
}
ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig,
bool AllowTypoCorrection,
bool CalleesAddressIsTaken) {
OverloadCandidateSet CandidateSet(
Fn->getExprLoc(), CalleesAddressIsTaken
? OverloadCandidateSet::CSK_AddressOfOverloadSet
: OverloadCandidateSet::CSK_Normal);
ExprResult result;
if (buildOverloadedCallSet(S, Fn, ULE, Args, LParenLoc, &CandidateSet,
&result))
return result;
if (CalleesAddressIsTaken)
markUnaddressableCandidatesUnviable(*this, CandidateSet);
OverloadCandidateSet::iterator Best;
OverloadingResult OverloadResult =
CandidateSet.BestViableFunction(*this, Fn->getBeginLoc(), Best);
if (OverloadResult == OR_Success) {
const FunctionDecl *FDecl = Best->Function;
if (FDecl && FDecl->isTemplateInstantiation() &&
FDecl->getReturnType()->isUndeducedType()) {
if (const auto *TP =
FDecl->getTemplateInstantiationPattern(false);
TP && TP->willHaveBody()) {
return CallExpr::Create(Context, Fn, Args, Context.DependentTy,
VK_PRValue, RParenLoc, CurFPFeatureOverrides());
}
}
}
return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args, RParenLoc,
ExecConfig, &CandidateSet, &Best,
OverloadResult, AllowTypoCorrection);
}
ExprResult Sema::CreateUnresolvedLookupExpr(CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc NNSLoc,
DeclarationNameInfo DNI,
const UnresolvedSetImpl &Fns,
bool PerformADL) {
return UnresolvedLookupExpr::Create(
Context, NamingClass, NNSLoc, DNI, PerformADL, Fns.begin(), Fns.end(),
false, false);
}
ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
CXXConversionDecl *Method,
bool HadMultipleCandidates) {
ExprResult Exp;
if (Method->isExplicitObjectMemberFunction())
Exp = InitializeExplicitObjectArgument(*this, E, Method);
else
Exp = PerformImplicitObjectArgumentInitialization(E, nullptr,
FoundDecl, Method);
if (Exp.isInvalid())
return true;
if (Method->getParent()->isLambda() &&
Method->getConversionType()->isBlockPointerType()) {
Expr *SubE = E;
auto *CE = dyn_cast<CastExpr>(SubE);
if (CE && CE->getCastKind() == CK_NoOp)
SubE = CE->getSubExpr();
SubE = SubE->IgnoreParens();
if (auto *BE = dyn_cast<CXXBindTemporaryExpr>(SubE))
SubE = BE->getSubExpr();
if (isa<LambdaExpr>(SubE)) {
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated);
ExprResult BlockExp = BuildBlockForLambdaConversion(
Exp.get()->getExprLoc(), Exp.get()->getExprLoc(), Method, Exp.get());
PopExpressionEvaluationContext();
if (BlockExp.isInvalid())
Diag(Exp.get()->getExprLoc(), diag::note_lambda_to_block_conv);
return BlockExp;
}
}
CallExpr *CE;
QualType ResultType = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);
if (Method->isExplicitObjectMemberFunction()) {
ExprResult FnExpr =
CreateFunctionRefExpr(*this, Method, FoundDecl, Exp.get(),
HadMultipleCandidates, E->getBeginLoc());
if (FnExpr.isInvalid())
return ExprError();
Expr *ObjectParam = Exp.get();
CE = CallExpr::Create(Context, FnExpr.get(), MultiExprArg(&ObjectParam, 1),
ResultType, VK, Exp.get()->getEndLoc(),
CurFPFeatureOverrides());
} else {
MemberExpr *ME =
BuildMemberExpr(Exp.get(), false, SourceLocation(),
NestedNameSpecifierLoc(), SourceLocation(), Method,
DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()),
HadMultipleCandidates, DeclarationNameInfo(),
Context.BoundMemberTy, VK_PRValue, OK_Ordinary);
CE = CXXMemberCallExpr::Create(Context, ME, {}, ResultType, VK,
Exp.get()->getEndLoc(),
CurFPFeatureOverrides());
}
if (CheckFunctionCall(Method, CE,
Method->getType()->castAs<FunctionProtoType>()))
return ExprError();
return CheckForImmediateInvocation(CE, CE->getDirectCallee());
}
ExprResult
Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
Expr *Input, bool PerformADL) {
OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc);
assert(Op != OO_None && "Invalid opcode for overloaded unary operator");
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
if (checkPlaceholderForOverload(*this, Input))
return ExprError();
Expr *Args[2] = { Input, nullptr };
unsigned NumArgs = 1;
if (Opc == UO_PostInc || Opc == UO_PostDec) {
llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false);
Args[1] = IntegerLiteral::Create(Context, Zero, Context.IntTy,
SourceLocation());
NumArgs = 2;
}
ArrayRef<Expr *> ArgsArray(Args, NumArgs);
if (Input->isTypeDependent()) {
ExprValueKind VK = ExprValueKind::VK_PRValue;
if (Opc == UO_PreDec || Opc == UO_PreInc || Opc == UO_Deref)
VK = VK_LValue;
if (Fns.empty())
return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy, VK,
OK_Ordinary, OpLoc, false,
CurFPFeatureOverrides());
CXXRecordDecl *NamingClass = nullptr;
ExprResult Fn = CreateUnresolvedLookupExpr(
NamingClass, NestedNameSpecifierLoc(), OpNameInfo, Fns);
if (Fn.isInvalid())
return ExprError();
return CXXOperatorCallExpr::Create(Context, Op, Fn.get(), ArgsArray,
Context.DependentTy, VK_PRValue, OpLoc,
CurFPFeatureOverrides());
}
OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
AddNonMemberOperatorCandidates(Fns, ArgsArray, CandidateSet);
AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
if (PerformADL) {
AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
nullptr,
CandidateSet);
}
AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) {
case OR_Success: {
FunctionDecl *FnDecl = Best->Function;
if (FnDecl) {
Expr *Base = nullptr;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
CheckMemberOperatorAccess(OpLoc, Input, nullptr, Best->FoundDecl);
ExprResult InputInit;
if (Method->isExplicitObjectMemberFunction())
InputInit = InitializeExplicitObjectArgument(*this, Input, Method);
else
InputInit = PerformImplicitObjectArgumentInitialization(
Input, nullptr, Best->FoundDecl, Method);
if (InputInit.isInvalid())
return ExprError();
Base = Input = InputInit.get();
} else {
ExprResult InputInit
= PerformCopyInitialization(InitializedEntity::InitializeParameter(
Context,
FnDecl->getParamDecl(0)),
SourceLocation(),
Input);
if (InputInit.isInvalid())
return ExprError();
Input = InputInit.get();
}
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl,
Base, HadMultipleCandidates,
OpLoc);
if (FnExpr.isInvalid())
return ExprError();
QualType ResultTy = FnDecl->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
Args[0] = Input;
CallExpr *TheCall = CXXOperatorCallExpr::Create(
Context, Op, FnExpr.get(), ArgsArray, ResultTy, VK, OpLoc,
CurFPFeatureOverrides(), Best->IsADLCandidate);
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
return ExprError();
if (CheckFunctionCall(FnDecl, TheCall,
FnDecl->getType()->castAs<FunctionProtoType>()))
return ExprError();
return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), FnDecl);
} else {
ExprResult InputRes = PerformImplicitConversion(
Input, Best->BuiltinParamTypes[0], Best->Conversions[0], AA_Passing,
CheckedConversionKind::ForBuiltinOverloadedOp);
if (InputRes.isInvalid())
return ExprError();
Input = InputRes.get();
break;
}
}
case OR_No_Viable_Function:
if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, ArgsArray))
return ExprError();
break;
case OR_Ambiguous:
CandidateSet.NoteCandidates(
PartialDiagnosticAt(OpLoc,
PDiag(diag::err_ovl_ambiguous_oper_unary)
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getType() << Input->getSourceRange()),
*this, OCD_AmbiguousCandidates, ArgsArray,
UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
case OR_Deleted: {
StringLiteral *Msg = Best->Function->getDeletedMessage();
CandidateSet.NoteCandidates(
PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper)
<< UnaryOperator::getOpcodeStr(Opc)
<< (Msg != nullptr)
<< (Msg ? Msg->getString() : StringRef())
<< Input->getSourceRange()),
*this, OCD_AllCandidates, ArgsArray.drop_front(),
UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
}
}
return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
}
void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet,
OverloadedOperatorKind Op,
const UnresolvedSetImpl &Fns,
ArrayRef<Expr *> Args, bool PerformADL) {
SourceLocation OpLoc = CandidateSet.getLocation();
OverloadedOperatorKind ExtraOp =
CandidateSet.getRewriteInfo().AllowRewrittenCandidates
? getRewrittenOverloadedOperator(Op)
: OO_None;
AddNonMemberOperatorCandidates(Fns, Args, CandidateSet);
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
if (CandidateSet.getRewriteInfo().allowsReversed(Op))
AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet,
OverloadCandidateParamOrder::Reversed);
if (ExtraOp) {
AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet);
if (CandidateSet.getRewriteInfo().allowsReversed(ExtraOp))
AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},
CandidateSet,
OverloadCandidateParamOrder::Reversed);
}
if (Op != OO_Equal && PerformADL) {
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
nullptr,
CandidateSet);
if (ExtraOp) {
DeclarationName ExtraOpName =
Context.DeclarationNames.getCXXOperatorName(ExtraOp);
AddArgumentDependentLookupCandidates(ExtraOpName, OpLoc, Args,
nullptr,
CandidateSet);
}
}
AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);
}
ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns, Expr *LHS,
Expr *RHS, bool PerformADL,
bool AllowRewrittenCandidates,
FunctionDecl *DefaultedFn) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=nullptr;
if (!getLangOpts().CPlusPlus20)
AllowRewrittenCandidates = false;
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
if (Fns.empty()) {
if (BinaryOperator::isCompoundAssignmentOp(Opc))
return CompoundAssignOperator::Create(
Context, Args[0], Args[1], Opc, Context.DependentTy, VK_LValue,
OK_Ordinary, OpLoc, CurFPFeatureOverrides(), Context.DependentTy,
Context.DependentTy);
return BinaryOperator::Create(
Context, Args[0], Args[1], Opc, Context.DependentTy, VK_PRValue,
OK_Ordinary, OpLoc, CurFPFeatureOverrides());
}
CXXRecordDecl *NamingClass = nullptr;
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
ExprResult Fn = CreateUnresolvedLookupExpr(
NamingClass, NestedNameSpecifierLoc(), OpNameInfo, Fns, PerformADL);
if (Fn.isInvalid())
return ExprError();
return CXXOperatorCallExpr::Create(Context, Op, Fn.get(), Args,
Context.DependentTy, VK_PRValue, OpLoc,
CurFPFeatureOverrides());
}
if (Opc == BO_PtrMemD) {
auto CheckPlaceholder = [&](Expr *&Arg) {
ExprResult Res = CheckPlaceholderExpr(Arg);
if (Res.isUsable())
Arg = Res.get();
return !Res.isUsable();
};
if (CheckPlaceholder(Args[0]) || CheckPlaceholder(Args[1]))
return ExprError();
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
if (checkPlaceholderForOverload(*this, Args[1]))
return ExprError();
assert(Args[0]->getObjectKind() != OK_ObjCProperty);
if (checkPlaceholderForOverload(*this, Args[0]))
return ExprError();
if (Opc == BO_Assign && !Args[0]->getType()->isOverloadableType())
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator,
OverloadCandidateSet::OperatorRewriteInfo(
Op, OpLoc, AllowRewrittenCandidates));
if (DefaultedFn)
CandidateSet.exclude(DefaultedFn);
LookupOverloadedBinOp(CandidateSet, Op, Fns, Args, PerformADL);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) {
case OR_Success: {
FunctionDecl *FnDecl = Best->Function;
bool IsReversed = Best->isReversed();
if (IsReversed)
std::swap(Args[0], Args[1]);
if (FnDecl) {
if (FnDecl->isInvalidDecl())
return ExprError();
Expr *Base = nullptr;
OverloadedOperatorKind ChosenOp =
FnDecl->getDeclName().getCXXOverloadedOperator();
if (Best->RewriteKind && ChosenOp == OO_EqualEqual &&
!FnDecl->getReturnType()->isBooleanType()) {
bool IsExtension =
FnDecl->getReturnType()->isIntegralOrUnscopedEnumerationType();
Diag(OpLoc, IsExtension ? diag::ext_ovl_rewrite_equalequal_not_bool
: diag::err_ovl_rewrite_equalequal_not_bool)
<< FnDecl->getReturnType() << BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
Diag(FnDecl->getLocation(), diag::note_declared_at);
if (!IsExtension)
return ExprError();
}
if (AllowRewrittenCandidates && !IsReversed &&
CandidateSet.getRewriteInfo().isReversible()) {
llvm::SmallVector<FunctionDecl*, 4> AmbiguousWith;
for (OverloadCandidate &Cand : CandidateSet) {
if (Cand.Viable && Cand.Function && Cand.isReversed() &&
allowAmbiguity(Context, Cand.Function, FnDecl)) {
for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {
if (CompareImplicitConversionSequences(
*this, OpLoc, Cand.Conversions[ArgIdx],
Best->Conversions[ArgIdx]) ==
ImplicitConversionSequence::Better) {
AmbiguousWith.push_back(Cand.Function);
break;
}
}
}
}
if (!AmbiguousWith.empty()) {
bool AmbiguousWithSelf =
AmbiguousWith.size() == 1 &&
declaresSameEntity(AmbiguousWith.front(), FnDecl);
Diag(OpLoc, diag::ext_ovl_ambiguous_oper_binary_reversed)
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getType() << Args[1]->getType() << AmbiguousWithSelf
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
if (AmbiguousWithSelf) {
Diag(FnDecl->getLocation(),
diag::note_ovl_ambiguous_oper_binary_reversed_self);
if (auto *MD = dyn_cast<CXXMethodDecl>(FnDecl))
if (Op == OverloadedOperatorKind::OO_EqualEqual &&
!MD->isConst() &&
!MD->hasCXXExplicitFunctionObjectParameter() &&
Context.hasSameUnqualifiedType(
MD->getFunctionObjectParameterType(),
MD->getParamDecl(0)->getType().getNonReferenceType()) &&
Context.hasSameUnqualifiedType(
MD->getFunctionObjectParameterType(),
Args[0]->getType()) &&
Context.hasSameUnqualifiedType(
MD->getFunctionObjectParameterType(),
Args[1]->getType()))
Diag(FnDecl->getLocation(),
diag::note_ovl_ambiguous_eqeq_reversed_self_non_const);
} else {
Diag(FnDecl->getLocation(),
diag::note_ovl_ambiguous_oper_binary_selected_candidate);
for (auto *F : AmbiguousWith)
Diag(F->getLocation(),
diag::note_ovl_ambiguous_oper_binary_reversed_candidate);
}
}
}
if (Op == OO_Equal)
diagnoseNullableToNonnullConversion(Args[0]->getType(),
Args[1]->getType(), OpLoc);
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Best->FoundDecl);
ExprResult Arg0, Arg1;
unsigned ParamIdx = 0;
if (Method->isExplicitObjectMemberFunction()) {
Arg0 = InitializeExplicitObjectArgument(*this, Args[0], FnDecl);
ParamIdx = 1;
} else {
Arg0 = PerformImplicitObjectArgumentInitialization(
Args[0], nullptr, Best->FoundDecl, Method);
}
Arg1 = PerformCopyInitialization(
InitializedEntity::InitializeParameter(
Context, FnDecl->getParamDecl(ParamIdx)),
SourceLocation(), Args[1]);
if (Arg0.isInvalid() || Arg1.isInvalid())
return ExprError();
Base = Args[0] = Arg0.getAs<Expr>();
Args[1] = RHS = Arg1.getAs<Expr>();
} else {
ExprResult Arg0 = PerformCopyInitialization(
InitializedEntity::InitializeParameter(Context,
FnDecl->getParamDecl(0)),
SourceLocation(), Args[0]);
if (Arg0.isInvalid())
return ExprError();
ExprResult Arg1 =
PerformCopyInitialization(
InitializedEntity::InitializeParameter(Context,
FnDecl->getParamDecl(1)),
SourceLocation(), Args[1]);
if (Arg1.isInvalid())
return ExprError();
Args[0] = LHS = Arg0.getAs<Expr>();
Args[1] = RHS = Arg1.getAs<Expr>();
}
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
Best->FoundDecl, Base,
HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
QualType ResultTy = FnDecl->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
CallExpr *TheCall;
ArrayRef<const Expr *> ArgsArray(Args, 2);
const Expr *ImplicitThis = nullptr;
TheCall = CXXOperatorCallExpr::Create(
Context, ChosenOp, FnExpr.get(), Args, ResultTy, VK, OpLoc,
CurFPFeatureOverrides(), Best->IsADLCandidate);
if (const auto *Method = dyn_cast<CXXMethodDecl>(FnDecl);
Method && Method->isImplicitObjectMemberFunction()) {
ImplicitThis = ArgsArray[0];
ArgsArray = ArgsArray.slice(1);
}
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall,
FnDecl))
return ExprError();
if (Op == OO_Equal) {
DiagnoseSelfMove(Args[0], Args[1], OpLoc);
checkExprLifetime(*this, AssignedEntity{Args[0]}, Args[1]);
}
if (ImplicitThis) {
QualType ThisType = Context.getPointerType(ImplicitThis->getType());
QualType ThisTypeFromDecl = Context.getPointerType(
cast<CXXMethodDecl>(FnDecl)->getFunctionObjectParameterType());
CheckArgAlignment(OpLoc, FnDecl, "'this'", ThisType,
ThisTypeFromDecl);
}
checkCall(FnDecl, nullptr, ImplicitThis, ArgsArray,
isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),
VariadicDoesNotApply);
ExprResult R = MaybeBindToTemporary(TheCall);
if (R.isInvalid())
return ExprError();
R = CheckForImmediateInvocation(R, FnDecl);
if (R.isInvalid())
return ExprError();
if ((Best->RewriteKind & CRK_DifferentOperator) ||
(Op == OO_Spaceship && IsReversed)) {
if (Op == OO_ExclaimEqual) {
assert(ChosenOp == OO_EqualEqual && "unexpected operator name");
R = CreateBuiltinUnaryOp(OpLoc, UO_LNot, R.get());
} else {
assert(ChosenOp == OO_Spaceship && "unexpected operator name");
llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false);
Expr *ZeroLiteral =
IntegerLiteral::Create(Context, Zero, Context.IntTy, OpLoc);
Sema::CodeSynthesisContext Ctx;
Ctx.Kind = Sema::CodeSynthesisContext::RewritingOperatorAsSpaceship;
Ctx.Entity = FnDecl;
pushCodeSynthesisContext(Ctx);
R = CreateOverloadedBinOp(
OpLoc, Opc, Fns, IsReversed ? ZeroLiteral : R.get(),
IsReversed ? R.get() : ZeroLiteral, true,
false);
popCodeSynthesisContext();
}
if (R.isInvalid())
return ExprError();
} else {
assert(ChosenOp == Op && "unexpected operator name");
}
if (Best->RewriteKind != CRK_None)
R = new (Context) CXXRewrittenBinaryOperator(R.get(), IsReversed);
return R;
} else {
ExprResult ArgsRes0 = PerformImplicitConversion(
Args[0], Best->BuiltinParamTypes[0], Best->Conversions[0],
AA_Passing, CheckedConversionKind::ForBuiltinOverloadedOp);
if (ArgsRes0.isInvalid())
return ExprError();
Args[0] = ArgsRes0.get();
ExprResult ArgsRes1 = PerformImplicitConversion(
Args[1], Best->BuiltinParamTypes[1], Best->Conversions[1],
AA_Passing, CheckedConversionKind::ForBuiltinOverloadedOp);
if (ArgsRes1.isInvalid())
return ExprError();
Args[1] = ArgsRes1.get();
break;
}
}
case OR_No_Viable_Function: {
if (Opc == BO_Comma)
break;
if (DefaultedFn && Opc == BO_Cmp) {
ExprResult E = BuildSynthesizedThreeWayComparison(OpLoc, Fns, Args[0],
Args[1], DefaultedFn);
if (E.isInvalid() || E.isUsable())
return E;
}
ExprResult Result = ExprError();
StringRef OpcStr = BinaryOperator::getOpcodeStr(Opc);
auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates,
Args, OpLoc);
DeferDiagsRAII DDR(*this,
CandidateSet.shouldDeferDiags(*this, Args, OpLoc));
if (Args[0]->getType()->isRecordType() &&
Opc >= BO_Assign && Opc <= BO_OrAssign) {
Diag(OpLoc, diag::err_ovl_no_viable_oper)
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
if (Args[0]->getType()->isIncompleteType()) {
Diag(OpLoc, diag::note_assign_lhs_incomplete)
<< Args[0]->getType()
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
}
} else {
if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args))
return ExprError();
Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
assert(Result.isInvalid() &&
"C++ binary operator overloading is missing candidates!");
CandidateSet.NoteCandidates(*this, Args, Cands, OpcStr, OpLoc);
return Result;
}
case OR_Ambiguous:
CandidateSet.NoteCandidates(
PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_binary)
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getType()
<< Args[1]->getType()
<< Args[0]->getSourceRange()
<< Args[1]->getSourceRange()),
*this, OCD_AmbiguousCandidates, Args, BinaryOperator::getOpcodeStr(Opc),
OpLoc);
return ExprError();
case OR_Deleted: {
if (isImplicitlyDeleted(Best->Function)) {
FunctionDecl *DeletedFD = Best->Function;
DefaultedFunctionKind DFK = getDefaultedFunctionKind(DeletedFD);
if (DFK.isSpecialMember()) {
Diag(OpLoc, diag::err_ovl_deleted_special_oper)
<< Args[0]->getType()
<< llvm::to_underlying(DFK.asSpecialMember());
} else {
assert(DFK.isComparison());
Diag(OpLoc, diag::err_ovl_deleted_comparison)
<< Args[0]->getType() << DeletedFD;
}
NoteDeletedFunction(DeletedFD);
return ExprError();
}
StringLiteral *Msg = Best->Function->getDeletedMessage();
CandidateSet.NoteCandidates(
PartialDiagnosticAt(
OpLoc,
PDiag(diag::err_ovl_deleted_oper)
<< getOperatorSpelling(Best->Function->getDeclName()
.getCXXOverloadedOperator())
<< (Msg != nullptr) << (Msg ? Msg->getString() : StringRef())
<< Args[0]->getSourceRange() << Args[1]->getSourceRange()),
*this, OCD_AllCandidates, Args, BinaryOperator::getOpcodeStr(Opc),
OpLoc);
return ExprError();
}
}
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
ExprResult Sema::BuildSynthesizedThreeWayComparison(
SourceLocation OpLoc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS,
FunctionDecl *DefaultedFn) {
const ComparisonCategoryInfo *Info =
Context.CompCategories.lookupInfoForType(DefaultedFn->getReturnType());
if (!Info)
return ExprResult((Expr*)nullptr);
assert(LHS->isGLValue() && RHS->isGLValue() &&
"cannot use prvalue expressions more than once");
Expr *OrigLHS = LHS;
Expr *OrigRHS = RHS;
LHS = new (Context)
OpaqueValueExpr(LHS->getExprLoc(), LHS->getType(), LHS->getValueKind(),
LHS->getObjectKind(), LHS);
RHS = new (Context)
OpaqueValueExpr(RHS->getExprLoc(), RHS->getType(), RHS->getValueKind(),
RHS->getObjectKind(), RHS);
ExprResult Eq = CreateOverloadedBinOp(OpLoc, BO_EQ, Fns, LHS, RHS, true, true,
DefaultedFn);
if (Eq.isInvalid())
return ExprError();
ExprResult Less = CreateOverloadedBinOp(OpLoc, BO_LT, Fns, LHS, RHS, true,
true, DefaultedFn);
if (Less.isInvalid())
return ExprError();
ExprResult Greater;
if (Info->isPartial()) {
Greater = CreateOverloadedBinOp(OpLoc, BO_LT, Fns, RHS, LHS, true, true,
DefaultedFn);
if (Greater.isInvalid())
return ExprError();
}
struct Comparison {
ExprResult Cmp;
ComparisonCategoryResult Result;
} Comparisons[4] =
{ {Eq, Info->isStrong() ? ComparisonCategoryResult::Equal
: ComparisonCategoryResult::Equivalent},
{Less, ComparisonCategoryResult::Less},
{Greater, ComparisonCategoryResult::Greater},
{ExprResult(), ComparisonCategoryResult::Unordered},
};
int I = Info->isPartial() ? 3 : 2;
ExprResult Result;
for (; I >= 0; --I) {
auto *VI = Info->lookupValueInfo(Comparisons[I].Result);
if (!VI)
return ExprResult((Expr*)nullptr);
ExprResult ThisResult =
BuildDeclarationNameExpr(CXXScopeSpec(), DeclarationNameInfo(), VI->VD);
if (ThisResult.isInvalid())
return ExprError();
if (Result.get()) {
Result = ActOnConditionalOp(OpLoc, OpLoc, Comparisons[I].Cmp.get(),
ThisResult.get(), Result.get());
if (Result.isInvalid())
return ExprError();
} else {
Result = ThisResult;
}
}
Expr *SyntacticForm = BinaryOperator::Create(
Context, OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(),
Result.get()->getValueKind(), Result.get()->getObjectKind(), OpLoc,
CurFPFeatureOverrides());
Expr *SemanticForm[] = {LHS, RHS, Result.get()};
return PseudoObjectExpr::Create(Context, SyntacticForm, SemanticForm, 2);
}
static bool PrepareArgumentsForCallToObjectOfClassType(
Sema &S, SmallVectorImpl<Expr *> &MethodArgs, CXXMethodDecl *Method,
MultiExprArg Args, SourceLocation LParenLoc) {
const auto *Proto = Method->getType()->castAs<FunctionProtoType>();
unsigned NumParams = Proto->getNumParams();
unsigned NumArgsSlots =
MethodArgs.size() + std::max<unsigned>(Args.size(), NumParams);
MethodArgs.reserve(MethodArgs.size() + NumArgsSlots);
bool IsError = false;
for (unsigned i = 0; i != NumParams; i++) {
Expr *Arg;
if (i < Args.size()) {
Arg = Args[i];
ExprResult InputInit =
S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
S.Context, Method->getParamDecl(i)),
SourceLocation(), Arg);
IsError |= InputInit.isInvalid();
Arg = InputInit.getAs<Expr>();
} else {
ExprResult DefArg =
S.BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i));
if (DefArg.isInvalid()) {
IsError = true;
break;
}
Arg = DefArg.getAs<Expr>();
}
MethodArgs.push_back(Arg);
}
return IsError;
}
ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
SourceLocation RLoc,
Expr *Base,
MultiExprArg ArgExpr) {
SmallVector<Expr *, 2> Args;
Args.push_back(Base);
for (auto *e : ArgExpr) {
Args.push_back(e);
}
DeclarationName OpName =
Context.DeclarationNames.getCXXOperatorName(OO_Subscript);
SourceRange Range = ArgExpr.empty()
? SourceRange{}
: SourceRange(ArgExpr.front()->getBeginLoc(),
ArgExpr.back()->getEndLoc());
if (Expr::hasAnyTypeDependentArguments(Args)) {
CXXRecordDecl *NamingClass = nullptr;
DeclarationNameInfo OpNameInfo(OpName, LLoc);
OpNameInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
ExprResult Fn = CreateUnresolvedLookupExpr(
NamingClass, NestedNameSpecifierLoc(), OpNameInfo, UnresolvedSet<0>());
if (Fn.isInvalid())
return ExprError();
return CXXOperatorCallExpr::Create(Context, OO_Subscript, Fn.get(), Args,
Context.DependentTy, VK_PRValue, RLoc,
CurFPFeatureOverrides());
}
UnbridgedCastsSet UnbridgedCasts;
if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts)) {
return ExprError();
}
OverloadCandidateSet CandidateSet(LLoc, OverloadCandidateSet::CSK_Operator);
AddMemberOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet);
if (Args.size() == 2)
AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, LLoc, Best)) {
case OR_Success: {
FunctionDecl *FnDecl = Best->Function;
if (FnDecl) {
CheckMemberOperatorAccess(LLoc, Args[0], ArgExpr, Best->FoundDecl);
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
SmallVector<Expr *, 2> MethodArgs;
if (Method->isExplicitObjectMemberFunction()) {
ExprResult Res =
InitializeExplicitObjectArgument(*this, Args[0], Method);
if (Res.isInvalid())
return ExprError();
Args[0] = Res.get();
ArgExpr = Args;
} else {
ExprResult Arg0 = PerformImplicitObjectArgumentInitialization(
Args[0], nullptr, Best->FoundDecl, Method);
if (Arg0.isInvalid())
return ExprError();
MethodArgs.push_back(Arg0.get());
}
bool IsError = PrepareArgumentsForCallToObjectOfClassType(
*this, MethodArgs, Method, ArgExpr, LLoc);
if (IsError)
return ExprError();
DeclarationNameInfo OpLocInfo(OpName, LLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
ExprResult FnExpr = CreateFunctionRefExpr(
*this, FnDecl, Best->FoundDecl, Base, HadMultipleCandidates,
OpLocInfo.getLoc(), OpLocInfo.getInfo());
if (FnExpr.isInvalid())
return ExprError();
QualType ResultTy = FnDecl->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
CallExpr *TheCall = CXXOperatorCallExpr::Create(
Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, RLoc,
CurFPFeatureOverrides());
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
return ExprError();
if (CheckFunctionCall(Method, TheCall,
Method->getType()->castAs<FunctionProtoType>()))
return ExprError();
return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall),
FnDecl);
} else {
ExprResult ArgsRes0 = PerformImplicitConversion(
Args[0], Best->BuiltinParamTypes[0], Best->Conversions[0],
AA_Passing, CheckedConversionKind::ForBuiltinOverloadedOp);
if (ArgsRes0.isInvalid())
return ExprError();
Args[0] = ArgsRes0.get();
ExprResult ArgsRes1 = PerformImplicitConversion(
Args[1], Best->BuiltinParamTypes[1], Best->Conversions[1],
AA_Passing, CheckedConversionKind::ForBuiltinOverloadedOp);
if (ArgsRes1.isInvalid())
return ExprError();
Args[1] = ArgsRes1.get();
break;
}
}
case OR_No_Viable_Function: {
PartialDiagnostic PD =
CandidateSet.empty()
? (PDiag(diag::err_ovl_no_oper)
<< Args[0]->getType() << 0
<< Args[0]->getSourceRange() << Range)
: (PDiag(diag::err_ovl_no_viable_subscript)
<< Args[0]->getType() << Args[0]->getSourceRange() << Range);
CandidateSet.NoteCandidates(PartialDiagnosticAt(LLoc, PD), *this,
OCD_AllCandidates, ArgExpr, "[]", LLoc);
return ExprError();
}
case OR_Ambiguous:
if (Args.size() == 2) {
CandidateSet.NoteCandidates(
PartialDiagnosticAt(
LLoc, PDiag(diag::err_ovl_ambiguous_oper_binary)
<< "[]" << Args[0]->getType() << Args[1]->getType()
<< Args[0]->getSourceRange() << Range),
*this, OCD_AmbiguousCandidates, Args, "[]", LLoc);
} else {
CandidateSet.NoteCandidates(
PartialDiagnosticAt(LLoc,
PDiag(diag::err_ovl_ambiguous_subscript_call)
<< Args[0]->getType()
<< Args[0]->getSourceRange() << Range),
*this, OCD_AmbiguousCandidates, Args, "[]", LLoc);
}
return ExprError();
case OR_Deleted: {
StringLiteral *Msg = Best->Function->getDeletedMessage();
CandidateSet.NoteCandidates(
PartialDiagnosticAt(LLoc,
PDiag(diag::err_ovl_deleted_oper)
<< "[]" << (Msg != nullptr)
<< (Msg ? Msg->getString() : StringRef())
<< Args[0]->getSourceRange() << Range),
*this, OCD_AllCandidates, Args, "[]", LLoc);
return ExprError();
}
}
return CreateBuiltinArraySubscriptExpr(Args[0], LLoc, Args[1], RLoc);
}
ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
SourceLocation LParenLoc,
MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig, bool IsExecConfig,
bool AllowRecovery) {
assert(MemExprE->getType() == Context.BoundMemberTy ||
MemExprE->getType() == Context.OverloadTy);
Expr *NakedMemExpr = MemExprE->IgnoreParens();
if (BinaryOperator *op = dyn_cast<BinaryOperator>(NakedMemExpr)) {
assert(op->getType() == Context.BoundMemberTy);
assert(op->getOpcode() == BO_PtrMemD || op->getOpcode() == BO_PtrMemI);
QualType fnType =
op->getRHS()->getType()->castAs<MemberPointerType>()->getPointeeType();
const FunctionProtoType *proto = fnType->castAs<FunctionProtoType>();
QualType resultType = proto->getCallResultType(Context);
ExprValueKind valueKind = Expr::getValueKindForType(proto->getReturnType());
Qualifiers funcQuals = proto->getMethodQuals();
QualType objectType = op->getLHS()->getType();
if (op->getOpcode() == BO_PtrMemI)
objectType = objectType->castAs<PointerType>()->getPointeeType();
Qualifiers objectQuals = objectType.getQualifiers();
Qualifiers difference = objectQuals - funcQuals;
difference.removeObjCGCAttr();
difference.removeAddressSpace();
if (difference) {
std::string qualsString = difference.getAsString();
Diag(LParenLoc, diag::err_pointer_to_member_call_drops_quals)
<< fnType.getUnqualifiedType()
<< qualsString
<< (qualsString.find(' ') == std::string::npos ? 1 : 2);
}
CXXMemberCallExpr *call = CXXMemberCallExpr::Create(
Context, MemExprE, Args, resultType, valueKind, RParenLoc,
CurFPFeatureOverrides(), proto->getNumParams());
if (CheckCallReturnType(proto->getReturnType(), op->getRHS()->getBeginLoc(),
call, nullptr))
return ExprError();
if (ConvertArgumentsForCall(call, op, nullptr, proto, Args, RParenLoc))
return ExprError();
if (CheckOtherCall(call, proto))
return ExprError();
return MaybeBindToTemporary(call);
}
auto BuildRecoveryExpr = [&](QualType Type) {
if (!AllowRecovery)
return ExprError();
std::vector<Expr *> SubExprs = {MemExprE};
llvm::append_range(SubExprs, Args);
return CreateRecoveryExpr(MemExprE->getBeginLoc(), RParenLoc, SubExprs,
Type);
};
if (isa<CXXPseudoDestructorExpr>(NakedMemExpr))
return CallExpr::Create(Context, MemExprE, Args, Context.VoidTy, VK_PRValue,
RParenLoc, CurFPFeatureOverrides());
UnbridgedCastsSet UnbridgedCasts;
if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts))
return ExprError();
MemberExpr *MemExpr;
CXXMethodDecl *Method = nullptr;
bool HadMultipleCandidates = false;
DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_public);
NestedNameSpecifier *Qualifier = nullptr;
if (isa<MemberExpr>(NakedMemExpr)) {
MemExpr = cast<MemberExpr>(NakedMemExpr);
Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl());
FoundDecl = MemExpr->getFoundDecl();
Qualifier = MemExpr->getQualifier();
UnbridgedCasts.restore();
} else {
UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr);
Qualifier = UnresExpr->getQualifier();
QualType ObjectType = UnresExpr->getBaseType();
Expr::Classification ObjectClassification
= UnresExpr->isArrow()? Expr::Classification::makeSimpleLValue()
: UnresExpr->getBase()->Classify(Context);
OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc(),
OverloadCandidateSet::CSK_Normal);
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;
if (UnresExpr->hasExplicitTemplateArgs()) {
UnresExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
TemplateArgs = &TemplateArgsBuffer;
}
for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(),
E = UnresExpr->decls_end(); I != E; ++I) {
QualType ExplicitObjectType = ObjectType;
NamedDecl *Func = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(Func->getDeclContext());
if (isa<UsingShadowDecl>(Func))
Func = cast<UsingShadowDecl>(Func)->getTargetDecl();
bool HasExplicitParameter = false;
if (const auto *M = dyn_cast<FunctionDecl>(Func);
M && M->hasCXXExplicitFunctionObjectParameter())
HasExplicitParameter = true;
else if (const auto *M = dyn_cast<FunctionTemplateDecl>(Func);
M &&
M->getTemplatedDecl()->hasCXXExplicitFunctionObjectParameter())
HasExplicitParameter = true;
if (HasExplicitParameter)
ExplicitObjectType = GetExplicitObjectType(*this, UnresExpr);
if (getLangOpts().MicrosoftExt && isa<CXXConstructorDecl>(Func)) {
AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args,
CandidateSet,
false);
} else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
if (TemplateArgs)
continue;
AddMethodCandidate(Method, I.getPair(), ActingDC, ExplicitObjectType,
ObjectClassification, Args, CandidateSet,
false);
} else {
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
I.getPair(), ActingDC, TemplateArgs,
ExplicitObjectType, ObjectClassification,
Args, CandidateSet,
false);
}
}
HadMultipleCandidates = (CandidateSet.size() > 1);
DeclarationName DeclName = UnresExpr->getMemberName();
UnbridgedCasts.restore();
OverloadCandidateSet::iterator Best;
bool Succeeded = false;
switch (CandidateSet.BestViableFunction(*this, UnresExpr->getBeginLoc(),
Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
if (DiagnoseUseOfOverloadedDecl(Best->FoundDecl, UnresExpr->getNameLoc()))
break;
if (Method != FoundDecl.getDecl() &&
DiagnoseUseOfOverloadedDecl(Method, UnresExpr->getNameLoc()))
break;
Succeeded = true;
break;
case OR_No_Viable_Function:
CandidateSet.NoteCandidates(
PartialDiagnosticAt(
UnresExpr->getMemberLoc(),
PDiag(diag::err_ovl_no_viable_member_function_in_call)
<< DeclName << MemExprE->getSourceRange()),
*this, OCD_AllCandidates, Args);
break;
case OR_Ambiguous:
CandidateSet.NoteCandidates(
PartialDiagnosticAt(UnresExpr->getMemberLoc(),
PDiag(diag::err_ovl_ambiguous_member_call)
<< DeclName << MemExprE->getSourceRange()),
*this, OCD_AmbiguousCandidates, Args);
break;
case OR_Deleted:
DiagnoseUseOfDeletedFunction(
UnresExpr->getMemberLoc(), MemExprE->getSourceRange(), DeclName,
CandidateSet, Best->Function, Args, true);
break;
}
if (!Succeeded)
return BuildRecoveryExpr(chooseRecoveryType(CandidateSet, &Best));
ExprResult Res =
FixOverloadedFunctionReference(MemExprE, FoundDecl, Method);
if (Res.isInvalid())
return ExprError();
MemExprE = Res.get();
if (Method->isStatic()) {
return BuildResolvedCallExpr(MemExprE, Method, LParenLoc, Args, RParenLoc,
ExecConfig, IsExecConfig);
}
MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens());
}
QualType ResultType = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);
assert(Method && "Member call to something that isn't a method?");
const auto *Proto = Method->getType()->castAs<FunctionProtoType>();
CallExpr *TheCall = nullptr;
llvm::SmallVector<Expr *, 8> NewArgs;
if (Method->isExplicitObjectMemberFunction()) {
if (PrepareExplicitObjectArgument(*this, Method, MemExpr->getBase(), Args,
NewArgs))
return ExprError();
ExprResult FnExpr =
CreateFunctionRefExpr(*this, Method, FoundDecl, MemExpr,
HadMultipleCandidates, MemExpr->getExprLoc());
if (FnExpr.isInvalid())
return ExprError();
TheCall =
CallExpr::Create(Context, FnExpr.get(), Args, ResultType, VK, RParenLoc,
CurFPFeatureOverrides(), Proto->getNumParams());
} else {
ExprResult ObjectArg = PerformImplicitObjectArgumentInitialization(
MemExpr->getBase(), Qualifier, FoundDecl, Method);
if (ObjectArg.isInvalid())
return ExprError();
MemExpr->setBase(ObjectArg.get());
TheCall = CXXMemberCallExpr::Create(Context, MemExprE, Args, ResultType, VK,
RParenLoc, CurFPFeatureOverrides(),
Proto->getNumParams());
}
if (CheckCallReturnType(Method->getReturnType(), MemExpr->getMemberLoc(),
TheCall, Method))
return BuildRecoveryExpr(ResultType);
if (ConvertArgumentsForCall(TheCall, MemExpr, Method, Proto, Args,
RParenLoc))
return BuildRecoveryExpr(ResultType);
DiagnoseSentinelCalls(Method, LParenLoc, Args);
if (CheckFunctionCall(Method, TheCall, Proto))
return ExprError();
if (auto *MemE = dyn_cast<MemberExpr>(NakedMemExpr)) {
if (const EnableIfAttr *Attr =
CheckEnableIf(Method, LParenLoc, Args, true)) {
Diag(MemE->getMemberLoc(),
diag::err_ovl_no_viable_member_function_in_call)
<< Method << Method->getSourceRange();
Diag(Method->getLocation(),
diag::note_ovl_candidate_disabled_by_function_cond_attr)
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
return ExprError();
}
}
if (isa<CXXConstructorDecl, CXXDestructorDecl>(CurContext) &&
TheCall->getDirectCallee()->isPureVirtual()) {
const FunctionDecl *MD = TheCall->getDirectCallee();
if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts()) &&
MemExpr->performsVirtualDispatch(getLangOpts())) {
Diag(MemExpr->getBeginLoc(),
diag::warn_call_to_pure_virtual_member_function_from_ctor_dtor)
<< MD->getDeclName() << isa<CXXDestructorDecl>(CurContext)
<< MD->getParent();
Diag(MD->getBeginLoc(), diag::note_previous_decl) << MD->getDeclName();
if (getLangOpts().AppleKext)
Diag(MemExpr->getBeginLoc(), diag::note_pure_qualified_call_kext)
<< MD->getParent() << MD->getDeclName();
}
}
if (auto *DD = dyn_cast<CXXDestructorDecl>(TheCall->getDirectCallee())) {
bool CallCanBeVirtual = !MemExpr->hasQualifier() || getLangOpts().AppleKext;
CheckVirtualDtorCall(DD, MemExpr->getBeginLoc(), false,
CallCanBeVirtual, true,
MemExpr->getMemberLoc());
}
return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall),
TheCall->getDirectCallee());
}
ExprResult
Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
SourceLocation LParenLoc,
MultiExprArg Args,
SourceLocation RParenLoc) {
if (checkPlaceholderForOverload(*this, Obj))
return ExprError();
ExprResult Object = Obj;
UnbridgedCastsSet UnbridgedCasts;
if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts))
return ExprError();
assert(Object.get()->getType()->isRecordType() &&
"Requires object type argument");
OverloadCandidateSet CandidateSet(LParenLoc,
OverloadCandidateSet::CSK_Operator);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
if (RequireCompleteType(LParenLoc, Object.get()->getType(),
diag::err_incomplete_object_call, Object.get()))
return true;
const auto *Record = Object.get()->getType()->castAs<RecordType>();
LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName);
LookupQualifiedName(R, Record->getDecl());
R.suppressAccessDiagnostics();
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Object.get()->getType(),
Object.get()->Classify(Context), Args, CandidateSet,
false);
}
bool IgnoreSurrogateFunctions = false;
if (CandidateSet.size() == 1 && Record->getAsCXXRecordDecl()->isLambda()) {
const OverloadCandidate &Candidate = *CandidateSet.begin();
if (!Candidate.Viable &&
Candidate.FailureKind == ovl_fail_constraints_not_satisfied)
IgnoreSurrogateFunctions = true;
}
const auto &Conversions =
cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end();
!IgnoreSurrogateFunctions && I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
if (isa<FunctionTemplateDecl>(D))
continue;
CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
if (!Conv->isExplicit()) {
QualType ConvType = Conv->getConversionType().getNonReferenceType();
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
ConvType = ConvPtrType->getPointeeType();
if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
{
AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto,
Object.get(), Args, CandidateSet);
}
}
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, Object.get()->getBeginLoc(),
Best)) {
case OR_Success:
break;
case OR_No_Viable_Function: {
PartialDiagnostic PD =
CandidateSet.empty()
? (PDiag(diag::err_ovl_no_oper)
<< Object.get()->getType() << 1
<< Object.get()->getSourceRange())
: (PDiag(diag::err_ovl_no_viable_object_call)
<< Object.get()->getType() << Object.get()->getSourceRange());
CandidateSet.NoteCandidates(
PartialDiagnosticAt(Object.get()->getBeginLoc(), PD), *this,
OCD_AllCandidates, Args);
break;
}
case OR_Ambiguous:
if (!R.isAmbiguous())
CandidateSet.NoteCandidates(
PartialDiagnosticAt(Object.get()->getBeginLoc(),
PDiag(diag::err_ovl_ambiguous_object_call)
<< Object.get()->getType()
<< Object.get()->getSourceRange()),
*this, OCD_AmbiguousCandidates, Args);
break;
case OR_Deleted: {
StringLiteral *Msg = Best->Function->getDeletedMessage();
CandidateSet.NoteCandidates(
PartialDiagnosticAt(Object.get()->getBeginLoc(),
PDiag(diag::err_ovl_deleted_object_call)
<< Object.get()->getType() << (Msg != nullptr)
<< (Msg ? Msg->getString() : StringRef())
<< Object.get()->getSourceRange()),
*this, OCD_AllCandidates, Args);
break;
}
}
if (Best == CandidateSet.end())
return true;
UnbridgedCasts.restore();
if (Best->Function == nullptr) {
CXXConversionDecl *Conv
= cast<CXXConversionDecl>(
Best->Conversions[0].UserDefined.ConversionFunction);
CheckMemberOperatorAccess(LParenLoc, Object.get(), nullptr,
Best->FoundDecl);
if (DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc))
return ExprError();
assert(Conv == Best->FoundDecl.getDecl() &&
"Found Decl & conversion-to-functionptr should be same, right?!");
ExprResult Call = BuildCXXMemberCallExpr(Object.get(), Best->FoundDecl,
Conv, HadMultipleCandidates);
if (Call.isInvalid())
return ExprError();
Call = ImplicitCastExpr::Create(
Context, Call.get()->getType(), CK_UserDefinedConversion, Call.get(),
nullptr, VK_PRValue, CurFPFeatureOverrides());
return BuildCallExpr(S, Call.get(), LParenLoc, Args, RParenLoc);
}
CheckMemberOperatorAccess(LParenLoc, Object.get(), nullptr, Best->FoundDecl);
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
if (Method->isInvalidDecl())
return ExprError();
const auto *Proto = Method->getType()->castAs<FunctionProtoType>();
unsigned NumParams = Proto->getNumParams();
DeclarationNameInfo OpLocInfo(
Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LParenLoc, RParenLoc));
ExprResult NewFn = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
Obj, HadMultipleCandidates,
OpLocInfo.getLoc(),
OpLocInfo.getInfo());
if (NewFn.isInvalid())
return true;
SmallVector<Expr *, 8> MethodArgs;
MethodArgs.reserve(NumParams + 1);
bool IsError = false;
llvm::SmallVector<Expr *, 8> NewArgs;
if (Method->isExplicitObjectMemberFunction()) {
IsError |= PrepareExplicitObjectArgument(*this, Method, Obj, Args, NewArgs);
} else {
ExprResult ObjRes = PerformImplicitObjectArgumentInitialization(
Object.get(), nullptr, Best->FoundDecl, Method);
if (ObjRes.isInvalid())
IsError = true;
else
Object = ObjRes;
MethodArgs.push_back(Object.get());
}
IsError |= PrepareArgumentsForCallToObjectOfClassType(
*this, MethodArgs, Method, Args, LParenLoc);
if (Proto->isVariadic()) {
for (unsigned i = NumParams, e = Args.size(); i < e; i++) {
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
nullptr);
IsError |= Arg.isInvalid();
MethodArgs.push_back(Arg.get());
}
}
if (IsError)
return true;
DiagnoseSentinelCalls(Method, LParenLoc, Args);
QualType ResultTy = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
CallExpr *TheCall = CXXOperatorCallExpr::Create(
Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc,
CurFPFeatureOverrides());
if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method))
return true;
if (CheckFunctionCall(Method, TheCall, Proto))
return true;
return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), Method);
}
ExprResult
Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
bool *NoArrowOperatorFound) {
assert(Base->getType()->isRecordType() &&
"left-hand side must have class type");
if (checkPlaceholderForOverload(*this, Base))
return ExprError();
SourceLocation Loc = Base->getExprLoc();
DeclarationName OpName =
Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Operator);
if (RequireCompleteType(Loc, Base->getType(),
diag::err_typecheck_incomplete_tag, Base))
return ExprError();
LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
LookupQualifiedName(R, Base->getType()->castAs<RecordType>()->getDecl());
R.suppressAccessDiagnostics();
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context),
std::nullopt, CandidateSet,
false);
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) {
case OR_Success:
break;
case OR_No_Viable_Function: {
auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates, Base);
if (CandidateSet.empty()) {
QualType BaseType = Base->getType();
if (NoArrowOperatorFound) {
*NoArrowOperatorFound = true;
return ExprError();
}
Diag(OpLoc, diag::err_typecheck_member_reference_arrow)
<< BaseType << Base->getSourceRange();
if (BaseType->isRecordType() && !BaseType->isPointerType()) {
Diag(OpLoc, diag::note_typecheck_member_reference_suggestion)
<< FixItHint::CreateReplacement(OpLoc, ".");
}
} else
Diag(OpLoc, diag::err_ovl_no_viable_oper)
<< "operator->" << Base->getSourceRange();
CandidateSet.NoteCandidates(*this, Base, Cands);
return ExprError();
}
case OR_Ambiguous:
if (!R.isAmbiguous())
CandidateSet.NoteCandidates(
PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_unary)
<< "->" << Base->getType()
<< Base->getSourceRange()),
*this, OCD_AmbiguousCandidates, Base);
return ExprError();
case OR_Deleted: {
StringLiteral *Msg = Best->Function->getDeletedMessage();
CandidateSet.NoteCandidates(
PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper)
<< "->" << (Msg != nullptr)
<< (Msg ? Msg->getString() : StringRef())
<< Base->getSourceRange()),
*this, OCD_AllCandidates, Base);
return ExprError();
}
}
CheckMemberOperatorAccess(OpLoc, Base, nullptr, Best->FoundDecl);
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
if (Method->isExplicitObjectMemberFunction()) {
ExprResult R = InitializeExplicitObjectArgument(*this, Base, Method);
if (R.isInvalid())
return ExprError();
Base = R.get();
} else {
ExprResult BaseResult = PerformImplicitObjectArgumentInitialization(
Base, nullptr, Best->FoundDecl, Method);
if (BaseResult.isInvalid())
return ExprError();
Base = BaseResult.get();
}
ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
Base, HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
QualType ResultTy = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
CallExpr *TheCall =
CXXOperatorCallExpr::Create(Context, OO_Arrow, FnExpr.get(), Base,
ResultTy, VK, OpLoc, CurFPFeatureOverrides());
if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method))
return ExprError();
if (CheckFunctionCall(Method, TheCall,
Method->getType()->castAs<FunctionProtoType>()))
return ExprError();
return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), Method);
}
ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
DeclarationNameInfo &SuffixInfo,
ArrayRef<Expr*> Args,
SourceLocation LitEndLoc,
TemplateArgumentListInfo *TemplateArgs) {
SourceLocation UDSuffixLoc = SuffixInfo.getCXXLiteralOperatorNameLoc();
OverloadCandidateSet CandidateSet(UDSuffixLoc,
OverloadCandidateSet::CSK_Normal);
AddNonMemberOperatorCandidates(R.asUnresolvedSet(), Args, CandidateSet,
TemplateArgs);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, UDSuffixLoc, Best)) {
case OR_Success:
case OR_Deleted:
break;
case OR_No_Viable_Function:
CandidateSet.NoteCandidates(
PartialDiagnosticAt(UDSuffixLoc,
PDiag(diag::err_ovl_no_viable_function_in_call)
<< R.getLookupName()),
*this, OCD_AllCandidates, Args);
return ExprError();
case OR_Ambiguous:
CandidateSet.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(), PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName()),
*this, OCD_AmbiguousCandidates, Args);
return ExprError();
}
FunctionDecl *FD = Best->Function;
ExprResult Fn = CreateFunctionRefExpr(*this, FD, Best->FoundDecl,
nullptr, HadMultipleCandidates,
SuffixInfo.getLoc(),
SuffixInfo.getInfo());
if (Fn.isInvalid())
return true;
Expr *ConvArgs[2];
for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) {
ExprResult InputInit = PerformCopyInitialization(
InitializedEntity::InitializeParameter(Context, FD->getParamDecl(ArgIdx)),
SourceLocation(), Args[ArgIdx]);
if (InputInit.isInvalid())
return true;
ConvArgs[ArgIdx] = InputInit.get();
}
QualType ResultTy = FD->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
UserDefinedLiteral *UDL = UserDefinedLiteral::Create(
Context, Fn.get(), llvm::ArrayRef(ConvArgs, Args.size()), ResultTy, VK,
LitEndLoc, UDSuffixLoc, CurFPFeatureOverrides());
if (CheckCallReturnType(FD->getReturnType(), UDSuffixLoc, UDL, FD))
return ExprError();
if (CheckFunctionCall(FD, UDL, nullptr))
return ExprError();
return CheckForImmediateInvocation(MaybeBindToTemporary(UDL), FD);
}
Sema::ForRangeStatus
Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
SourceLocation RangeLoc,
const DeclarationNameInfo &NameInfo,
LookupResult &MemberLookup,
OverloadCandidateSet *CandidateSet,
Expr *Range, ExprResult *CallExpr) {
Scope *S = nullptr;
CandidateSet->clear(OverloadCandidateSet::CSK_Normal);
if (!MemberLookup.empty()) {
ExprResult MemberRef =
BuildMemberReferenceExpr(Range, Range->getType(), Loc,
false, CXXScopeSpec(),
SourceLocation(),
nullptr,
MemberLookup,
nullptr, S);
if (MemberRef.isInvalid()) {
*CallExpr = ExprError();
return FRS_DiagnosticIssued;
}
*CallExpr =
BuildCallExpr(S, MemberRef.get(), Loc, std::nullopt, Loc, nullptr);
if (CallExpr->isInvalid()) {
*CallExpr = ExprError();
return FRS_DiagnosticIssued;
}
} else {
ExprResult FnR = CreateUnresolvedLookupExpr(nullptr,
NestedNameSpecifierLoc(),
NameInfo, UnresolvedSet<0>());
if (FnR.isInvalid())
return FRS_DiagnosticIssued;
UnresolvedLookupExpr *Fn = cast<UnresolvedLookupExpr>(FnR.get());
bool CandidateSetError = buildOverloadedCallSet(S, Fn, Fn, Range, Loc,
CandidateSet, CallExpr);
if (CandidateSet->empty() || CandidateSetError) {
*CallExpr = ExprError();
return FRS_NoViableFunction;
}
OverloadCandidateSet::iterator Best;
OverloadingResult OverloadResult =
CandidateSet->BestViableFunction(*this, Fn->getBeginLoc(), Best);
if (OverloadResult == OR_No_Viable_Function) {
*CallExpr = ExprError();
return FRS_NoViableFunction;
}
*CallExpr = FinishOverloadedCallExpr(*this, S, Fn, Fn, Loc, Range,
Loc, nullptr, CandidateSet, &Best,
OverloadResult,
false);
if (CallExpr->isInvalid() || OverloadResult != OR_Success) {
*CallExpr = ExprError();
return FRS_DiagnosticIssued;
}
}
return FRS_Success;
}
ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
FunctionDecl *Fn) {
if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
ExprResult SubExpr =
FixOverloadedFunctionReference(PE->getSubExpr(), Found, Fn);
if (SubExpr.isInvalid())
return ExprError();
if (SubExpr.get() == PE->getSubExpr())
return PE;
return new (Context)
ParenExpr(PE->getLParen(), PE->getRParen(), SubExpr.get());
}
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
ExprResult SubExpr =
FixOverloadedFunctionReference(ICE->getSubExpr(), Found, Fn);
if (SubExpr.isInvalid())
return ExprError();
assert(Context.hasSameType(ICE->getSubExpr()->getType(),
SubExpr.get()->getType()) &&
"Implicit cast type cannot be determined from overload");
assert(ICE->path_empty() && "fixing up hierarchy conversion?");
if (SubExpr.get() == ICE->getSubExpr())
return ICE;
return ImplicitCastExpr::Create(Context, ICE->getType(), ICE->getCastKind(),
SubExpr.get(), nullptr, ICE->getValueKind(),
CurFPFeatureOverrides());
}
if (auto *GSE = dyn_cast<GenericSelectionExpr>(E)) {
if (!GSE->isResultDependent()) {
ExprResult SubExpr =
FixOverloadedFunctionReference(GSE->getResultExpr(), Found, Fn);
if (SubExpr.isInvalid())
return ExprError();
if (SubExpr.get() == GSE->getResultExpr())
return GSE;
ArrayRef<Expr *> A = GSE->getAssocExprs();
SmallVector<Expr *, 4> AssocExprs(A.begin(), A.end());
unsigned ResultIdx = GSE->getResultIndex();
AssocExprs[ResultIdx] = SubExpr.get();
if (GSE->isExprPredicate())
return GenericSelectionExpr::Create(
Context, GSE->getGenericLoc(), GSE->getControllingExpr(),
GSE->getAssocTypeSourceInfos(), AssocExprs, GSE->getDefaultLoc(),
GSE->getRParenLoc(), GSE->containsUnexpandedParameterPack(),
ResultIdx);
return GenericSelectionExpr::Create(
Context, GSE->getGenericLoc(), GSE->getControllingType(),
GSE->getAssocTypeSourceInfos(), AssocExprs, GSE->getDefaultLoc(),
GSE->getRParenLoc(), GSE->containsUnexpandedParameterPack(),
ResultIdx);
}
return GSE;
}
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) {
assert(UnOp->getOpcode() == UO_AddrOf &&
"Can only take the address of an overloaded function");
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
if (!Method->isImplicitObjectMemberFunction()) {
} else {
ExprResult SubExpr =
FixOverloadedFunctionReference(UnOp->getSubExpr(), Found, Fn);
if (SubExpr.isInvalid())
return ExprError();
if (SubExpr.get() == UnOp->getSubExpr())
return UnOp;
if (CheckUseOfCXXMethodAsAddressOfOperand(UnOp->getBeginLoc(),
SubExpr.get(), Method))
return ExprError();
assert(isa<DeclRefExpr>(SubExpr.get()) &&
"fixed to something other than a decl ref");
assert(cast<DeclRefExpr>(SubExpr.get())->getQualifier() &&
"fixed to a member ref with no nested name qualifier");
QualType ClassType
= Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
QualType MemPtrType
= Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr());
if (Context.getTargetInfo().getCXXABI().isMicrosoft())
(void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType);
return UnaryOperator::Create(Context, SubExpr.get(), UO_AddrOf,
MemPtrType, VK_PRValue, OK_Ordinary,
UnOp->getOperatorLoc(), false,
CurFPFeatureOverrides());
}
}
ExprResult SubExpr =
FixOverloadedFunctionReference(UnOp->getSubExpr(), Found, Fn);
if (SubExpr.isInvalid())
return ExprError();
if (SubExpr.get() == UnOp->getSubExpr())
return UnOp;
return CreateBuiltinUnaryOp(UnOp->getOperatorLoc(), UO_AddrOf,
SubExpr.get());
}
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;
if (ULE->hasExplicitTemplateArgs()) {
ULE->copyTemplateArgumentsInto(TemplateArgsBuffer);
TemplateArgs = &TemplateArgsBuffer;
}
QualType Type = Fn->getType();
ExprValueKind ValueKind =
getLangOpts().CPlusPlus && !Fn->hasCXXExplicitFunctionObjectParameter()
? VK_LValue
: VK_PRValue;
if (unsigned BID = Fn->getBuiltinID()) {
if (!Context.BuiltinInfo.isDirectlyAddressable(BID)) {
Type = Context.BuiltinFnTy;
ValueKind = VK_PRValue;
}
}
DeclRefExpr *DRE = BuildDeclRefExpr(
Fn, Type, ValueKind, ULE->getNameInfo(), ULE->getQualifierLoc(),
Found.getDecl(), ULE->getTemplateKeywordLoc(), TemplateArgs);
DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);
return DRE;
}
if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;
if (MemExpr->hasExplicitTemplateArgs()) {
MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
TemplateArgs = &TemplateArgsBuffer;
}
Expr *Base;
if (MemExpr->isImplicitAccess()) {
if (cast<CXXMethodDecl>(Fn)->isStatic()) {
DeclRefExpr *DRE = BuildDeclRefExpr(
Fn, Fn->getType(), VK_LValue, MemExpr->getNameInfo(),
MemExpr->getQualifierLoc(), Found.getDecl(),
MemExpr->getTemplateKeywordLoc(), TemplateArgs);
DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1);
return DRE;
} else {
SourceLocation Loc = MemExpr->getMemberLoc();
if (MemExpr->getQualifier())
Loc = MemExpr->getQualifierLoc().getBeginLoc();
Base =
BuildCXXThisExpr(Loc, MemExpr->getBaseType(), true);
}
} else
Base = MemExpr->getBase();
ExprValueKind valueKind;
QualType type;
if (cast<CXXMethodDecl>(Fn)->isStatic()) {
valueKind = VK_LValue;
type = Fn->getType();
} else {
valueKind = VK_PRValue;
type = Context.BoundMemberTy;
}
return BuildMemberExpr(
Base, MemExpr->isArrow(), MemExpr->getOperatorLoc(),
MemExpr->getQualifierLoc(), MemExpr->getTemplateKeywordLoc(), Fn, Found,
true, MemExpr->getMemberNameInfo(),
type, valueKind, OK_Ordinary, TemplateArgs);
}
llvm_unreachable("Invalid reference to overloaded function");
}
ExprResult Sema::FixOverloadedFunctionReference(ExprResult E,
DeclAccessPair Found,
FunctionDecl *Fn) {
return FixOverloadedFunctionReference(E.get(), Found, Fn);
}
bool clang::shouldEnforceArgLimit(bool PartialOverloading,
FunctionDecl *Function) {
if (!PartialOverloading || !Function)
return true;
if (Function->isVariadic())
return false;
if (const auto *Proto =
dyn_cast<FunctionProtoType>(Function->getFunctionType()))
if (Proto->isTemplateVariadic())
return false;
if (auto *Pattern = Function->getTemplateInstantiationPattern())
if (const auto *Proto =
dyn_cast<FunctionProtoType>(Pattern->getFunctionType()))
if (Proto->isTemplateVariadic())
return false;
return true;
}
void Sema::DiagnoseUseOfDeletedFunction(SourceLocation Loc, SourceRange Range,
DeclarationName Name,
OverloadCandidateSet &CandidateSet,
FunctionDecl *Fn, MultiExprArg Args,
bool IsMember) {
StringLiteral *Msg = Fn->getDeletedMessage();
CandidateSet.NoteCandidates(
PartialDiagnosticAt(Loc, PDiag(diag::err_ovl_deleted_call)
<< IsMember << Name << (Msg != nullptr)
<< (Msg ? Msg->getString() : StringRef())
<< Range),
*this, OCD_AllCandidates, Args);
}