Skip to content

Commit

Permalink
Revert r284753 "[c++1z] Teach composite pointer type computation how …
Browse files Browse the repository at this point in the history
…to compute the composite"

It caused PR30749.

llvm-svn: 284778
  • Loading branch information
zmodem committed Oct 20, 2016
1 parent ae81850 commit 2b81f42
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 246 deletions.
3 changes: 1 addition & 2 deletions clang/include/clang/Sema/Overload.h
Expand Up @@ -145,8 +145,7 @@ namespace clang {
/// pointer-to-member conversion, or boolean conversion.
ImplicitConversionKind Second : 8;

/// Third - The third conversion can be a qualification conversion
/// or a function conversion.
/// Third - The third conversion can be a qualification conversion.
ImplicitConversionKind Third : 8;

/// \brief Whether this is the deprecated conversion of a
Expand Down
10 changes: 4 additions & 6 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -8954,15 +8954,13 @@ class Sema {
ExprResult &cond, ExprResult &lhs, ExprResult &rhs,
ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc);
QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2,
bool *NonStandardCompositeType = nullptr,
bool ConvertArgs = true);
bool *NonStandardCompositeType = nullptr);
QualType FindCompositePointerType(SourceLocation Loc,
ExprResult &E1, ExprResult &E2,
bool *NonStandardCompositeType = nullptr,
bool ConvertArgs = true) {
bool *NonStandardCompositeType = nullptr) {
Expr *E1Tmp = E1.get(), *E2Tmp = E2.get();
QualType Composite = FindCompositePointerType(
Loc, E1Tmp, E2Tmp, NonStandardCompositeType, ConvertArgs);
QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp,
NonStandardCompositeType);
E1 = E1Tmp;
E2 = E2Tmp;
return Composite;
Expand Down
190 changes: 26 additions & 164 deletions clang/lib/Sema/SemaExprCXX.cpp
Expand Up @@ -3610,6 +3610,16 @@ 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()) {
Expand Down Expand Up @@ -3856,7 +3866,6 @@ 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:
Expand All @@ -3869,16 +3878,6 @@ 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.
Expand Down Expand Up @@ -5394,17 +5393,6 @@ 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()) {
LTy = FindCompositePointerType(QuestionLoc, LHS, RHS, nullptr,
/*ConvertArgs*/false);
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;
}

Expand Down Expand Up @@ -5459,14 +5447,6 @@ 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;
}

Expand Down Expand Up @@ -5537,78 +5517,6 @@ 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
Expand All @@ -5623,12 +5531,9 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1,
/// 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 ConvertArgs) {
bool *NonStandardCompositeType) {
if (NonStandardCompositeType)
*NonStandardCompositeType = false;

Expand All @@ -5655,18 +5560,16 @@ 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)) {
if (ConvertArgs)
E2 = ImpCastExprToType(E2, T1, T1->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer).get();
E2 = ImpCastExprToType(E2, T1, T1->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer).get();
return T1;
}
if (T2IsPointerLike &&
E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
if (ConvertArgs)
E1 = ImpCastExprToType(E1, T2, T2->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer).get();
E1 = ImpCastExprToType(E1, T2, T2->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer).get();
return T2;
}

Expand Down Expand Up @@ -5712,8 +5615,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
// exists.
SmallVector<unsigned, 4> QualifierUnion;
SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
QualType Composite1 = T1;
QualType Composite2 = T2;
QualType Composite1 = Context.getCanonicalType(T1);
QualType Composite2 = Context.getCanonicalType(T2);
unsigned NeedConstBefore = 0;
while (true) {
const PointerType *Ptr1, *Ptr2;
Expand Down Expand Up @@ -5759,41 +5662,6 @@ 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
Expand Down Expand Up @@ -5843,28 +5711,25 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
E1ToC(S, Entity, Kind, E1), E2ToC(S, Entity, Kind, E2),
Viable(E1ToC && E2ToC) {}

bool perform() {
QualType perform() {
ExprResult E1Result = E1ToC.Perform(S, Entity, Kind, E1);
if (E1Result.isInvalid())
return true;
return QualType();
E1 = E1Result.getAs<Expr>();

ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2);
if (E2Result.isInvalid())
return true;
return QualType();
E2 = E2Result.getAs<Expr>();

return false;
return Composite;
}
};

// Try to convert to each composite pointer type.
Conversion C1(*this, Loc, E1, E2, Composite1);
if (C1.Viable && Context.hasSameType(Composite1, Composite2)) {
if (ConvertArgs && C1.perform())
return QualType();
return C1.Composite;
}
if (C1.Viable && Context.hasSameType(Composite1, Composite2))
return C1.perform();
Conversion C2(*this, Loc, E1, E2, Composite2);

if (C1.Viable == C2.Viable) {
Expand All @@ -5875,10 +5740,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
}

// Convert to the chosen type.
if (ConvertArgs && (C1.Viable ? C1 : C2).perform())
return QualType();

return C1.Viable ? C1.Composite : C2.Composite;
return (C1.Viable ? C1 : C2).perform();
}

ExprResult Sema::MaybeBindToTemporary(Expr *E) {
Expand Down

0 comments on commit 2b81f42

Please sign in to comment.