When instantiating a UnaryOperator, allow the resulting expression to

still be dependent or invoke an overloaded operator. Previously, we
only supported builtin operators.

BinaryOperator/CompoundAssignOperator didn't have this issue because
we always built a CXXOperatorCallExpr node, even when name lookup
didn't find any functions to save until instantiation time. Now, that
code builds a BinaryOperator or CompoundAssignOperator rather than a
CXXOperatorCallExpr, to save some space.

llvm-svn: 86087
This commit is contained in:
Douglas Gregor 2009-11-05 00:51:44 +00:00
parent 45119d8850
commit 5287f091b2
5 changed files with 75 additions and 31 deletions

View File

@ -1667,6 +1667,8 @@ public:
OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc,
unsigned OpcIn,
ExprArg InputArg);
OwningExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc,
UnaryOperator::Opcode Opc, ExprArg input);
virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Op, ExprArg Input);
@ -1792,6 +1794,9 @@ public:
virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
tok::TokenKind Kind,
ExprArg LHS, ExprArg RHS);
OwningExprResult BuildBinOp(Scope *S, SourceLocation OpLoc,
BinaryOperator::Opcode Opc,
Expr *lhs, Expr *rhs);
OwningExprResult CreateBuiltinBinOp(SourceLocation TokLoc,
unsigned Opc, Expr *lhs, Expr *rhs);

View File

@ -5509,6 +5509,12 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
// Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0"
DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs);
return BuildBinOp(S, TokLoc, Opc, lhs, rhs);
}
Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
BinaryOperator::Opcode Opc,
Expr *lhs, Expr *rhs) {
if (getLangOptions().CPlusPlus &&
(lhs->getType()->isOverloadableType() ||
rhs->getType()->isOverloadableType())) {
@ -5519,21 +5525,22 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
FunctionSet Functions;
OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);
if (OverOp != OO_None) {
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
Functions);
if (S)
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
Functions);
Expr *Args[2] = { lhs, rhs };
DeclarationName OpName
= Context.DeclarationNames.getCXXOperatorName(OverOp);
ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions);
}
// Build the (potentially-overloaded, potentially-dependent)
// binary operation.
return CreateOverloadedBinOp(TokLoc, Opc, Functions, lhs, rhs);
return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs);
}
// Build a built-in binary operation.
return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs);
}
Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
@ -5624,12 +5631,10 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc));
}
// Unary Operators. 'Tok' is the token for the operator.
Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Op, ExprArg input) {
Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
UnaryOperator::Opcode Opc,
ExprArg input) {
Expr *Input = (Expr*)input.get();
UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType()) {
// Find all of the overloaded operators visible from this
// point. We perform both an operator-name lookup from the local
@ -5638,19 +5643,26 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
FunctionSet Functions;
OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc);
if (OverOp != OO_None) {
LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
Functions);
if (S)
LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
Functions);
DeclarationName OpName
= Context.DeclarationNames.getCXXOperatorName(OverOp);
ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions);
}
return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input));
}
return CreateBuiltinUnaryOp(OpLoc, Opc, move(input));
}
// Unary Operators. 'Tok' is the token for the operator.
Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Op, ExprArg input) {
return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), move(input));
}
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
Sema::OwningExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
SourceLocation LabLoc,

View File

@ -4787,11 +4787,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// If either side is type-dependent, create an appropriate dependent
// expression.
if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
// .* cannot be overloaded.
if (Opc == BinaryOperator::PtrMemD)
return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc,
Context.DependentTy, OpLoc));
if (Functions.empty()) {
// If there are no functions to store, just build a dependent
// BinaryOperator or CompoundAssignment.
if (Opc <= BinaryOperator::Assign || Opc > BinaryOperator::OrAssign)
return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc,
Context.DependentTy, OpLoc));
return Owned(new (Context) CompoundAssignOperator(Args[0], Args[1], Opc,
Context.DependentTy,
Context.DependentTy,
Context.DependentTy,
OpLoc));
}
OverloadedFunctionDecl *Overloads
= OverloadedFunctionDecl::Create(Context, CurContext, OpName);
for (FunctionSet::iterator Func = Functions.begin(),

View File

@ -877,7 +877,7 @@ public:
OwningExprResult RebuildUnaryOperator(SourceLocation OpLoc,
UnaryOperator::Opcode Opc,
ExprArg SubExpr) {
return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, move(SubExpr));
return getSema().BuildUnaryOp(/*Scope=*/0, OpLoc, Opc, move(SubExpr));
}
/// \brief Build a new sizeof or alignof expression with a type argument.
@ -986,15 +986,8 @@ public:
OwningExprResult RebuildBinaryOperator(SourceLocation OpLoc,
BinaryOperator::Opcode Opc,
ExprArg LHS, ExprArg RHS) {
OwningExprResult Result
= getSema().CreateBuiltinBinOp(OpLoc, Opc, (Expr *)LHS.get(),
(Expr *)RHS.get());
if (Result.isInvalid())
return SemaRef.ExprError();
LHS.release();
RHS.release();
return move(Result);
return getSema().BuildBinOp(/*Scope=*/0, OpLoc, Opc,
LHS.takeAs<Expr>(), RHS.takeAs<Expr>());
}
/// \brief Build a new conditional operator expression.

View File

@ -1,5 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
template<int I, int J>
struct Bitfields {
int simple : I; // expected-error{{bit-field 'simple' has zero width}}
@ -69,3 +68,29 @@ void test_BitfieldNeg() {
(void)sizeof(BitfieldNeg2<int, -5>); // okay
(void)sizeof(BitfieldNeg2<int, 5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg2<int, 5>' requested here}}
}
template<typename T>
void increment(T &x) {
(void)++x;
}
struct Incrementable {
Incrementable &operator++();
};
void test_increment(Incrementable inc) {
increment(inc);
}
template<typename T>
void add(const T &x) {
(void)(x + x);
}
struct Addable {
Addable operator+(const Addable&) const;
};
void test_add(Addable &a) {
add(a);
}