summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/Sema/SemaExpr.cpp29
-rw-r--r--clang/lib/Sema/SemaOverload.cpp62
-rw-r--r--clang/test/SemaCXX/overloaded-builtin-operators.cpp15
-rw-r--r--clang/test/SemaCXX/overloaded-operator.cpp21
4 files changed, 101 insertions, 26 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 960c99af1f2..0e62e26e8b5 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2145,9 +2145,12 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
Diag(Loc, diag::warn_selfcomparison);
}
+ // The result of comparisons is 'bool' in C++, 'int' in C.
+ QualType ResultTy = getLangOptions().CPlusPlus? Context.BoolTy : Context.IntTy;
+
if (isRelational) {
if (lType->isRealType() && rType->isRealType())
- return Context.IntTy;
+ return ResultTy;
} else {
// Check for comparisons of floating point operands using != and ==.
if (lType->isFloatingType()) {
@@ -2156,7 +2159,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
}
if (lType->isArithmeticType() && rType->isArithmeticType())
- return Context.IntTy;
+ return ResultTy;
}
bool LHSIsNull = lex->isNullPointerConstant(Context);
@@ -2181,7 +2184,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< lex->getSourceRange() << rex->getSourceRange();
}
ImpCastExprToType(rex, lType); // promote the pointer to pointer
- return Context.IntTy;
+ return ResultTy;
}
// Handle block pointer types.
if (lType->isBlockPointerType() && rType->isBlockPointerType()) {
@@ -2195,7 +2198,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< lex->getSourceRange() << rex->getSourceRange();
}
ImpCastExprToType(rex, lType); // promote the pointer to pointer
- return Context.IntTy;
+ return ResultTy;
}
// Allow block pointers to be compared with null pointer constants.
if ((lType->isBlockPointerType() && rType->isPointerType()) ||
@@ -2206,7 +2209,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< lex->getSourceRange() << rex->getSourceRange();
}
ImpCastExprToType(rex, lType); // promote the pointer to pointer
- return Context.IntTy;
+ return ResultTy;
}
if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
@@ -2224,21 +2227,21 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< lType.getAsString() << rType.getAsString()
<< lex->getSourceRange() << rex->getSourceRange();
ImpCastExprToType(rex, lType);
- return Context.IntTy;
+ return ResultTy;
}
ImpCastExprToType(rex, lType);
- return Context.IntTy;
+ return ResultTy;
}
if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
ImpCastExprToType(rex, lType);
- return Context.IntTy;
+ return ResultTy;
} else {
if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) {
Diag(Loc, diag::warn_incompatible_qualified_id_operands)
<< lType.getAsString() << rType.getAsString()
<< lex->getSourceRange() << rex->getSourceRange();
ImpCastExprToType(rex, lType);
- return Context.IntTy;
+ return ResultTy;
}
}
}
@@ -2249,7 +2252,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< lType.getAsString() << rType.getAsString()
<< lex->getSourceRange() << rex->getSourceRange();
ImpCastExprToType(rex, lType); // promote the integer to pointer
- return Context.IntTy;
+ return ResultTy;
}
if (lType->isIntegerType() &&
(rType->isPointerType() || rType->isObjCQualifiedIdType())) {
@@ -2258,7 +2261,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< lType.getAsString() << rType.getAsString()
<< lex->getSourceRange() << rex->getSourceRange();
ImpCastExprToType(lex, rType); // promote the integer to pointer
- return Context.IntTy;
+ return ResultTy;
}
// Handle block pointers.
if (lType->isBlockPointerType() && rType->isIntegerType()) {
@@ -2267,7 +2270,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< lType.getAsString() << rType.getAsString()
<< lex->getSourceRange() << rex->getSourceRange();
ImpCastExprToType(rex, lType); // promote the integer to pointer
- return Context.IntTy;
+ return ResultTy;
}
if (lType->isIntegerType() && rType->isBlockPointerType()) {
if (!LHSIsNull)
@@ -2275,7 +2278,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< lType.getAsString() << rType.getAsString()
<< lex->getSourceRange() << rex->getSourceRange();
ImpCastExprToType(lex, rType); // promote the integer to pointer
- return Context.IntTy;
+ return ResultTy;
}
return InvalidOperands(Loc, lex, rex);
}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 749b916e0d6..98a32ef2679 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -637,7 +637,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
Context.IntTy, Context.UnsignedIntTy,
Context.LongTy, Context.UnsignedLongTy
};
- for (int Idx = 0; Idx < 0; ++Idx) {
+ for (int Idx = 0; Idx < 4; ++Idx) {
uint64_t ToSize = Context.getTypeSize(PromoteTypes[Idx]);
if (FromSize < ToSize ||
(FromSize == ToSize &&
@@ -1712,6 +1712,42 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
}
}
+/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is
+/// an acceptable non-member overloaded operator for a call whose
+/// arguments have types T1 (and, if non-empty, T2). This routine
+/// implements the check in C++ [over.match.oper]p3b2 concerning
+/// enumeration types.
+static bool
+IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
+ QualType T1, QualType T2,
+ ASTContext &Context) {
+ if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
+ return true;
+
+ const FunctionTypeProto *Proto = Fn->getType()->getAsFunctionTypeProto();
+ if (Proto->getNumArgs() < 1)
+ return false;
+
+ if (T1->isEnumeralType()) {
+ QualType ArgType = Proto->getArgType(0).getNonReferenceType();
+ if (Context.getCanonicalType(T1).getUnqualifiedType()
+ == Context.getCanonicalType(ArgType).getUnqualifiedType())
+ return true;
+ }
+
+ if (Proto->getNumArgs() < 2)
+ return false;
+
+ if (!T2.isNull() && T2->isEnumeralType()) {
+ QualType ArgType = Proto->getArgType(1).getNonReferenceType();
+ if (Context.getCanonicalType(T2).getUnqualifiedType()
+ == Context.getCanonicalType(ArgType).getUnqualifiedType())
+ return true;
+ }
+
+ return false;
+}
+
/// AddOperatorCandidates - Add the overloaded operator candidates for
/// the operator Op that was used in an operator expression such as "x
/// Op y". S is the scope in which the expression occurred (used for
@@ -1790,18 +1826,19 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
break;
}
- // FIXME: check that strange "However" condition above. It's going
- // to need a special test.
- if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NonMemberOps))
- AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
- /*SuppressUserConversions=*/false);
- else if (OverloadedFunctionDecl *Ovl
- = dyn_cast_or_null<OverloadedFunctionDecl>(NonMemberOps)) {
+ if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NonMemberOps)) {
+ if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
+ AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ } else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast_or_null<OverloadedFunctionDecl>(NonMemberOps)) {
for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
FEnd = Ovl->function_end();
- F != FEnd; ++F)
- AddOverloadCandidate(*F, Args, NumArgs, CandidateSet,
- /*SuppressUserConversions=*/false);
+ F != FEnd; ++F) {
+ if (IsAcceptableNonMemberOperatorCandidate(*F, T1, T2, Context))
+ AddOverloadCandidate(*F, Args, NumArgs, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ }
}
}
@@ -2476,7 +2513,8 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
// the type of the entity being initialized) is a better
// conversion sequence than the standard conversion sequence
// from the return type of F2 to the destination type.
- if (isa<CXXConversionDecl>(Cand1.Function) &&
+ if (Cand1.Function && Cand2.Function &&
+ isa<CXXConversionDecl>(Cand1.Function) &&
isa<CXXConversionDecl>(Cand2.Function)) {
switch (CompareStandardConversionSequences(Cand1.FinalConversion,
Cand2.FinalConversion)) {
diff --git a/clang/test/SemaCXX/overloaded-builtin-operators.cpp b/clang/test/SemaCXX/overloaded-builtin-operators.cpp
index aabe8dde1b1..af328da212b 100644
--- a/clang/test/SemaCXX/overloaded-builtin-operators.cpp
+++ b/clang/test/SemaCXX/overloaded-builtin-operators.cpp
@@ -10,10 +10,21 @@ struct Long {
operator long();
};
+enum E1 { };
+struct Enum1 {
+ operator E1();
+};
+
+enum E2 { };
+struct Enum2 {
+ operator E2();
+};
+
yes& islong(long);
+yes& islong(unsigned long); // FIXME: shouldn't be needed
no& islong(int);
-void f(Short s, Long l) {
+void f(Short s, Long l, Enum1 e1, Enum2 e2) {
// C++ [over.built]p12
(void)static_cast<yes&>(islong(s + l));
(void)static_cast<no&>(islong(s + s));
@@ -22,6 +33,8 @@ void f(Short s, Long l) {
(void)static_cast<yes&>(islong(s % l));
(void)static_cast<yes&>(islong(l << s));
(void)static_cast<no&>(islong(s << l));
+ (void)static_cast<yes&>(islong(e1 % l));
+ // FIXME: should pass (void)static_cast<no&>(islong(e1 % e2));
}
struct ShortRef {
diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp
index 71d949d750a..c540c2dafcb 100644
--- a/clang/test/SemaCXX/overloaded-operator.cpp
+++ b/clang/test/SemaCXX/overloaded-operator.cpp
@@ -48,3 +48,24 @@ struct B {
make_A() == z;
}
};
+
+enum Enum1 { };
+enum Enum2 { };
+
+struct E1 {
+ E1(Enum1) { }
+};
+
+struct E2 {
+ E2(Enum2);
+};
+
+// C++ [over.match.oper]p3 - enum restriction.
+float& operator==(E1, E2);
+
+void enum_test(Enum1 enum1, Enum2 enum2, E1 e1, E2 e2) {
+ float &f1 = (e1 == e2);
+ float &f2 = (enum1 == e2);
+ float &f3 = (e1 == enum2);
+ float &f4 = (enum1 == enum2); // expected-error{{non-const reference to type 'float' cannot be initialized with a temporary of type '_Bool'}}
+}
OpenPOWER on IntegriCloud