From: Douglas Gregor Date: Sun, 12 Sep 2010 04:28:07 +0000 (+0000) Subject: Implement the "note" in C++ [over.built]p1, which is actually meant to X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=661b4939ae3f84380dc3e670a06e963b4b9d3b6e;p=clang Implement the "note" in C++ [over.built]p1, which is actually meant to be a semantic requirement that a built-in overloaded operator is not added to the overload set of there is already a user-defined overloaded operator with the same parameter types. Fixes PR8087. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113713 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 7ec5f3ac81..7fa35269f9 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -25,6 +25,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/PartialDiagnostic.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include @@ -4527,6 +4528,44 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, Op == OO_PipePipe), 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; + + if (CandidateTypes.enumeration_begin() != CandidateTypes.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))); + } + } + bool isComparison = false; switch (Op) { case OO_None: @@ -4779,7 +4818,10 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, = CandidateTypes.enumeration_begin(); Enum != CandidateTypes.enumeration_end(); ++Enum) { QualType ParamTypes[2] = { *Enum, *Enum }; - AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); + CanQualType CanonType = Context.getCanonicalType(*Enum); + if (!UserDefinedBinaryOperators.count( + std::make_pair(CanonType, CanonType))) + AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); } // Fall through. diff --git a/test/CXX/over/over.built/p1.cpp b/test/CXX/over/over.built/p1.cpp new file mode 100644 index 0000000000..6000f5b01c --- /dev/null +++ b/test/CXX/over/over.built/p1.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +enum E1 { one }; +enum E2 { two }; + +bool operator >= (E1, E1) { + return false; +} + +bool operator >= (E1, const E2) { + return false; +} + +bool test(E1 a, E1 b, E2 c) { + return a >= b || a >= c; +}