diff options
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 515 |
1 files changed, 320 insertions, 195 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e41cd5b6653a..5f4071924d3f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -25,6 +25,7 @@ #include "clang/AST/ExprOpenMP.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/FixedPoint.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" @@ -97,21 +98,16 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { /// Emit a note explaining that this function is deleted. void Sema::NoteDeletedFunction(FunctionDecl *Decl) { - assert(Decl->isDeleted()); + assert(Decl && Decl->isDeleted()); - CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl); - - if (Method && Method->isDeleted() && Method->isDefaulted()) { + if (Decl->isDefaulted()) { // If the method was explicitly defaulted, point at that declaration. - if (!Method->isImplicit()) + if (!Decl->isImplicit()) Diag(Decl->getLocation(), diag::note_implicitly_deleted); // Try to diagnose why this special member function was implicitly // deleted. This might fail, if that reason no longer applies. - CXXSpecialMember CSM = getSpecialMember(Method); - if (CSM != CXXInvalid) - ShouldDeleteSpecialMember(Method, CSM, nullptr, /*Diagnose=*/true); - + DiagnoseDeletedDefaultedFunction(Decl); return; } @@ -330,6 +326,30 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); + // [expr.prim.id]p4 + // A program that refers explicitly or implicitly to a function with a + // trailing requires-clause whose constraint-expression is not satisfied, + // other than to declare it, is ill-formed. [...] + // + // See if this is a function with constraints that need to be satisfied. + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (Expr *RC = FD->getTrailingRequiresClause()) { + ConstraintSatisfaction Satisfaction; + bool Failed = CheckConstraintSatisfaction(RC, Satisfaction); + if (Failed) + // A diagnostic will have already been generated (non-constant + // constraint expression, for example) + return true; + if (!Satisfaction.IsSatisfied) { + Diag(Loc, + diag::err_reference_to_function_with_unsatisfied_constraints) + << D; + DiagnoseUnsatisfiedConstraint(Satisfaction); + return true; + } + } + } + return false; } @@ -481,16 +501,22 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) { // optimizer will delete, so warn about it. People sometimes try to use this // to get a deterministic trap and are surprised by clang's behavior. This // only handles the pattern "*null", which is a very syntactic check. - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts())) - if (UO->getOpcode() == UO_Deref && - UO->getSubExpr()->IgnoreParenCasts()-> - isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) && + const auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts()); + if (UO && UO->getOpcode() == UO_Deref && + UO->getSubExpr()->getType()->isPointerType()) { + const LangAS AS = + UO->getSubExpr()->getType()->getPointeeType().getAddressSpace(); + if ((!isTargetAddressSpace(AS) || + (isTargetAddressSpace(AS) && toTargetAddressSpace(AS) == 0)) && + UO->getSubExpr()->IgnoreParenCasts()->isNullPointerConstant( + S.Context, Expr::NPC_ValueDependentIsNotNull) && !UO->getType().isVolatileQualified()) { - S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, - S.PDiag(diag::warn_indirection_through_null) - << UO->getSubExpr()->getSourceRange()); - S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, - S.PDiag(diag::note_indirection_through_null)); + S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, + S.PDiag(diag::warn_indirection_through_null) + << UO->getSubExpr()->getSourceRange()); + S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, + S.PDiag(diag::note_indirection_through_null)); + } } } @@ -1331,13 +1357,72 @@ static QualType handleFixedPointConversion(Sema &S, QualType LHSTy, return ResultTy; } +/// Check that the usual arithmetic conversions can be performed on this pair of +/// expressions that might be of enumeration type. +static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS, + SourceLocation Loc, + Sema::ArithConvKind ACK) { + // C++2a [expr.arith.conv]p1: + // If one operand is of enumeration type and the other operand is of a + // different enumeration type or a floating-point type, this behavior is + // deprecated ([depr.arith.conv.enum]). + // + // Warn on this in all language modes. Produce a deprecation warning in C++20. + // Eventually we will presumably reject these cases (in C++23 onwards?). + QualType L = LHS->getType(), R = RHS->getType(); + bool LEnum = L->isUnscopedEnumerationType(), + REnum = R->isUnscopedEnumerationType(); + bool IsCompAssign = ACK == Sema::ACK_CompAssign; + if ((!IsCompAssign && LEnum && R->isFloatingType()) || + (REnum && L->isFloatingType())) { + S.Diag(Loc, S.getLangOpts().CPlusPlus2a + ? diag::warn_arith_conv_enum_float_cxx2a + : diag::warn_arith_conv_enum_float) + << LHS->getSourceRange() << RHS->getSourceRange() + << (int)ACK << LEnum << L << R; + } else if (!IsCompAssign && LEnum && REnum && + !S.Context.hasSameUnqualifiedType(L, R)) { + unsigned DiagID; + if (!L->castAs<EnumType>()->getDecl()->hasNameForLinkage() || + !R->castAs<EnumType>()->getDecl()->hasNameForLinkage()) { + // If either enumeration type is unnamed, it's less likely that the + // user cares about this, but this situation is still deprecated in + // C++2a. Use a different warning group. + DiagID = S.getLangOpts().CPlusPlus2a + ? diag::warn_arith_conv_mixed_anon_enum_types_cxx2a + : diag::warn_arith_conv_mixed_anon_enum_types; + } else if (ACK == Sema::ACK_Conditional) { + // Conditional expressions are separated out because they have + // historically had a different warning flag. + DiagID = S.getLangOpts().CPlusPlus2a + ? diag::warn_conditional_mixed_enum_types_cxx2a + : diag::warn_conditional_mixed_enum_types; + } else if (ACK == Sema::ACK_Comparison) { + // Comparison expressions are separated out because they have + // historically had a different warning flag. + DiagID = S.getLangOpts().CPlusPlus2a + ? diag::warn_comparison_mixed_enum_types_cxx2a + : diag::warn_comparison_mixed_enum_types; + } else { + DiagID = S.getLangOpts().CPlusPlus2a + ? diag::warn_arith_conv_mixed_enum_types_cxx2a + : diag::warn_arith_conv_mixed_enum_types; + } + S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange() + << (int)ACK << L << R; + } +} + /// UsualArithmeticConversions - Performs various conversions that are common to /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this /// routine returns the first non-arithmetic type found. The client is /// responsible for emitting appropriate error diagnostics. QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, - bool IsCompAssign) { - if (!IsCompAssign) { + SourceLocation Loc, + ArithConvKind ACK) { + checkEnumArithmeticConversions(*this, LHS.get(), RHS.get(), Loc, ACK); + + if (ACK != ACK_CompAssign) { LHS = UsualUnaryConversions(LHS.get()); if (LHS.isInvalid()) return QualType(); @@ -1374,7 +1459,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get()); if (!LHSBitfieldPromoteTy.isNull()) LHSType = LHSBitfieldPromoteTy; - if (LHSType != LHSUnpromotedType && !IsCompAssign) + if (LHSType != LHSUnpromotedType && ACK != ACK_CompAssign) LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast); // If both types are identical, no conversion is needed. @@ -1391,24 +1476,24 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // Handle complex types first (C99 6.3.1.8p1). if (LHSType->isComplexType() || RHSType->isComplexType()) return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, - IsCompAssign); + ACK == ACK_CompAssign); // Now handle "real" floating types (i.e. float, double, long double). if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType()) return handleFloatConversion(*this, LHS, RHS, LHSType, RHSType, - IsCompAssign); + ACK == ACK_CompAssign); // Handle GCC complex int extension. if (LHSType->isComplexIntegerType() || RHSType->isComplexIntegerType()) return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType, - IsCompAssign); + ACK == ACK_CompAssign); if (LHSType->isFixedPointType() || RHSType->isFixedPointType()) return handleFixedPointConversion(*this, LHSType, RHSType); // Finally, we have two differing integer types. return handleIntegerConversion<doIntegralCast, doIntegralCast> - (*this, LHS, RHS, LHSType, RHSType, IsCompAssign); + (*this, LHS, RHS, LHSType, RHSType, ACK == ACK_CompAssign); } //===----------------------------------------------------------------------===// @@ -1825,6 +1910,25 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D)); MarkDeclRefReferenced(E); + // C++ [except.spec]p17: + // An exception-specification is considered to be needed when: + // - in an expression, the function is the unique lookup result or + // the selected member of a set of overloaded functions. + // + // We delay doing this until after we've built the function reference and + // marked it as used so that: + // a) if the function is defaulted, we get errors from defining it before / + // instead of errors from computing its exception specification, and + // b) if the function is a defaulted comparison, we can use the body we + // build when defining it as input to the exception specification + // computation rather than computing a new body. + if (auto *FPT = Ty->getAs<FunctionProtoType>()) { + if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) { + if (auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT)) + E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers())); + } + } + if (getLangOpts().ObjCWeak && isa<VarDecl>(D) && Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !isUnevaluatedContext() && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getBeginLoc())) @@ -2704,6 +2808,20 @@ Sema::PerformObjectMemberConversion(Expr *From, FromRecordType = FromType; DestType = DestRecordType; } + + LangAS FromAS = FromRecordType.getAddressSpace(); + LangAS DestAS = DestRecordType.getAddressSpace(); + if (FromAS != DestAS) { + QualType FromRecordTypeWithoutAS = + Context.removeAddrSpaceQualType(FromRecordType); + QualType FromTypeWithDestAS = + Context.getAddrSpaceQualType(FromRecordTypeWithoutAS, DestAS); + if (PointerConversions) + FromTypeWithDestAS = Context.getPointerType(FromTypeWithDestAS); + From = ImpCastExprToType(From, FromTypeWithDestAS, + CK_AddressSpaceConversion, From->getValueKind()) + .get(); + } } else { // No conversion necessary. return From; @@ -2993,14 +3111,6 @@ ExprResult Sema::BuildDeclarationNameExpr( QualType type = VD->getType(); if (type.isNull()) return ExprError(); - if (auto *FPT = type->getAs<FunctionProtoType>()) { - // C++ [except.spec]p17: - // An exception-specification is considered to be needed when: - // - in an expression, the function is the unique lookup result or - // the selected member of a set of overloaded functions. - ResolveExceptionSpec(Loc, FPT); - type = VD->getType(); - } ExprValueKind valueKind = VK_RValue; switch (D->getKind()) { @@ -5231,6 +5341,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, for (Expr *A : Args.slice(ArgIx)) { ExprResult Arg = DefaultVariadicArgumentPromotion(A, CallType, FDecl); Invalid |= Arg.isInvalid(); + // Copy blocks to the heap. + if (A->getType()->isBlockPointerType()) + maybeExtendBlockObject(Arg); AllArgs.push_back(Arg.get()); } } @@ -5424,15 +5537,15 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, Expr *Arg = ArgRes.get(); QualType ArgType = Arg->getType(); if (!ParamType->isPointerType() || - ParamType.getQualifiers().hasAddressSpace() || + ParamType.hasAddressSpace() || !ArgType->isPointerType() || - !ArgType->getPointeeType().getQualifiers().hasAddressSpace()) { + !ArgType->getPointeeType().hasAddressSpace()) { OverloadParams.push_back(ParamType); continue; } QualType PointeeType = ParamType->getPointeeType(); - if (PointeeType.getQualifiers().hasAddressSpace()) + if (PointeeType.hasAddressSpace()) continue; NeedsNewDecl = true; @@ -7363,7 +7476,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, /*AllowBothBool*/true, /*AllowBoolConversions*/false); - QualType ResTy = UsualArithmeticConversions(LHS, RHS); + QualType ResTy = + UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -7639,7 +7753,7 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, E = E->IgnoreConversionOperator(); E = E->IgnoreImpCasts(); if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) { - E = MTE->GetTemporaryExpr(); + E = MTE->getSubExpr(); E = E->IgnoreImpCasts(); } @@ -8695,7 +8809,7 @@ namespace { struct OriginalOperand { explicit OriginalOperand(Expr *Op) : Orig(Op), Conversion(nullptr) { if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Op)) - Op = MTE->GetTemporaryExpr(); + Op = MTE->getSubExpr(); if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Op)) Op = BTE->getSubExpr(); if (auto *ICE = dyn_cast<ImplicitCastExpr>(Op)) { @@ -8957,6 +9071,12 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, return true; ScalarCast = CK_IntegralCast; + } else if (VectorEltTy->isIntegralType(S.Context) && + ScalarTy->isRealFloatingType()) { + if (S.Context.getTypeSize(VectorEltTy) == S.Context.getTypeSize(ScalarTy)) + ScalarCast = CK_FloatingToIntegral; + else + return true; } else if (VectorEltTy->isRealFloatingType()) { if (ScalarTy->isRealFloatingType()) { @@ -9276,7 +9396,8 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, /*AllowBothBool*/getLangOpts().AltiVec, /*AllowBoolConversions*/false); - QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign); + QualType compType = UsualArithmeticConversions( + LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -9304,7 +9425,8 @@ QualType Sema::CheckRemainderOperands( return InvalidOperands(Loc, LHS, RHS); } - QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign); + QualType compType = UsualArithmeticConversions( + LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -9593,7 +9715,8 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, return compType; } - QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy); + QualType compType = UsualArithmeticConversions( + LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -9687,7 +9810,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, return compType; } - QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy); + QualType compType = UsualArithmeticConversions( + LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -10018,35 +10142,6 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, return LHSType; } -/// If two different enums are compared, raise a warning. -static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS, - Expr *RHS) { - QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType(); - QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType(); - - const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>(); - if (!LHSEnumType) - return; - const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>(); - if (!RHSEnumType) - return; - - // Ignore anonymous enums. - if (!LHSEnumType->getDecl()->getIdentifier() && - !LHSEnumType->getDecl()->getTypedefNameForAnonDecl()) - return; - if (!RHSEnumType->getDecl()->getIdentifier() && - !RHSEnumType->getDecl()->getTypedefNameForAnonDecl()) - return; - - if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) - return; - - S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types) - << LHSStrippedType << RHSStrippedType - << LHS->getSourceRange() << RHS->getSourceRange(); -} - /// Diagnose bad pointer comparisons. static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc, ExprResult &LHS, ExprResult &RHS, @@ -10085,8 +10180,6 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc, return true; } - LHS = S.ImpCastExprToType(LHS.get(), T, CK_BitCast); - RHS = S.ImpCastExprToType(RHS.get(), T, CK_BitCast); return false; } @@ -10317,7 +10410,6 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, QualType RHSType = RHS->getType(); if (LHSType->hasFloatingRepresentation() || (LHSType->isBlockPointerType() && !BinaryOperator::isEqualityOp(Opc)) || - LHS->getBeginLoc().isMacroID() || RHS->getBeginLoc().isMacroID() || S.inTemplateInstantiation()) return; @@ -10345,45 +10437,64 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, AlwaysEqual, // std::strong_ordering::equal from operator<=> }; - if (Expr::isSameComparisonOperand(LHS, RHS)) { - unsigned Result; - switch (Opc) { - case BO_EQ: case BO_LE: case BO_GE: - Result = AlwaysTrue; - break; - case BO_NE: case BO_LT: case BO_GT: - Result = AlwaysFalse; - break; - case BO_Cmp: - Result = AlwaysEqual; - break; - default: - Result = AlwaysConstant; - break; - } - S.DiagRuntimeBehavior(Loc, nullptr, - S.PDiag(diag::warn_comparison_always) - << 0 /*self-comparison*/ - << Result); - } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) { - // What is it always going to evaluate to? - unsigned Result; - switch(Opc) { - case BO_EQ: // e.g. array1 == array2 - Result = AlwaysFalse; - break; - case BO_NE: // e.g. array1 != array2 - Result = AlwaysTrue; - break; - default: // e.g. array1 <= array2 - // The best we can say is 'a constant' - Result = AlwaysConstant; - break; + // C++2a [depr.array.comp]: + // Equality and relational comparisons ([expr.eq], [expr.rel]) between two + // operands of array type are deprecated. + if (S.getLangOpts().CPlusPlus2a && LHSStripped->getType()->isArrayType() && + RHSStripped->getType()->isArrayType()) { + S.Diag(Loc, diag::warn_depr_array_comparison) + << LHS->getSourceRange() << RHS->getSourceRange() + << LHSStripped->getType() << RHSStripped->getType(); + // Carry on to produce the tautological comparison warning, if this + // expression is potentially-evaluated, we can resolve the array to a + // non-weak declaration, and so on. + } + + if (!LHS->getBeginLoc().isMacroID() && !RHS->getBeginLoc().isMacroID()) { + if (Expr::isSameComparisonOperand(LHS, RHS)) { + unsigned Result; + switch (Opc) { + case BO_EQ: + case BO_LE: + case BO_GE: + Result = AlwaysTrue; + break; + case BO_NE: + case BO_LT: + case BO_GT: + Result = AlwaysFalse; + break; + case BO_Cmp: + Result = AlwaysEqual; + break; + default: + Result = AlwaysConstant; + break; + } + S.DiagRuntimeBehavior(Loc, nullptr, + S.PDiag(diag::warn_comparison_always) + << 0 /*self-comparison*/ + << Result); + } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) { + // What is it always going to evaluate to? + unsigned Result; + switch (Opc) { + case BO_EQ: // e.g. array1 == array2 + Result = AlwaysFalse; + break; + case BO_NE: // e.g. array1 != array2 + Result = AlwaysTrue; + break; + default: // e.g. array1 <= array2 + // The best we can say is 'a constant' + Result = AlwaysConstant; + break; + } + S.DiagRuntimeBehavior(Loc, nullptr, + S.PDiag(diag::warn_comparison_always) + << 1 /*array comparison*/ + << Result); } - S.DiagRuntimeBehavior(Loc, nullptr, - S.PDiag(diag::warn_comparison_always) - << 1 /*array comparison*/ - << Result); } if (isa<CastExpr>(LHSStripped)) @@ -10392,7 +10503,7 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, RHSStripped = RHSStripped->IgnoreParenCasts(); // Warn about comparisons against a string constant (unless the other - // operand is null); the user probably wants strcmp. + // operand is null); the user probably wants string comparison function. Expr *LiteralString = nullptr; Expr *LiteralStringStripped = nullptr; if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && @@ -10500,8 +10611,6 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { - using CCT = ComparisonCategoryType; - QualType LHSType = LHS.get()->getType(); QualType RHSType = RHS.get()->getType(); // Dig out the original argument type and expression before implicit casts @@ -10519,6 +10628,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, return QualType(); } + // FIXME: Consider combining this with checkEnumArithmeticConversions. int NumEnumArgs = (int)LHSStrippedType->isEnumeralType() + RHSStrippedType->isEnumeralType(); if (NumEnumArgs == 1) { @@ -10554,12 +10664,17 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, // C++2a [expr.spaceship]p4: If both operands have arithmetic types, the // usual arithmetic conversions are applied to the operands. - QualType Type = S.UsualArithmeticConversions(LHS, RHS); + QualType Type = + S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (Type.isNull()) return S.InvalidOperands(Loc, LHS, RHS); - assert(Type->isArithmeticType() || Type->isEnumeralType()); + + Optional<ComparisonCategoryType> CCT = + getComparisonCategoryForBuiltinCmp(Type); + if (!CCT) + return S.InvalidOperands(Loc, LHS, RHS); bool HasNarrowing = checkThreeWayNarrowingConversion( S, Type, LHS.get(), LHSType, LHS.get()->getBeginLoc()); @@ -10570,20 +10685,8 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, assert(!Type.isNull() && "composite type for <=> has not been set"); - auto TypeKind = [&]() { - if (const ComplexType *CT = Type->getAs<ComplexType>()) { - if (CT->getElementType()->hasFloatingRepresentation()) - return CCT::WeakEquality; - return CCT::StrongEquality; - } - if (Type->isIntegralOrEnumerationType()) - return CCT::StrongOrdering; - if (Type->hasFloatingRepresentation()) - return CCT::PartialOrdering; - llvm_unreachable("other types are unimplemented"); - }(); - - return S.CheckComparisonCategoryType(TypeKind, Loc); + return S.CheckComparisonCategoryType( + *CCT, Loc, Sema::ComparisonCategoryUsage::OperatorInExpression); } static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS, @@ -10594,15 +10697,14 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS, return checkArithmeticOrEnumeralThreeWayCompare(S, LHS, RHS, Loc); // C99 6.5.8p3 / C99 6.5.9p4 - QualType Type = S.UsualArithmeticConversions(LHS, RHS); + QualType Type = + S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (Type.isNull()) return S.InvalidOperands(Loc, LHS, RHS); assert(Type->isArithmeticType() || Type->isEnumeralType()); - checkEnumComparison(S, Loc, LHS.get(), RHS.get()); - if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc)) return S.InvalidOperands(Loc, LHS, RHS); @@ -10646,6 +10748,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, BinaryOperatorKind Opc) { bool IsRelational = BinaryOperator::isRelationalOp(Opc); bool IsThreeWay = Opc == BO_Cmp; + bool IsOrdered = IsRelational || IsThreeWay; auto IsAnyPointerType = [](ExprResult E) { QualType Ty = E.get()->getType(); return Ty->isPointerType() || Ty->isMemberPointerType(); @@ -10708,36 +10811,26 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, QualType CompositeTy = LHS.get()->getType(); assert(!CompositeTy->isReferenceType()); - auto buildResultTy = [&](ComparisonCategoryType Kind) { - return CheckComparisonCategoryType(Kind, Loc); - }; - - // C++2a [expr.spaceship]p7: If the composite pointer type is a function - // pointer type, a pointer-to-member type, or std::nullptr_t, the - // result is of type std::strong_equality - if (CompositeTy->isFunctionPointerType() || - CompositeTy->isMemberPointerType() || CompositeTy->isNullPtrType()) - // FIXME: consider making the function pointer case produce - // strong_ordering not strong_equality, per P0946R0-Jax18 discussion - // and direction polls - return buildResultTy(ComparisonCategoryType::StrongEquality); - - // C++2a [expr.spaceship]p8: If the composite pointer type is an object - // pointer type, p <=> q is of type std::strong_ordering. - if (CompositeTy->isPointerType()) { + Optional<ComparisonCategoryType> CCT = + getComparisonCategoryForBuiltinCmp(CompositeTy); + if (!CCT) + return InvalidOperands(Loc, LHS, RHS); + + if (CompositeTy->isPointerType() && LHSIsNull != RHSIsNull) { // P0946R0: Comparisons between a null pointer constant and an object - // pointer result in std::strong_equality - if (LHSIsNull != RHSIsNull) - return buildResultTy(ComparisonCategoryType::StrongEquality); - return buildResultTy(ComparisonCategoryType::StrongOrdering); + // pointer result in std::strong_equality, which is ill-formed under + // P1959R0. + Diag(Loc, diag::err_typecheck_three_way_comparison_of_pointer_and_zero) + << (LHSIsNull ? LHS.get()->getSourceRange() + : RHS.get()->getSourceRange()); + return QualType(); } - // C++2a [expr.spaceship]p9: Otherwise, the program is ill-formed. - // TODO: Extend support for operator<=> to ObjC types. - return InvalidOperands(Loc, LHS, RHS); - }; + return CheckComparisonCategoryType( + *CCT, Loc, ComparisonCategoryUsage::OperatorInExpression); + }; - if (!IsRelational && LHSIsNull != RHSIsNull) { + if (!IsOrdered && LHSIsNull != RHSIsNull) { bool IsEquality = Opc == BO_EQ; if (RHSIsNull) DiagnoseAlwaysNonNullPointer(LHS.get(), RHSNullKind, IsEquality, @@ -10756,7 +10849,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // but we allow it as an extension. // FIXME: If we really want to allow this, should it be part of composite // pointer type computation so it works in conditionals too? - if (!IsRelational && + if (!IsOrdered && ((LHSType->isFunctionPointerType() && RHSType->isVoidPointerType()) || (RHSType->isFunctionPointerType() && LHSType->isVoidPointerType()))) { // This is a gcc extension compatibility comparison. @@ -10781,8 +10874,11 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // C++ [expr.rel]p2: // If both operands are pointers, [...] bring them to their composite // pointer type. + // For <=>, the only valid non-pointer types are arrays and functions, and + // we already decayed those, so this is really the same as the relational + // comparison rule. if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >= - (IsRelational ? 2 : 1) && + (IsOrdered ? 2 : 1) && (!LangOpts.ObjCAutoRefCount || !(LHSType->isObjCObjectPointerType() || RHSType->isObjCObjectPointerType()))) { if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) @@ -10845,7 +10941,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // C++ [expr.eq]p4: // Two operands of type std::nullptr_t or one operand of type // std::nullptr_t and the other a null pointer constant compare equal. - if (!IsRelational && LHSIsNull && RHSIsNull) { + if (!IsOrdered && LHSIsNull && RHSIsNull) { if (LHSType->isNullPtrType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); @@ -10858,12 +10954,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // Comparison of Objective-C pointers and block pointers against nullptr_t. // These aren't covered by the composite pointer type rules. - if (!IsRelational && RHSType->isNullPtrType() && + if (!IsOrdered && RHSType->isNullPtrType() && (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); } - if (!IsRelational && LHSType->isNullPtrType() && + if (!IsOrdered && LHSType->isNullPtrType() && (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); @@ -10897,7 +10993,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // C++ [expr.eq]p2: // If at least one operand is a pointer to member, [...] bring them to // their composite pointer type. - if (!IsRelational && + if (!IsOrdered && (LHSType->isMemberPointerType() || RHSType->isMemberPointerType())) { if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); @@ -10907,7 +11003,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } // Handle block pointer types. - if (!IsRelational && LHSType->isBlockPointerType() && + if (!IsOrdered && LHSType->isBlockPointerType() && RHSType->isBlockPointerType()) { QualType lpointee = LHSType->castAs<BlockPointerType>()->getPointeeType(); QualType rpointee = RHSType->castAs<BlockPointerType>()->getPointeeType(); @@ -10923,7 +11019,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } // Allow block pointers to be compared with null pointer constants. - if (!IsRelational + if (!IsOrdered && ((LHSType->isBlockPointerType() && RHSType->isPointerType()) || (LHSType->isPointerType() && RHSType->isBlockPointerType()))) { if (!LHSIsNull && !RHSIsNull) { @@ -10959,6 +11055,9 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false); } + // FIXME: If LPtrToVoid, we should presumably convert the LHS rather than + // the RHS, but we have test coverage for this behavior. + // FIXME: Consider using convertPointersToCompositeType in C++. if (LHSIsNull && !RHSIsNull) { Expr *E = LHS.get(); if (getLangOpts().ObjCAutoRefCount) @@ -10993,12 +11092,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, return computeResultTy(); } - if (!IsRelational && LHSType->isBlockPointerType() && + if (!IsOrdered && LHSType->isBlockPointerType() && RHSType->isBlockCompatibleObjCPointerType(Context)) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BlockPointerToObjCPointerCast); return computeResultTy(); - } else if (!IsRelational && + } else if (!IsOrdered && LHSType->isBlockCompatibleObjCPointerType(Context) && RHSType->isBlockPointerType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, @@ -11015,7 +11114,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // since users tend to want to compare addresses. } else if ((LHSIsNull && LHSType->isIntegerType()) || (RHSIsNull && RHSType->isIntegerType())) { - if (IsRelational) { + if (IsOrdered) { isError = getLangOpts().CPlusPlus; DiagID = isError ? diag::err_typecheck_ordered_comparison_of_pointer_and_zero @@ -11024,7 +11123,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } else if (getLangOpts().CPlusPlus) { DiagID = diag::err_typecheck_comparison_of_pointer_integer; isError = true; - } else if (IsRelational) + } else if (IsOrdered) DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer; else DiagID = diag::ext_typecheck_comparison_of_pointer_integer; @@ -11047,12 +11146,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } // Handle block pointers. - if (!IsRelational && RHSIsNull + if (!IsOrdered && RHSIsNull && LHSType->isBlockPointerType() && RHSType->isIntegerType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); } - if (!IsRelational && LHSIsNull + if (!IsOrdered && LHSIsNull && LHSType->isIntegerType() && RHSType->isBlockPointerType()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); @@ -11129,6 +11228,11 @@ QualType Sema::GetSignedVectorType(QualType V) { QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { + if (Opc == BO_Cmp) { + Diag(Loc, diag::err_three_way_vector_comparison); + return QualType(); + } + // Check to make sure we're operating on vectors of the same type and width, // Allowing one side to be a scalar of element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false, @@ -11318,9 +11422,13 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, if (Opc == BO_And) diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc); + if (LHS.get()->getType()->hasFloatingRepresentation() || + RHS.get()->getType()->hasFloatingRepresentation()) + return InvalidOperands(Loc, LHS, RHS); + ExprResult LHSResult = LHS, RHSResult = RHS; - QualType compType = UsualArithmeticConversions(LHSResult, RHSResult, - IsCompAssign); + QualType compType = UsualArithmeticConversions( + LHSResult, RHSResult, Loc, IsCompAssign ? ACK_CompAssign : ACK_BitwiseOp); if (LHSResult.isInvalid() || RHSResult.isInvalid()) return QualType(); LHS = LHSResult.get(); @@ -13011,6 +13119,14 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid()) return ExprError(); + if (ResultTy->isRealFloatingType() && + (getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest || + getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore)) + // Mark the current function as usng floating point constrained intrinsics + if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) { + F->setUsesFPIntrin(true); + } + // Some of the binary operations require promoting operands of half vector to // float vectors and truncating the result back to half vector. For now, we do // this only when HalfArgsAndReturn is set (that is, when the target is arm or @@ -15268,8 +15384,7 @@ static bool funcHasParameterSizeMangling(Sema &S, FunctionDecl *FD) { // These manglings don't do anything on non-Windows or non-x86 platforms, so // we don't need parameter type sizes. const llvm::Triple &TT = S.Context.getTargetInfo().getTriple(); - if (!TT.isOSWindows() || (TT.getArch() != llvm::Triple::x86 && - TT.getArch() != llvm::Triple::x86_64)) + if (!TT.isOSWindows() || !TT.isX86()) return false; // If this is C++ and this isn't an extern "C" function, parameters do not @@ -15385,9 +15500,8 @@ static OdrUseContext isOdrUseContext(Sema &SemaRef) { } static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) { - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func); return Func->isConstexpr() && - (Func->isImplicitlyInstantiable() || (MD && !MD->isUserProvided())); + (Func->isImplicitlyInstantiable() || !Func->isUserProvided()); } /// Mark a function referenced, and check whether it is odr-used @@ -15467,19 +15581,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, Func->getMemberSpecializationInfo())) checkSpecializationVisibility(Loc, Func); - // C++14 [except.spec]p17: - // An exception-specification is considered to be needed when: - // - the function is odr-used or, if it appears in an unevaluated operand, - // would be odr-used if the expression were potentially-evaluated; - // - // Note, we do this even if MightBeOdrUse is false. That indicates that the - // function is a pure virtual function we're calling, and in that case the - // function was selected by overload resolution and we need to resolve its - // exception specification for a different reason. - const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>(); - if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) - ResolveExceptionSpec(Loc, FPT); - if (getLangOpts().CUDA) CheckCUDACall(Loc, Func); @@ -15535,6 +15636,12 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, MarkVTableUsed(Loc, MethodDecl->getParent()); } + if (Func->isDefaulted() && !Func->isDeleted()) { + DefaultedComparisonKind DCK = getDefaultedComparisonKind(Func); + if (DCK != DefaultedComparisonKind::None) + DefineDefaultedComparison(Loc, Func, DCK); + } + // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { @@ -15582,6 +15689,19 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, }); } + // C++14 [except.spec]p17: + // An exception-specification is considered to be needed when: + // - the function is odr-used or, if it appears in an unevaluated operand, + // would be odr-used if the expression were potentially-evaluated; + // + // Note, we do this even if MightBeOdrUse is false. That indicates that the + // function is a pure virtual function we're calling, and in that case the + // function was selected by overload resolution and we need to resolve its + // exception specification for a different reason. + const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>(); + if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) + ResolveExceptionSpec(Loc, FPT); + // If this is the first "real" use, act on that. if (OdrUse == OdrUseContext::Used && !Func->isUsed(/*CheckUsedAttr=*/false)) { // Keep track of used but undefined functions. @@ -17880,7 +18000,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization // leaves Result unchanged on failure. Result = E; - if (resolveAndFixAddressOfOnlyViableOverloadCandidate(Result)) + if (resolveAndFixAddressOfSingleOverloadCandidate(Result)) return Result; // If that failed, try to recover with a call. @@ -18017,3 +18137,8 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); } + +bool Sema::IsDependentFunctionNameExpr(Expr *E) { + assert(E->isTypeDependent()); + return isa<UnresolvedLookupExpr>(E); +} |