diff options
-rw-r--r-- | include/clang/AST/Expr.h | 8 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 30 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 14 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 150 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 150 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 146 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-expr-1.cpp | 16 | ||||
-rw-r--r-- | 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<CXXMethodDecl>(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<UnaryOperator::Opcode>(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<UnaryOperator::Opcode>(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<CXXMethodDecl>(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<BinaryOperator::Opcode>(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); @@ -634,6 +635,17 @@ TemplateExprInstantiator::VisitParenExpr(ParenExpr *E) { } 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()); if (LHS.isInvalid()) @@ -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<DeclRefExpr>(E->getCallee()); - OverloadedFunctionDecl *Overloads - = cast<OverloadedFunctionDecl>(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<DeclRefExpr>(E->getCallee()); + OverloadedFunctionDecl *Overloads + = cast<OverloadedFunctionDecl>(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<int, 1, 5>); } +template<int I> +struct BitfieldNeg { + int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}} +}; + +template<typename T, T I> +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<int, -5>); // okay + (void)sizeof(BitfieldNeg2<int, 5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg2<int, 5>' 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<typename T> + struct UnaryOpOverload { + typedef A<sizeof(-T())> type; + }; +} + +void test_unary_op_overload(A<8> *a8) { + typedef N4::UnaryOpOverload<N3::Z>::type UZ; + UZ *uz = a8; +} |