/// \brief The set of vector types that will be used in the built-in
/// candidates.
TypeSet VectorTypes;
-
+
+ /// \brief A flag indicating non-record types are viable candidates
+ bool HasNonRecordTypes;
+
+ /// \brief A flag indicating whether either arithmetic or enumeration types
+ /// were present in the candidate set.
+ bool HasArithmeticOrEnumeralTypes;
+
/// Sema - The semantic analysis instance where we are building the
/// candidate type set.
Sema &SemaRef;
typedef TypeSet::iterator iterator;
BuiltinCandidateTypeSet(Sema &SemaRef)
- : SemaRef(SemaRef), Context(SemaRef.Context) { }
+ : HasNonRecordTypes(false),
+ HasArithmeticOrEnumeralTypes(false),
+ SemaRef(SemaRef),
+ Context(SemaRef.Context) { }
void AddTypesConvertedFrom(QualType Ty,
SourceLocation Loc,
iterator vector_begin() { return VectorTypes.begin(); }
iterator vector_end() { return VectorTypes.end(); }
+
+ bool hasNonRecordTypes() { return HasNonRecordTypes; }
+ bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; }
};
/// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to
// We don't care about qualifiers on the type.
Ty = Ty.getLocalUnqualifiedType();
+ // Flag if we ever add a non-record type.
+ const RecordType *TyRec = Ty->getAs<RecordType>();
+ HasNonRecordTypes = HasNonRecordTypes || !TyRec;
+
// If we're dealing with an array type, decay to the pointer.
if (Ty->isArrayType())
Ty = SemaRef.Context.getArrayDecayedType(Ty);
+
+ // Flag if we encounter an arithmetic type.
+ HasArithmeticOrEnumeralTypes =
+ HasArithmeticOrEnumeralTypes || Ty->isArithmeticType();
+
if (Ty->isObjCIdType() || Ty->isObjCClassType())
PointerTypes.insert(Ty);
else if (Ty->getAs<PointerType>() || Ty->getAs<ObjCObjectPointerType>()) {
if (!AddMemberPointerWithMoreQualifiedTypeVariants(Ty))
return;
} else if (Ty->isEnumeralType()) {
+ HasArithmeticOrEnumeralTypes = true;
EnumerationTypes.insert(Ty);
} else if (Ty->isVectorType()) {
+ // We treat vector types as arithmetic types in many contexts as an
+ // extension.
+ HasArithmeticOrEnumeralTypes = true;
VectorTypes.insert(Ty);
- } else if (AllowUserConversions) {
- if (const RecordType *TyRec = Ty->getAs<RecordType>()) {
- if (SemaRef.RequireCompleteType(Loc, Ty, 0)) {
- // No conversion functions in incomplete types.
- return;
- }
+ } else if (AllowUserConversions && TyRec) {
+ // No conversion functions in incomplete types.
+ if (SemaRef.RequireCompleteType(Loc, Ty, 0))
+ return;
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- const UnresolvedSetImpl *Conversions
- = ClassDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
- NamedDecl *D = I.getDecl();
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
+ const UnresolvedSetImpl *Conversions
+ = ClassDecl->getVisibleConversionFunctions();
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = I.getDecl();
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
- // Skip conversion function templates; they don't tell us anything
- // about which builtin types we can convert to.
- if (isa<FunctionTemplateDecl>(D))
- continue;
+ // Skip conversion function templates; they don't tell us anything
+ // about which builtin types we can convert to.
+ if (isa<FunctionTemplateDecl>(D))
+ continue;
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
- if (AllowExplicitConversions || !Conv->isExplicit()) {
- AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false,
- VisibleQuals);
- }
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
+ if (AllowExplicitConversions || !Conv->isExplicit()) {
+ AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false,
+ VisibleQuals);
}
}
}
Expr **Args;
unsigned NumArgs;
Qualifiers VisibleTypeConversionsQuals;
+ bool HasArithmeticOrEnumeralCandidateType;
llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes;
OverloadCandidateSet &CandidateSet;
BuiltinOperatorOverloadBuilder(
Sema &S, Expr **Args, unsigned NumArgs,
Qualifiers VisibleTypeConversionsQuals,
+ bool HasArithmeticOrEnumeralCandidateType,
llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes,
OverloadCandidateSet &CandidateSet)
: S(S), Args(Args), NumArgs(NumArgs),
VisibleTypeConversionsQuals(VisibleTypeConversionsQuals),
+ HasArithmeticOrEnumeralCandidateType(
+ HasArithmeticOrEnumeralCandidateType),
CandidateTypes(CandidateTypes),
CandidateSet(CandidateSet) {
// Validate some of our static helper constants in debug builds.
// VQ T& operator--(VQ T&);
// T operator--(VQ T&, int);
void addPlusPlusMinusMinusArithmeticOverloads(OverloadedOperatorKind Op) {
+ if (!HasArithmeticOrEnumeralCandidateType)
+ return;
+
for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1);
Arith < NumArithmeticTypes; ++Arith) {
addPlusPlusMinusMinusStyleOverloads(
// T operator+(T);
// T operator-(T);
void addUnaryPlusOrMinusArithmeticOverloads() {
+ if (!HasArithmeticOrEnumeralCandidateType)
+ return;
+
for (unsigned Arith = FirstPromotedArithmeticType;
Arith < LastPromotedArithmeticType; ++Arith) {
QualType ArithTy = getArithmeticType(Arith);
//
// T operator~(T);
void addUnaryTildePromotedIntegralOverloads() {
+ if (!HasArithmeticOrEnumeralCandidateType)
+ return;
+
for (unsigned Int = FirstPromotedIntegralType;
Int < LastPromotedIntegralType; ++Int) {
QualType IntTy = getArithmeticType(Int);
// between types L and R.
// Our candidates ignore the first parameter.
void addGenericBinaryArithmeticOverloads(bool isComparison) {
+ if (!HasArithmeticOrEnumeralCandidateType)
+ return;
+
for (unsigned Left = FirstPromotedArithmeticType;
Left < LastPromotedArithmeticType; ++Left) {
for (unsigned Right = FirstPromotedArithmeticType;
// where LR is the result of the usual arithmetic conversions
// between types L and R.
void addBinaryBitwiseArithmeticOverloads(OverloadedOperatorKind Op) {
+ if (!HasArithmeticOrEnumeralCandidateType)
+ return;
+
for (unsigned Left = FirstPromotedIntegralType;
Left < LastPromotedIntegralType; ++Left) {
for (unsigned Right = FirstPromotedIntegralType;
// VQ L& operator+=(VQ L&, R);
// VQ L& operator-=(VQ L&, R);
void addAssignmentArithmeticOverloads(bool isEqualOp) {
+ if (!HasArithmeticOrEnumeralCandidateType)
+ return;
+
for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) {
for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
// VQ L& operator^=(VQ L&, R);
// VQ L& operator|=(VQ L&, R);
void addAssignmentIntegralOverloads() {
+ if (!HasArithmeticOrEnumeralCandidateType)
+ return;
+
for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) {
for (unsigned Right = FirstPromotedIntegralType;
Right < LastPromotedIntegralType; ++Right) {
OverloadCandidateSet& CandidateSet) {
// Find all of the types that the arguments can convert to, but only
// if the operator we're looking at has built-in operator candidates
- // that make use of these types.
+ // that make use of these types. Also record whether we encounter non-record
+ // candidate types or either arithmetic or enumeral candidate types.
Qualifiers VisibleTypeConversionsQuals;
VisibleTypeConversionsQuals.addConst();
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]);
-
+
+ bool HasNonRecordCandidateType = false;
+ bool HasArithmeticOrEnumeralCandidateType = false;
llvm::SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes;
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
CandidateTypes.push_back(BuiltinCandidateTypeSet(*this));
Op == OO_AmpAmp ||
Op == OO_PipePipe),
VisibleTypeConversionsQuals);
+ HasNonRecordCandidateType = HasNonRecordCandidateType ||
+ CandidateTypes[ArgIdx].hasNonRecordTypes();
+ HasArithmeticOrEnumeralCandidateType =
+ HasArithmeticOrEnumeralCandidateType ||
+ CandidateTypes[ArgIdx].hasArithmeticOrEnumeralTypes();
}
+ // Exit early when no non-record types have been added to the candidate set
+ // for any of the arguments to the operator.
+ if (!HasNonRecordCandidateType)
+ return;
+
// Setup an object to manage the common state for building overloads.
BuiltinOperatorOverloadBuilder OpBuilder(*this, Args, NumArgs,
VisibleTypeConversionsQuals,
+ HasArithmeticOrEnumeralCandidateType,
CandidateTypes, CandidateSet);
// Dispatch over the operation to add in only those overloads which apply.