aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-09-12 04:28:07 +0000
committerDouglas Gregor <dgregor@apple.com>2010-09-12 04:28:07 +0000
commit661b4939ae3f84380dc3e670a06e963b4b9d3b6e (patch)
tree637cea5a669deb49d031b9e8ef010d9298e81bc3
parent5dde1605da5e6db8a9214f4a5d094ae0bbc64a4e (diff)
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
-rw-r--r--lib/Sema/SemaOverload.cpp44
-rw-r--r--test/CXX/over/over.built/p1.cpp16
2 files changed, 59 insertions, 1 deletions
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 <algorithm>
@@ -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<std::pair<CanQualType, CanQualType> >
+ 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;
+}