From bc736fceca6f0bca31d16003a7587857190408fb Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 13 Mar 2009 23:49:33 +0000 Subject: [PATCH] Implement template instantiation for the prefix unary operators. As always, refactored the existing logic to tease apart the parser action and the semantic analysis shared by the parser and template instantiation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66987 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 8 ++ lib/AST/Expr.cpp | 30 +++++ lib/Sema/Sema.h | 14 ++- lib/Sema/SemaExpr.cpp | 150 +++++++---------------- lib/Sema/SemaOverload.cpp | 150 ++++++++++++++++++++++- lib/Sema/SemaTemplateInstantiate.cpp | 146 +++++++++++++++------- test/SemaTemplate/instantiate-expr-1.cpp | 16 +++ test/SemaTemplate/instantiate-expr-2.cpp | 15 +++ 8 files changed, 372 insertions(+), 157 deletions(-) diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index bfd8538788..ed571fd6c4 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -660,6 +660,14 @@ public: /// corresponds to, e.g. "sizeof" or "[pre]++" static const char *getOpcodeStr(Opcode Op); + /// \brief Retrieve the unary opcode that corresponds to the given + /// overloaded operator. + static Opcode getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix); + + /// \brief Retrieve the overloaded operator kind that corresponds to + /// the given unary opcode. + static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); + virtual SourceRange getSourceRange() const { if (isPostfix()) return SourceRange(Val->getLocStart(), Loc); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 4b99eefcd4..273b5ed72f 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -91,6 +91,36 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) { } } +UnaryOperator::Opcode +UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) { + switch (OO) { + case OO_PlusPlus: return Postfix? PostInc : PreInc; + case OO_MinusMinus: return Postfix? PostDec : PreDec; + case OO_Amp: return AddrOf; + case OO_Star: return Deref; + case OO_Plus: return Plus; + case OO_Minus: return Minus; + case OO_Tilde: return Not; + case OO_Exclaim: return LNot; + default: assert(false && "No unary operator for overloaded function"); + } +} + +OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { + switch (Opc) { + case PostInc: case PreInc: return OO_PlusPlus; + case PostDec: case PreDec: return OO_MinusMinus; + case AddrOf: return OO_Amp; + case Deref: return OO_Star; + case Plus: return OO_Plus; + case Minus: return OO_Minus; + case Not: return OO_Tilde; + case LNot: return OO_Exclaim; + default: return OO_None; + } +} + + //===----------------------------------------------------------------------===// // Postfix Operators. //===----------------------------------------------------------------------===// diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b29790e7b5..a86aa65aff 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -586,6 +586,11 @@ public: SourceLocation RParenLoc, bool &ArgumentDependentLookup); + OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, + unsigned Opc, + FunctionSet &Functions, + ExprArg input); + OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc, unsigned Opc, FunctionSet &Functions, @@ -1182,16 +1187,19 @@ public: unsigned NumToks); // Binary/Unary Operators. 'Tok' is the token for the operator. + OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, + unsigned OpcIn, + ExprArg InputArg); virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, ExprArg Input); - virtual OwningExprResult - ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, - void *TyOrEx, const SourceRange &ArgRange); OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, bool isSizeOf, SourceRange R); OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, bool isSizeOf, SourceRange R); + virtual OwningExprResult + ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, + void *TyOrEx, const SourceRange &ArgRange); bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R); bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index c04006cb1c..c3ae4f7f67 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4036,114 +4036,22 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs); } -// Unary Operators. 'Tok' is the token for the operator. -Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Op, ExprArg input) { - // FIXME: Input is modified later, but smart pointer not reassigned. - Expr *Input = (Expr*)input.get(); - UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op); - - if (getLangOptions().CPlusPlus && - (Input->getType()->isRecordType() - || Input->getType()->isEnumeralType())) { - // Determine which overloaded operator we're dealing with. - static const OverloadedOperatorKind OverOps[] = { - OO_None, OO_None, - OO_PlusPlus, OO_MinusMinus, - OO_Amp, OO_Star, - OO_Plus, OO_Minus, - OO_Tilde, OO_Exclaim, - OO_None, OO_None, - OO_None, - OO_None - }; - OverloadedOperatorKind OverOp = OverOps[Opc]; - - // Add the appropriate overloaded operators (C++ [over.match.oper]) - // to the candidate set. - OverloadCandidateSet CandidateSet; - if (OverOp != OO_None) - AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet); - - // Perform overload resolution. - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, Best)) { - case OR_Success: { - // We found a built-in operator or an overloaded operator. - FunctionDecl *FnDecl = Best->Function; - - if (FnDecl) { - // We matched an overloaded operator. Build a call to that - // operator. - - // Convert the arguments. - if (CXXMethodDecl *Method = dyn_cast(FnDecl)) { - if (PerformObjectArgumentInitialization(Input, Method)) - return ExprError(); - } else { - // Convert the arguments. - if (PerformCopyInitialization(Input, - FnDecl->getParamDecl(0)->getType(), - "passing")) - return ExprError(); - } - - // Determine the result type - QualType ResultTy - = FnDecl->getType()->getAsFunctionType()->getResultType(); - ResultTy = ResultTy.getNonReferenceType(); - - // Build the actual expression node. - Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), - SourceLocation()); - UsualUnaryConversions(FnExpr); - - input.release(); - return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr, - &Input, 1, ResultTy, - OpLoc)); - } else { - // We matched a built-in operator. Convert the arguments, then - // break out so that we will build the appropriate built-in - // operator node. - if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0], - Best->Conversions[0], "passing")) - return ExprError(); - - break; - } - } - - case OR_No_Viable_Function: - // No viable function; fall through to handling this as a - // built-in operator, which will produce an error message for us. - break; - - case OR_Ambiguous: - Diag(OpLoc, diag::err_ovl_ambiguous_oper) - << UnaryOperator::getOpcodeStr(Opc) - << Input->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return ExprError(); - - case OR_Deleted: - Diag(OpLoc, diag::err_ovl_deleted_oper) - << Best->Function->isDeleted() - << UnaryOperator::getOpcodeStr(Opc) - << Input->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return ExprError(); - } - - // Either we found no viable overloaded operator or we matched a - // built-in operator. In either case, fall through to trying to - // build a built-in operation. - } - +Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, + unsigned OpcIn, + ExprArg InputArg) { + UnaryOperator::Opcode Opc = static_cast(OpcIn); + + // FIXME: Input is modified below, but InputArg is not updated + // appropriately. + Expr *Input = (Expr *)InputArg.get(); QualType resultType; switch (Opc) { - default: - assert(0 && "Unimplemented unary expr!"); + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::OffsetOf: + assert(false && "Invalid unary operator"); + break; + case UnaryOperator::PreInc: case UnaryOperator::PreDec: resultType = CheckIncrementDecrementOperand(Input, OpLoc, @@ -4211,10 +4119,38 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, } if (resultType.isNull()) return ExprError(); - input.release(); + + InputArg.release(); 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) { + 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 + // scope and an argument-dependent lookup based on the types of + // the arguments. + FunctionSet Functions; + OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc); + if (OverOp != OO_None) { + LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), + Functions); + DeclarationName OpName + = Context.DeclarationNames.getCXXOperatorName(OverOp); + ArgumentDependentLookup(OpName, &Input, 1, Functions); + } + + return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); + } + + return CreateBuiltinUnaryOp(OpLoc, Opc, move(input)); +} + /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". Sema::ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 865034707d..8943aa602e 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3623,6 +3623,153 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, return 0; } +/// \brief Create a unary operation that may resolve to an overloaded +/// operator. +/// +/// \param OpLoc The location of the operator itself (e.g., '*'). +/// +/// \param OpcIn The UnaryOperator::Opcode that describes this +/// operator. +/// +/// \param Functions The set of non-member functions that will be +/// considered by overload resolution. The caller needs to build this +/// set based on the context using, e.g., +/// LookupOverloadedOperatorName() and ArgumentDependentLookup(). This +/// set should not contain any member functions; those will be added +/// by CreateOverloadedUnaryOp(). +/// +/// \param input The input argument. +Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, + unsigned OpcIn, + FunctionSet &Functions, + ExprArg input) { + UnaryOperator::Opcode Opc = static_cast(OpcIn); + Expr *Input = (Expr *)input.get(); + + OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc); + assert(Op != OO_None && "Invalid opcode for overloaded unary operator"); + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); + + Expr *Args[2] = { Input, 0 }; + unsigned NumArgs = 1; + + // For post-increment and post-decrement, add the implicit '0' as + // the second argument, so that we know this is a post-increment or + // post-decrement. + if (Opc == UnaryOperator::PostInc || Opc == UnaryOperator::PostDec) { + llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false); + Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy, + SourceLocation()); + NumArgs = 2; + } + + if (Input->isTypeDependent()) { + OverloadedFunctionDecl *Overloads + = OverloadedFunctionDecl::Create(Context, CurContext, OpName); + for (FunctionSet::iterator Func = Functions.begin(), + FuncEnd = Functions.end(); + Func != FuncEnd; ++Func) + Overloads->addOverload(*Func); + + DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy, + OpLoc, false, false); + + input.release(); + return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, + &Args[0], NumArgs, + Context.DependentTy, + OpLoc)); + } + + // Build an empty overload set. + OverloadCandidateSet CandidateSet; + + // Add the candidates from the given function set. + AddFunctionCandidates(Functions, &Args[0], NumArgs, CandidateSet, false); + + // Add operator candidates that are member functions. + AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); + + // Add builtin operator candidates. + AddBuiltinOperatorCandidates(Op, &Args[0], NumArgs, CandidateSet); + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: { + // We found a built-in operator or an overloaded operator. + FunctionDecl *FnDecl = Best->Function; + + if (FnDecl) { + // We matched an overloaded operator. Build a call to that + // operator. + + // Convert the arguments. + if (CXXMethodDecl *Method = dyn_cast(FnDecl)) { + if (PerformObjectArgumentInitialization(Input, Method)) + return ExprError(); + } else { + // Convert the arguments. + if (PerformCopyInitialization(Input, + FnDecl->getParamDecl(0)->getType(), + "passing")) + return ExprError(); + } + + // Determine the result type + QualType ResultTy + = FnDecl->getType()->getAsFunctionType()->getResultType(); + ResultTy = ResultTy.getNonReferenceType(); + + // Build the actual expression node. + Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), + SourceLocation()); + UsualUnaryConversions(FnExpr); + + input.release(); + return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, + &Input, 1, ResultTy, + OpLoc)); + } else { + // We matched a built-in operator. Convert the arguments, then + // break out so that we will build the appropriate built-in + // operator node. + if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0], + Best->Conversions[0], "passing")) + return ExprError(); + + break; + } + } + + case OR_No_Viable_Function: + // No viable function; fall through to handling this as a + // built-in operator, which will produce an error message for us. + break; + + case OR_Ambiguous: + Diag(OpLoc, diag::err_ovl_ambiguous_oper) + << UnaryOperator::getOpcodeStr(Opc) + << Input->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + + case OR_Deleted: + Diag(OpLoc, diag::err_ovl_deleted_oper) + << Best->Function->isDeleted() + << UnaryOperator::getOpcodeStr(Opc) + << Input->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + } + + // Either we found no viable overloaded operator or we matched a + // built-in operator. In either case, fall through to trying to + // build a built-in operation. + input.release(); + return CreateBuiltinUnaryOp(OpLoc, Opc, Owned(Input)); +} + /// \brief Create a binary operation that may resolve to an overloaded /// operator. /// @@ -3645,7 +3792,6 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, unsigned OpcIn, FunctionSet &Functions, Expr *LHS, Expr *RHS) { - OverloadCandidateSet CandidateSet; Expr *Args[2] = { LHS, RHS }; BinaryOperator::Opcode Opc = static_cast(OpcIn); @@ -3688,6 +3834,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, !LHS->getType()->isOverloadableType()) return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS); + // Build an empty overload set. + OverloadCandidateSet CandidateSet; // Add the candidates from the given function set. AddFunctionCandidates(Functions, Args, 2, CandidateSet, false); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 4bd7ad4e83..4c3f100d74 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -584,6 +584,7 @@ namespace { OwningExprResult VisitIntegerLiteral(IntegerLiteral *E); OwningExprResult VisitDeclRefExpr(DeclRefExpr *E); OwningExprResult VisitParenExpr(ParenExpr *E); + OwningExprResult VisitUnaryOperator(UnaryOperator *E); OwningExprResult VisitBinaryOperator(BinaryOperator *E); OwningExprResult VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); OwningExprResult VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); @@ -633,6 +634,17 @@ TemplateExprInstantiator::VisitParenExpr(ParenExpr *E) { (Expr *)SubExpr.release())); } +Sema::OwningExprResult +TemplateExprInstantiator::VisitUnaryOperator(UnaryOperator *E) { + Sema::OwningExprResult Arg = Visit(E->getSubExpr()); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(), + E->getOpcode(), + move(Arg)); +} + Sema::OwningExprResult TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) { Sema::OwningExprResult LHS = Visit(E->getLHS()); @@ -658,74 +670,116 @@ TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) { Sema::OwningExprResult TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { - // FIXME: Only handles binary operators at the moment. - - Sema::OwningExprResult LHS = Visit(E->getArg(0)); - if (LHS.isInvalid()) + Sema::OwningExprResult First = Visit(E->getArg(0)); + if (First.isInvalid()) return SemaRef.ExprError(); - Sema::OwningExprResult RHS = Visit(E->getArg(1)); - if (RHS.isInvalid()) - return SemaRef.ExprError(); + Expr *Args[2] = { (Expr *)First.get(), 0 }; + + Sema::OwningExprResult Second(SemaRef); + if (E->getNumArgs() == 2) { + Second = Visit(E->getArg(1)); + + if (Second.isInvalid()) + return SemaRef.ExprError(); - Expr *lhs = (Expr *)LHS.get(), *rhs = (Expr *)RHS.get(); - Expr *Args[2] = { lhs, rhs }; + Args[1] = (Expr *)Second.get(); + } if (!E->isTypeDependent()) { // Since our original expression was not type-dependent, we do not // perform lookup again at instantiation time (C++ [temp.dep]p1). // Instead, we just build the new overloaded operator call // expression. - LHS.release(); - RHS.release(); + First.release(); + Second.release(); return SemaRef.Owned(new (SemaRef.Context) CXXOperatorCallExpr( SemaRef.Context, E->getOperator(), E->getCallee(), - Args, 2, E->getType(), + Args, E->getNumArgs(), + E->getType(), E->getOperatorLoc())); } - BinaryOperator::Opcode Opc = - BinaryOperator::getOverloadedOpcode(E->getOperator()); - Sema::OwningExprResult Result(SemaRef); - if (!lhs->getType()->isOverloadableType() && - !rhs->getType()->isOverloadableType()) { - // Neither LHS nor RHS is an overloadable type, so try create a - // built-in binary operation. - Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc, - lhs, rhs); + bool isPostIncDec = E->getNumArgs() == 2 && + (E->getOperator() == OO_PlusPlus || E->getOperator() == OO_MinusMinus); + if (E->getNumArgs() == 1 || isPostIncDec) { + if (!Args[0]->getType()->isOverloadableType()) { + // The argument is not of overloadable type, so try to create a + // built-in unary operation. + UnaryOperator::Opcode Opc + = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec); + + return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(), Opc, + move(First)); + } + + // Fall through to perform overload resolution } else { - // Compute the set of functions that were found at template - // definition time. - Sema::FunctionSet Functions; - DeclRefExpr *DRE = cast(E->getCallee()); - OverloadedFunctionDecl *Overloads - = cast(DRE->getDecl()); - - // FIXME: Do we have to check - // IsAcceptableNonMemberOperatorCandidate for each of these? - for (OverloadedFunctionDecl::function_iterator - F = Overloads->function_begin(), - FEnd = Overloads->function_end(); - F != FEnd; ++F) - Functions.insert(*F); - - // Add any functions found via argument-dependent lookup. - DeclarationName OpName - = SemaRef.Context.DeclarationNames.getCXXOperatorName(E->getOperator()); - SemaRef.ArgumentDependentLookup(OpName, Args, 2, Functions); - - // Create the overloaded operator. - Result = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc, - Functions, lhs, rhs); + assert(E->getNumArgs() == 2 && "Expected binary operation"); + + Sema::OwningExprResult Result(SemaRef); + if (!Args[0]->getType()->isOverloadableType() && + !Args[1]->getType()->isOverloadableType()) { + // Neither of the arguments is an overloadable type, so try to + // create a built-in binary operation. + BinaryOperator::Opcode Opc = + BinaryOperator::getOverloadedOpcode(E->getOperator()); + Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc, + Args[0], Args[1]); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + First.release(); + Second.release(); + return move(Result); + } + + // Fall through to perform overload resolution. } + // Compute the set of functions that were found at template + // definition time. + Sema::FunctionSet Functions; + DeclRefExpr *DRE = cast(E->getCallee()); + OverloadedFunctionDecl *Overloads + = cast(DRE->getDecl()); + + // FIXME: Do we have to check + // IsAcceptableNonMemberOperatorCandidate for each of these? + for (OverloadedFunctionDecl::function_iterator + F = Overloads->function_begin(), + FEnd = Overloads->function_end(); + F != FEnd; ++F) + Functions.insert(*F); + + // Add any functions found via argument-dependent lookup. + DeclarationName OpName + = SemaRef.Context.DeclarationNames.getCXXOperatorName(E->getOperator()); + SemaRef.ArgumentDependentLookup(OpName, Args, E->getNumArgs(), Functions); + + // Create the overloaded operator invocation. + if (E->getNumArgs() == 1 || isPostIncDec) { + UnaryOperator::Opcode Opc + = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec); + return SemaRef.CreateOverloadedUnaryOp(E->getOperatorLoc(), Opc, + Functions, move(First)); + } + + // FIXME: This would be far less ugly if CreateOverloadedBinOp took + // in ExprArg arguments! + BinaryOperator::Opcode Opc = + BinaryOperator::getOverloadedOpcode(E->getOperator()); + OwningExprResult Result + = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc, + Functions, Args[0], Args[1]); + if (Result.isInvalid()) return SemaRef.ExprError(); - LHS.release(); - RHS.release(); + First.release(); + Second.release(); return move(Result); } diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp index 869d558e33..2ea0641b00 100644 --- a/test/SemaTemplate/instantiate-expr-1.cpp +++ b/test/SemaTemplate/instantiate-expr-1.cpp @@ -53,3 +53,19 @@ void test_BitfieldDep() { (void)sizeof(BitfieldDep); } +template +struct BitfieldNeg { + int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}} +}; + +template +struct BitfieldNeg2 { + int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}} +}; + +void test_BitfieldNeg() { + (void)sizeof(BitfieldNeg<-5>); // okay + (void)sizeof(BitfieldNeg<5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg<5>' requested here}} + (void)sizeof(BitfieldNeg2); // okay + (void)sizeof(BitfieldNeg2); // expected-note{{in instantiation of template class 'struct BitfieldNeg2' requested here}} +} diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp index 81af5730de..d90cef5a0b 100644 --- a/test/SemaTemplate/instantiate-expr-2.cpp +++ b/test/SemaTemplate/instantiate-expr-2.cpp @@ -50,3 +50,18 @@ void test_bin_op_overload(A<1> *a1, A<2> *a2, A<4> *a4, A<8> *a8) { ZZ *zz = a8; } +namespace N3 { + eight_bytes operator-(::N3::Z); +} + +namespace N4 { + template + struct UnaryOpOverload { + typedef A type; + }; +} + +void test_unary_op_overload(A<8> *a8) { + typedef N4::UnaryOpOverload::type UZ; + UZ *uz = a8; +} -- 2.40.0