diff options
Diffstat (limited to 'clang/lib/Sema/SemaExprCXX.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 193 |
1 files changed, 167 insertions, 26 deletions
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index b660bd34865..83474cb7f83 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3610,16 +3610,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Nothing else to do. break; - case ICK_Function_Conversion: - // If both sides are functions (or pointers/references to them), there could - // be incompatible exception declarations. - if (CheckExceptionSpecCompatibility(From, ToType)) - return ExprError(); - - From = ImpCastExprToType(From, ToType, CK_NoOp, - VK_RValue, /*BasePath=*/nullptr, CCK).get(); - break; - case ICK_Integral_Promotion: case ICK_Integral_Conversion: if (ToType->isBooleanType()) { @@ -3866,6 +3856,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: + case ICK_Function_Conversion: case ICK_Qualification: case ICK_Num_Conversion_Kinds: case ICK_C_Only_Conversion: @@ -3878,6 +3869,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Nothing to do. break; + case ICK_Function_Conversion: + // If both sides are functions (or pointers/references to them), there could + // be incompatible exception declarations. + if (CheckExceptionSpecCompatibility(From, ToType)) + return ExprError(); + + From = ImpCastExprToType(From, ToType, CK_NoOp, + VK_RValue, /*BasePath=*/nullptr, CCK).get(); + break; + case ICK_Qualification: { // The qualification keeps the category of the inner expression, unless the // target type isn't a reference. @@ -5393,6 +5394,20 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (LHS.get()->getObjectKind() == OK_BitField || RHS.get()->getObjectKind() == OK_BitField) OK = OK_BitField; + + // If we have function pointer types, unify them anyway to unify their + // exception specifications, if any. + if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { + Qualifiers Qs = LTy.getQualifiers(); + LTy = FindCompositePointerType(QuestionLoc, LHS, RHS, nullptr, + /*ConvertArgs*/false); + LTy = Context.getQualifiedType(LTy, Qs); + + assert(!LTy.isNull() && "failed to find composite pointer type for " + "canonically equivalent function ptr types"); + assert(Context.hasSameType(LTy, RTy) && "bad composite pointer type"); + } + return LTy; } @@ -5447,6 +5462,14 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, RHS = RHSCopy; } + // If we have function pointer types, unify them anyway to unify their + // exception specifications, if any. + if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { + LTy = FindCompositePointerType(QuestionLoc, LHS, RHS); + assert(!LTy.isNull() && "failed to find composite pointer type for " + "canonically equivalent function ptr types"); + } + return LTy; } @@ -5517,6 +5540,78 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, return QualType(); } +static FunctionProtoType::ExceptionSpecInfo +mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, + FunctionProtoType::ExceptionSpecInfo ESI2, + SmallVectorImpl<QualType> &ExceptionTypeStorage) { + ExceptionSpecificationType EST1 = ESI1.Type; + ExceptionSpecificationType EST2 = ESI2.Type; + + // If either of them can throw anything, that is the result. + if (EST1 == EST_None) return ESI1; + if (EST2 == EST_None) return ESI2; + if (EST1 == EST_MSAny) return ESI1; + if (EST2 == EST_MSAny) return ESI2; + + // If either of them is non-throwing, the result is the other. + if (EST1 == EST_DynamicNone) return ESI2; + if (EST2 == EST_DynamicNone) return ESI1; + if (EST1 == EST_BasicNoexcept) return ESI2; + if (EST2 == EST_BasicNoexcept) return ESI1; + + // If either of them is a non-value-dependent computed noexcept, that + // determines the result. + if (EST2 == EST_ComputedNoexcept && ESI2.NoexceptExpr && + !ESI2.NoexceptExpr->isValueDependent()) + return !ESI2.NoexceptExpr->EvaluateKnownConstInt(S.Context) ? ESI2 : ESI1; + if (EST1 == EST_ComputedNoexcept && ESI1.NoexceptExpr && + !ESI1.NoexceptExpr->isValueDependent()) + return !ESI1.NoexceptExpr->EvaluateKnownConstInt(S.Context) ? ESI1 : ESI2; + // If we're left with value-dependent computed noexcept expressions, we're + // stuck. Before C++17, we can just drop the exception specification entirely, + // since it's not actually part of the canonical type. And this should never + // happen in C++17, because it would mean we were computing the composite + // pointer type of dependent types, which should never happen. + if (EST1 == EST_ComputedNoexcept || EST2 == EST_ComputedNoexcept) { + assert(!S.getLangOpts().CPlusPlus1z && + "computing composite pointer type of dependent types"); + return FunctionProtoType::ExceptionSpecInfo(); + } + + // Switch over the possibilities so that people adding new values know to + // update this function. + switch (EST1) { + case EST_None: + case EST_DynamicNone: + case EST_MSAny: + case EST_BasicNoexcept: + case EST_ComputedNoexcept: + llvm_unreachable("handled above"); + + case EST_Dynamic: { + // This is the fun case: both exception specifications are dynamic. Form + // the union of the two lists. + assert(EST2 == EST_Dynamic && "other cases should already be handled"); + llvm::SmallPtrSet<QualType, 8> Found; + for (auto &Exceptions : {ESI1.Exceptions, ESI2.Exceptions}) + for (QualType E : Exceptions) + if (Found.insert(S.Context.getCanonicalType(E)).second) + ExceptionTypeStorage.push_back(E); + + FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic); + Result.Exceptions = ExceptionTypeStorage; + return Result; + } + + case EST_Unevaluated: + case EST_Uninstantiated: + case EST_Unparsed: + llvm_unreachable("shouldn't see unresolved exception specifications here"); + } + + llvm_unreachable("invalid ExceptionSpecificationType"); +} + /// \brief Find a merged pointer type and convert the two expressions to it. /// /// This finds the composite pointer type (or member pointer type) for @p E1 @@ -5531,9 +5626,12 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, /// a non-standard (but still sane) composite type to which both expressions /// can be converted. When such a type is chosen, \c *NonStandardCompositeType /// will be set true. +/// +/// \param ConvertArgs If \c false, do not convert E1 and E2 to the target type. QualType Sema::FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, - bool *NonStandardCompositeType) { + bool *NonStandardCompositeType, + bool ConvertArgs) { if (NonStandardCompositeType) *NonStandardCompositeType = false; @@ -5560,16 +5658,18 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // - if either p1 or p2 is a null pointer constant, T2 or T1, respectively; if (T1IsPointerLike && E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - E2 = ImpCastExprToType(E2, T1, T1->isMemberPointerType() - ? CK_NullToMemberPointer - : CK_NullToPointer).get(); + if (ConvertArgs) + E2 = ImpCastExprToType(E2, T1, T1->isMemberPointerType() + ? CK_NullToMemberPointer + : CK_NullToPointer).get(); return T1; } if (T2IsPointerLike && E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - E1 = ImpCastExprToType(E1, T2, T2->isMemberPointerType() - ? CK_NullToMemberPointer - : CK_NullToPointer).get(); + if (ConvertArgs) + E1 = ImpCastExprToType(E1, T2, T2->isMemberPointerType() + ? CK_NullToMemberPointer + : CK_NullToPointer).get(); return T2; } @@ -5615,8 +5715,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // exists. SmallVector<unsigned, 4> QualifierUnion; SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass; - QualType Composite1 = Context.getCanonicalType(T1); - QualType Composite2 = Context.getCanonicalType(T2); + QualType Composite1 = T1; + QualType Composite2 = T2; unsigned NeedConstBefore = 0; while (true) { const PointerType *Ptr1, *Ptr2; @@ -5662,6 +5762,41 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, break; } + // Apply the function pointer conversion to unify the types. We've already + // unwrapped down to the function types, and we want to merge rather than + // just convert, so do this ourselves rather than calling + // IsFunctionConversion. + // + // FIXME: In order to match the standard wording as closely as possible, we + // currently only do this under a single level of pointers. Ideally, we would + // allow this in general, and set NeedConstBefore to the relevant depth on + // the side(s) where we changed anything. + if (QualifierUnion.size() == 1) { + if (auto *FPT1 = Composite1->getAs<FunctionProtoType>()) { + if (auto *FPT2 = Composite2->getAs<FunctionProtoType>()) { + FunctionProtoType::ExtProtoInfo EPI1 = FPT1->getExtProtoInfo(); + FunctionProtoType::ExtProtoInfo EPI2 = FPT2->getExtProtoInfo(); + + // The result is noreturn if both operands are. + bool Noreturn = + EPI1.ExtInfo.getNoReturn() && EPI2.ExtInfo.getNoReturn(); + EPI1.ExtInfo = EPI1.ExtInfo.withNoReturn(Noreturn); + EPI2.ExtInfo = EPI2.ExtInfo.withNoReturn(Noreturn); + + // The result is nothrow if both operands are. + SmallVector<QualType, 8> ExceptionTypeStorage; + EPI1.ExceptionSpec = EPI2.ExceptionSpec = + mergeExceptionSpecs(*this, EPI1.ExceptionSpec, EPI2.ExceptionSpec, + ExceptionTypeStorage); + + Composite1 = Context.getFunctionType(FPT1->getReturnType(), + FPT1->getParamTypes(), EPI1); + Composite2 = Context.getFunctionType(FPT2->getReturnType(), + FPT2->getParamTypes(), EPI2); + } + } + } + if (NeedConstBefore && NonStandardCompositeType) { // Extension: Add 'const' to qualifiers that come before the first qualifier // mismatch, so that our (non-standard!) composite type meets the @@ -5711,25 +5846,28 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, E1ToC(S, Entity, Kind, E1), E2ToC(S, Entity, Kind, E2), Viable(E1ToC && E2ToC) {} - QualType perform() { + bool perform() { ExprResult E1Result = E1ToC.Perform(S, Entity, Kind, E1); if (E1Result.isInvalid()) - return QualType(); + return true; E1 = E1Result.getAs<Expr>(); ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2); if (E2Result.isInvalid()) - return QualType(); + return true; E2 = E2Result.getAs<Expr>(); - return Composite; + return false; } }; // Try to convert to each composite pointer type. Conversion C1(*this, Loc, E1, E2, Composite1); - if (C1.Viable && Context.hasSameType(Composite1, Composite2)) - return C1.perform(); + if (C1.Viable && Context.hasSameType(Composite1, Composite2)) { + if (ConvertArgs && C1.perform()) + return QualType(); + return C1.Composite; + } Conversion C2(*this, Loc, E1, E2, Composite2); if (C1.Viable == C2.Viable) { @@ -5740,7 +5878,10 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, } // Convert to the chosen type. - return (C1.Viable ? C1 : C2).perform(); + if (ConvertArgs && (C1.Viable ? C1 : C2).perform()) + return QualType(); + + return C1.Viable ? C1.Composite : C2.Composite; } ExprResult Sema::MaybeBindToTemporary(Expr *E) { |

