diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 29 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 62 | ||||
-rw-r--r-- | clang/test/SemaCXX/overloaded-builtin-operators.cpp | 15 | ||||
-rw-r--r-- | clang/test/SemaCXX/overloaded-operator.cpp | 21 |
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'}} +} |