Be sure to build a dependent expression when we see

a binary operator involving a dependently-typed overload set.

llvm-svn: 143172
This commit is contained in:
John McCall 2011-10-28 01:04:34 +00:00
parent 16dab1bada
commit 9a43e12117
2 changed files with 35 additions and 12 deletions

View File

@ -8007,6 +8007,12 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHSExpr, Expr *RHSExpr) {
// We want to end up calling one of checkPseudoObjectAssignment
// (if the LHS is a pseudo-object), BuildOverloadedBinOp (if
// both expressions are overloadable or either is type-dependent),
// or CreateBuiltinBinOp (in any other case). We also want to get
// any placeholder types out of the way.
// Handle pseudo-objects in the LHS.
if (const BuiltinType *pty = LHSExpr->getType()->getAsPlaceholderType()) {
// Assignments with a pseudo-object l-value need special analysis.
@ -8018,12 +8024,15 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
if (pty->getKind() == BuiltinType::Overload) {
// We can't actually test that if we still have a placeholder,
// though. Fortunately, none of the exceptions we see in that
// code below are valid when the LHS is an overload set.
// code below are valid when the LHS is an overload set. Note
// that an overload set can be dependently-typed, but it never
// instantiates to having an overloadable type.
ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr);
if (resolvedRHS.isInvalid()) return ExprError();
RHSExpr = resolvedRHS.take();
if (RHSExpr->getType()->isOverloadableType())
if (RHSExpr->isTypeDependent() ||
RHSExpr->getType()->isOverloadableType())
return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
}
@ -8036,8 +8045,12 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
if (const BuiltinType *pty = RHSExpr->getType()->getAsPlaceholderType()) {
// An overload in the RHS can potentially be resolved by the type
// being assigned to.
if (Opc == BO_Assign && pty->getKind() == BuiltinType::Overload)
if (Opc == BO_Assign && pty->getKind() == BuiltinType::Overload) {
if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())
return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
}
// Don't resolve overloads if the other type is overloadable.
if (pty->getKind() == BuiltinType::Overload &&
@ -8050,16 +8063,15 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
}
if (getLangOptions().CPlusPlus) {
bool UseBuiltinOperator;
// If either expression is type-dependent, always build an
// overloaded op.
if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())
return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) {
UseBuiltinOperator = false;
} else {
UseBuiltinOperator = !LHSExpr->getType()->isOverloadableType() &&
!RHSExpr->getType()->isOverloadableType();
}
if (!UseBuiltinOperator)
// Otherwise, build an overloaded op if either expression has an
// overloadable type.
if (LHSExpr->getType()->isOverloadableType() ||
RHSExpr->getType()->isOverloadableType())
return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
}

View File

@ -17,3 +17,14 @@ void f(int i, int j) {
// CHECK: ret
(i += j) = 17;
}
// Taken from g++.old-deja/g++.jason/net.C
namespace test1 {
template <class T> void fn (T t) { }
template <class T> struct A {
void (*p)(T);
A() { p = fn; }
};
A<int> a;
}