From 7b80b4b9a9df2ee54466922ce14cdfd639ac1972 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Sun, 12 Dec 2010 09:14:11 +0000 Subject: [PATCH] Sink the logic to suppress builtin operator overloads in the presence of user-defined operator overloads on the same enumeral types to the one place where it is used. In theory this removes wasted computation from several paths through this code, but I'm not aware of a case where it actually matters. This is mostly for cleanliness. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121630 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaOverload.cpp | 104 +++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 69f48d69a8..937384d3a1 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4839,9 +4839,50 @@ public: // bool operator>=(T, T); // bool operator==(T, T); // bool operator!=(T, T); - void addRelationalPointerOrEnumeralOverloads( - const llvm::DenseSet > - &UserDefinedBinaryOperators) { + void addRelationalPointerOrEnumeralOverloads() { + // C++ [over.built]p1: + // If there is a user-written candidate with the same name and parameter + // types as a built-in candidate operator function, the built-in operator + // function is hidden and is not included in the set of candidate + // functions. + // + // The text is actually in a note, but if we don't implement it then we end + // up with ambiguities when the user provides an overloaded operator for + // an enumeration type. Note that only enumeration types have this problem, + // so we track which enumeration types we've seen operators for. Also, the + // only other overloaded operator with enumeration argumenst, operator=, + // cannot be overloaded for enumeration types, so this is the only place + // where we must suppress candidates like this. + llvm::DenseSet > + UserDefinedBinaryOperators; + + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + if (CandidateTypes[ArgIdx].enumeration_begin() != + CandidateTypes[ArgIdx].enumeration_end()) { + for (OverloadCandidateSet::iterator C = CandidateSet.begin(), + CEnd = CandidateSet.end(); + C != CEnd; ++C) { + if (!C->Viable || !C->Function || C->Function->getNumParams() != 2) + continue; + + QualType FirstParamType = + C->Function->getParamDecl(0)->getType().getUnqualifiedType(); + QualType SecondParamType = + C->Function->getParamDecl(1)->getType().getUnqualifiedType(); + + // Skip if either parameter isn't of enumeral type. + if (!FirstParamType->isEnumeralType() || + !SecondParamType->isEnumeralType()) + continue; + + // Add this operator to the set of known user-defined operators. + UserDefinedBinaryOperators.insert( + std::make_pair(S.Context.getCanonicalType(FirstParamType), + S.Context.getCanonicalType(SecondParamType))); + } + } + } + /// Set of (canonical) types that we've already handled. llvm::SmallPtrSet AddedTypes; @@ -4864,15 +4905,16 @@ public: Enum != EnumEnd; ++Enum) { CanQualType CanonType = S.Context.getCanonicalType(*Enum); - // Don't add the same builtin candidate twice. - if (!AddedTypes.insert(CanonType)) + // Don't add the same builtin candidate twice, or if a user defined + // candidate exists. + if (!AddedTypes.insert(CanonType) || + UserDefinedBinaryOperators.count(std::make_pair(CanonType, + CanonType))) continue; QualType ParamTypes[2] = { *Enum, *Enum }; - if (!UserDefinedBinaryOperators.count( - std::make_pair(CanonType, CanonType))) - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, + CandidateSet); } } } @@ -5486,47 +5528,6 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, VisibleTypeConversionsQuals); } - // C++ [over.built]p1: - // If there is a user-written candidate with the same name and parameter - // types as a built-in candidate operator function, the built-in operator - // function is hidden and is not included in the set of candidate functions. - // - // The text is actually in a note, but if we don't implement it then we end - // up with ambiguities when the user provides an overloaded operator for - // an enumeration type. Note that only enumeration types have this problem, - // so we track which enumeration types we've seen operators for. - llvm::DenseSet > - UserDefinedBinaryOperators; - - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { - if (CandidateTypes[ArgIdx].enumeration_begin() - != CandidateTypes[ArgIdx].enumeration_end()) { - for (OverloadCandidateSet::iterator C = CandidateSet.begin(), - CEnd = CandidateSet.end(); - C != CEnd; ++C) { - if (!C->Viable || !C->Function || C->Function->getNumParams() != 2) - continue; - - // Check if the first parameter is of enumeration type. - QualType FirstParamType - = C->Function->getParamDecl(0)->getType().getUnqualifiedType(); - if (!FirstParamType->isEnumeralType()) - continue; - - // Check if the second parameter is of enumeration type. - QualType SecondParamType - = C->Function->getParamDecl(1)->getType().getUnqualifiedType(); - if (!SecondParamType->isEnumeralType()) - continue; - - // Add this operator to the set of known user-defined operators. - UserDefinedBinaryOperators.insert( - std::make_pair(Context.getCanonicalType(FirstParamType), - Context.getCanonicalType(SecondParamType))); - } - } - } - // Setup an object to manage the common state for building overloads. BuiltinOperatorOverloadBuilder OpBuilder(*this, Args, NumArgs, VisibleTypeConversionsQuals, @@ -5594,8 +5595,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, case OO_Greater: case OO_LessEqual: case OO_GreaterEqual: - OpBuilder.addRelationalPointerOrEnumeralOverloads( - UserDefinedBinaryOperators); + OpBuilder.addRelationalPointerOrEnumeralOverloads(); OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/true); break; -- 2.40.0