From 6ca7cfb3fbe4dc92e457fd303814d274176cf359 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 5 Nov 2009 00:51:44 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86087 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.h | 5 +++ lib/Sema/SemaExpr.cpp | 42 +++++++++++++++--------- lib/Sema/SemaOverload.cpp | 19 ++++++++--- lib/Sema/TreeTransform.h | 13 ++------ test/SemaTemplate/instantiate-expr-1.cpp | 27 ++++++++++++++- 5 files changed, 75 insertions(+), 31 deletions(-) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b0aa7b7473..e97417680b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ea8504549a..c9a28a74ee 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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, diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index dd009a062f..d2bdfb8e2c 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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(), diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 51393a37c0..767725a1f3 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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(), RHS.takeAs()); } /// \brief Build a new conditional operator expression. diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp index 13ee3ab525..fb88213c40 100644 --- a/test/SemaTemplate/instantiate-expr-1.cpp +++ b/test/SemaTemplate/instantiate-expr-1.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s - template struct Bitfields { int simple : I; // expected-error{{bit-field 'simple' has zero width}} @@ -69,3 +68,29 @@ void test_BitfieldNeg() { (void)sizeof(BitfieldNeg2); // okay (void)sizeof(BitfieldNeg2); // expected-note{{in instantiation of template class 'struct BitfieldNeg2' requested here}} } + +template +void increment(T &x) { + (void)++x; +} + +struct Incrementable { + Incrementable &operator++(); +}; + +void test_increment(Incrementable inc) { + increment(inc); +} + +template +void add(const T &x) { + (void)(x + x); +} + +struct Addable { + Addable operator+(const Addable&) const; +}; + +void test_add(Addable &a) { + add(a); +} -- 2.40.0