diff options
| -rw-r--r-- | clang/Driver/PrintParserCallbacks.cpp | 6 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Action.h | 6 | ||||
| -rw-r--r-- | clang/lib/AST/Expr.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseStmt.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 12 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 219 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 242 | ||||
| -rw-r--r-- | clang/test/SemaCXX/overloaded-builtin-operators.cpp | 40 | ||||
| -rw-r--r-- | clang/test/SemaCXX/overloaded-operator.cpp | 28 | ||||
| -rw-r--r-- | clang/www/cxx_status.html | 38 | 
11 files changed, 522 insertions, 87 deletions
diff --git a/clang/Driver/PrintParserCallbacks.cpp b/clang/Driver/PrintParserCallbacks.cpp index 0048a6d459b..2a85f64646f 100644 --- a/clang/Driver/PrintParserCallbacks.cpp +++ b/clang/Driver/PrintParserCallbacks.cpp @@ -436,7 +436,7 @@ namespace {      }      // Postfix Expressions. -    virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc,  +    virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,                                              tok::TokenKind Kind, ExprTy *Input) {        llvm::cout << __FUNCTION__ << "\n";        return 0; @@ -467,8 +467,8 @@ namespace {      }      // Unary Operators.  'Tok' is the token for the operator. -    virtual ExprResult ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, -                                    ExprTy *Input) { +    virtual ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,  +                                    tok::TokenKind Op, ExprTy *Input) {        llvm::cout << __FUNCTION__ << "\n";        return 0;      } diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 8e1a23f6e74..e9e59257dfd 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -509,7 +509,7 @@ public:    }    // Postfix Expressions. -  virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc,  +  virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,                                            tok::TokenKind Kind, ExprTy *Input) {      return 0;    } @@ -536,8 +536,8 @@ public:    }    // Unary Operators.  'Tok' is the token for the operator. -  virtual ExprResult ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, -                                  ExprTy *Input) { +  virtual ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,  +                                  tok::TokenKind Op, ExprTy *Input) {      return 0;    }    virtual ExprResult  diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 49a4d777838..a179af8b145 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -398,6 +398,11 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {          cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Imag ||          cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Extension)        return cast<UnaryOperator>(this)->getSubExpr()->isLvalue(Ctx);  // GNU. + +    if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.pre.incr]p1 +        (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreInc || +         cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreDec)) +      return LV_Valid;      break;    case ImplicitCastExprClass:      return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid  diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 2b803d9ad0c..440393dac6b 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -515,7 +515,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {      SourceLocation SavedLoc = ConsumeToken();      Res = ParseCastExpression(true);      if (!Res.isInvalid) -      Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); +      Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, Res.Val);      return Res;    }    case tok::amp:           // unary-expression: '&' cast-expression @@ -529,7 +529,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {      SourceLocation SavedLoc = ConsumeToken();      Res = ParseCastExpression(false);      if (!Res.isInvalid) -      Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); +      Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, Res.Val);      return Res;    }     @@ -539,7 +539,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {      SourceLocation SavedLoc = ConsumeToken();      Res = ParseCastExpression(false);      if (!Res.isInvalid) -      Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); +      Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, Res.Val);      return Res;    }    case tok::kw_sizeof:     // unary-expression: 'sizeof' unary-expression @@ -724,8 +724,8 @@ Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {      case tok::plusplus:    // postfix-expression: postfix-expression '++'      case tok::minusminus:  // postfix-expression: postfix-expression '--'        if (!LHS.isInvalid) -        LHS = Actions.ActOnPostfixUnaryOp(Tok.getLocation(), Tok.getKind(), -                                          LHS.Val); +        LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(),  +                                          Tok.getKind(), LHS.Val);        ConsumeToken();        break;      } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 49b81809048..221ad90273d 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -386,7 +386,8 @@ Parser::StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {          }          // Add the __extension__ node to the AST. -        Res = Actions.ActOnUnaryOp(ExtLoc, tok::kw___extension__, Res.Val); +        Res = Actions.ActOnUnaryOp(CurScope, ExtLoc, tok::kw___extension__,  +                                   Res.Val);          if (Res.isInvalid)            continue; diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 29994d41c30..c60fd352f9d 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -435,9 +435,9 @@ public:    void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,                              Expr **Args, unsigned NumArgs,                             OverloadCandidateSet& CandidateSet); -  void AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,  -                                          Expr **Args,  -                                          OverloadCandidateSet& CandidateSet); +  void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,  +                                    Expr **Args, unsigned NumArgs,  +                                    OverloadCandidateSet& CandidateSet);    void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl,                                Expr **Args, unsigned NumArgs,                               OverloadCandidateSet& CandidateSet, @@ -640,8 +640,8 @@ public:    virtual ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks);    // Binary/Unary Operators.  'Tok' is the token for the operator. -  virtual ExprResult ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, -                                  ExprTy *Input); +  virtual ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,  +                                  tok::TokenKind Op, ExprTy *Input);    virtual ExprResult       ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,                             void *TyOrEx, const SourceRange &ArgRange); @@ -649,7 +649,7 @@ public:    bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc,                                   const SourceRange &R, bool isSizeof); -  virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc,  +  virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,                                            tok::TokenKind Kind, ExprTy *Input);    virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 9a77e4f8e1d..c7803722fe9 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -752,19 +752,112 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc) { -Action::ExprResult Sema::ActOnPostfixUnaryOp(SourceLocation OpLoc,  +Action::ExprResult Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,                                                tok::TokenKind Kind,                                               ExprTy *Input) { +  Expr *Arg = (Expr *)Input; +    UnaryOperator::Opcode Opc;    switch (Kind) {    default: assert(0 && "Unknown unary op!");    case tok::plusplus:   Opc = UnaryOperator::PostInc; break;    case tok::minusminus: Opc = UnaryOperator::PostDec; break;    } -  QualType result = CheckIncrementDecrementOperand((Expr *)Input, OpLoc); +   +  if (getLangOptions().CPlusPlus && +      (Arg->getType()->isRecordType() || Arg->getType()->isEnumeralType())) { +    // Which overloaded operator? +    OverloadedOperatorKind OverOp =  +      (Opc == UnaryOperator::PostInc)? OO_PlusPlus : OO_MinusMinus; + +    // C++ [over.inc]p1: +    // +    //     [...] If the function is a member function with one +    //     parameter (which shall be of type int) or a non-member +    //     function with two parameters (the second of which shall be +    //     of type int), it defines the postfix increment operator ++ +    //     for objects of that type. When the postfix increment is +    //     called as a result of using the ++ operator, the int +    //     argument will have value zero. +    Expr *Args[2] = {  +      Arg,  +      new IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0,  +                                     /*isSigned=*/true),  +                         Context.IntTy, SourceLocation()) +    }; + +    // Build the candidate set for overloading +    OverloadCandidateSet CandidateSet; +    AddOperatorCandidates(OverOp, S, Args, 2, 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(Arg, Method)) +            return true; +        } else { +          // Convert the arguments. +          if (PerformCopyInitialization(Arg,  +                                        FnDecl->getParamDecl(0)->getType(), +                                        "passing")) +            return true; +        } + +        // Determine the result type +        QualType ResultTy  +          = FnDecl->getType()->getAsFunctionType()->getResultType(); +        ResultTy = ResultTy.getNonReferenceType(); +         +        // Build the actual expression node. +        Expr *FnExpr = new DeclRefExpr(FnDecl, FnDecl->getType(),  +                                       SourceLocation()); +        UsualUnaryConversions(FnExpr); + +        return new CXXOperatorCallExpr(FnExpr, Args, 2, 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 (PerformCopyInitialization(Arg, Best->BuiltinTypes.ParamTypes[0], +                                      "passing")) +          return true; + +        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) +          << Arg->getSourceRange(); +      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); +      return true; +    } + +    // 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. +  } + +  QualType result = CheckIncrementDecrementOperand(Arg, OpLoc);    if (result.isNull())      return true; -  return new UnaryOperator((Expr *)Input, Opc, result, OpLoc); +  return new UnaryOperator(Arg, Opc, result, OpLoc);  }  Action::ExprResult Sema:: @@ -2819,16 +2912,6 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,          !(lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType())) {        return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);      } - -    // C++ [over.binary]p1: -    //   A binary operator shall be implemented either by a non-static -    //   member function (9.3) with one parameter or by a non-member -    //   function with two parameters. Thus, for any binary operator -    //   @, x@y can be interpreted as either x.operator@(y) or -    //   operator@(x,y). If both forms of the operator function have -    //   been declared, the rules in 13.3.1.2 determines which, if -    //   any, interpretation is used. -    OverloadCandidateSet CandidateSet;      // Determine which overloaded operator we're dealing with.      static const OverloadedOperatorKind OverOps[] = { @@ -2854,6 +2937,7 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,      // Add the appropriate overloaded operators (C++ [over.match.oper])       // to the candidate set. +    OverloadCandidateSet CandidateSet;      Expr *Args[2] = { lhs, rhs };      AddOperatorCandidates(OverOp, S, Args, 2, CandidateSet); @@ -2893,7 +2977,6 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,                                         SourceLocation());          UsualUnaryConversions(FnExpr); -        Expr *Args[2] = { lhs, rhs };          return new CXXOperatorCallExpr(FnExpr, Args, 2, ResultTy, TokLoc);        } else {          // We matched a built-in operator. Convert the arguments, then @@ -2933,10 +3016,98 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,  }  // Unary Operators.  'Tok' is the token for the operator. -Action::ExprResult Sema::ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, -                                      ExprTy *input) { +Action::ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,  +                                      tok::TokenKind Op, ExprTy *input) {    Expr *Input = (Expr*)input;    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, &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 true; +        } else { +          // Convert the arguments. +          if (PerformCopyInitialization(Input,  +                                        FnDecl->getParamDecl(0)->getType(), +                                        "passing")) +            return true; +        } + +        // Determine the result type +        QualType ResultTy  +          = FnDecl->getType()->getAsFunctionType()->getResultType(); +        ResultTy = ResultTy.getNonReferenceType(); +         +        // Build the actual expression node. +        Expr *FnExpr = new DeclRefExpr(FnDecl, FnDecl->getType(),  +                                       SourceLocation()); +        UsualUnaryConversions(FnExpr); + +        return new CXXOperatorCallExpr(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 (PerformCopyInitialization(Input, Best->BuiltinTypes.ParamTypes[0], +                                      "passing")) +          return true; + +        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 true; +    } + +    // 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.     +  } + +    QualType resultType;    switch (Opc) {    default: @@ -2956,10 +3127,18 @@ Action::ExprResult Sema::ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,    case UnaryOperator::Minus:      UsualUnaryConversions(Input);      resultType = Input->getType(); -    if (!resultType->isArithmeticType())  // C99 6.5.3.3p1 -      return Diag(OpLoc, diag::err_typecheck_unary_expr,  -                  resultType.getAsString()); -    break; +    if (resultType->isArithmeticType()) // C99 6.5.3.3p1 +      break; +    else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6-7 +             resultType->isEnumeralType()) +      break; +    else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6 +             Opc == UnaryOperator::Plus && +             resultType->isPointerType()) +      break; + +    return Diag(OpLoc, diag::err_typecheck_unary_expr,  +                resultType.getAsString());    case UnaryOperator::Not: // bitwise complement      UsualUnaryConversions(Input);      resultType = Input->getType(); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index dbd21264f3b..869fcc93528 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1843,8 +1843,7 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,    }    // Add builtin overload candidates (C++ [over.built]). -  if (NumArgs == 2) -    return AddBuiltinBinaryOperatorCandidates(Op, Args, CandidateSet); +  AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet);  }  /// AddBuiltinCandidate - Add a candidate for a built-in @@ -2053,16 +2052,15 @@ void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,    }  } -/// AddBuiltinCandidates - Add the appropriate built-in operator -/// overloads to the candidate set (C++ [over.built]), based on the -/// operator @p Op and the arguments given. For example, if the -/// operator is a binary '+', this routine might add -///   "int operator+(int, int)" -/// to cover integer addition. +/// AddBuiltinOperatorCandidates - Add the appropriate built-in +/// operator overloads to the candidate set (C++ [over.built]), based +/// on the operator @p Op and the arguments given. For example, if the +/// operator is a binary '+', this routine might add "int +/// operator+(int, int)" to cover integer addition.  void -Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,  -                                         Expr **Args,  -                                         OverloadCandidateSet& CandidateSet) { +Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,  +                                   Expr **Args, unsigned NumArgs, +                                   OverloadCandidateSet& CandidateSet) {    // The set of "promoted arithmetic types", which are the arithmetic    // types are that preserved by promotion (C++ [over.built]p2). Note    // that the first few of these types are the promoted integral @@ -2090,10 +2088,11 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,    BuiltinCandidateTypeSet CandidateTypes(Context);    if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual ||        Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual || -      Op == OO_Plus || Op == OO_Minus || Op == OO_Equal || +      Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal ||        Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript || -      Op == OO_ArrowStar) { -    for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) +      Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus || +      (Op == OO_Star && NumArgs == 1)) { +    for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)        CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType());    } @@ -2104,24 +2103,184 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,      assert(false && "Expected an overloaded operator");      break; +  case OO_Star: // '*' is either unary or binary +    if (NumArgs == 1)  +      goto UnaryStar; +    else +      goto BinaryStar; +    break; + +  case OO_Plus: // '+' is either unary or binary +    if (NumArgs == 1) +      goto UnaryPlus; +    else +      goto BinaryPlus; +    break; + +  case OO_Minus: // '-' is either unary or binary +    if (NumArgs == 1) +      goto UnaryMinus; +    else +      goto BinaryMinus; +    break; + +  case OO_Amp: // '&' is either unary or binary +    if (NumArgs == 1) +      goto UnaryAmp; +    else +      goto BinaryAmp; + +  case OO_PlusPlus: +  case OO_MinusMinus: +    // C++ [over.built]p3: +    // +    //   For every pair (T, VQ), where T is an arithmetic type, and VQ +    //   is either volatile or empty, there exist candidate operator +    //   functions of the form +    // +    //       VQ T&      operator++(VQ T&); +    //       T          operator++(VQ T&, int); +    // +    // C++ [over.built]p4: +    // +    //   For every pair (T, VQ), where T is an arithmetic type other +    //   than bool, and VQ is either volatile or empty, there exist +    //   candidate operator functions of the form +    // +    //       VQ T&      operator--(VQ T&); +    //       T          operator--(VQ T&, int); +    for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1);  +         Arith < NumArithmeticTypes; ++Arith) { +      QualType ArithTy = ArithmeticTypes[Arith]; +      QualType ParamTypes[2]  +        = { Context.getReferenceType(ArithTy), Context.IntTy }; + +      // Non-volatile version. +      if (NumArgs == 1) +        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); +      else +        AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); + +      // Volatile version +      ParamTypes[0] = Context.getReferenceType(ArithTy.withVolatile()); +      if (NumArgs == 1) +        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); +      else +        AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); +    } + +    // C++ [over.built]p5: +    // +    //   For every pair (T, VQ), where T is a cv-qualified or +    //   cv-unqualified object type, and VQ is either volatile or +    //   empty, there exist candidate operator functions of the form +    // +    //       T*VQ&      operator++(T*VQ&); +    //       T*VQ&      operator--(T*VQ&); +    //       T*         operator++(T*VQ&, int); +    //       T*         operator--(T*VQ&, int); +    for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); +         Ptr != CandidateTypes.pointer_end(); ++Ptr) { +      // Skip pointer types that aren't pointers to object types. +      if (!(*Ptr)->getAsPointerType()->getPointeeType()->isObjectType()) +        continue; + +      QualType ParamTypes[2] = {  +        Context.getReferenceType(*Ptr), Context.IntTy  +      }; +       +      // Without volatile +      if (NumArgs == 1) +        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); +      else +        AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + +      if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { +        // With volatile +        ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile()); +        if (NumArgs == 1) +          AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); +        else +          AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); +      } +    } +    break; + +  UnaryStar: +    // C++ [over.built]p6: +    //   For every cv-qualified or cv-unqualified object type T, there +    //   exist candidate operator functions of the form +    // +    //       T&         operator*(T*); +    // +    // C++ [over.built]p7: +    //   For every function type T, there exist candidate operator +    //   functions of the form +    //       T&         operator*(T*); +    for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); +         Ptr != CandidateTypes.pointer_end(); ++Ptr) { +      QualType ParamTy = *Ptr; +      QualType PointeeTy = ParamTy->getAsPointerType()->getPointeeType(); +      AddBuiltinCandidate(Context.getReferenceType(PointeeTy),  +                          &ParamTy, Args, 1, CandidateSet); +    } +    break; + +  UnaryPlus: +    // C++ [over.built]p8: +    //   For every type T, there exist candidate operator functions of +    //   the form +    // +    //       T*         operator+(T*); +    for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); +         Ptr != CandidateTypes.pointer_end(); ++Ptr) { +      QualType ParamTy = *Ptr; +      AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet); +    } +     +    // Fall through + +  UnaryMinus: +    // C++ [over.built]p9: +    //  For every promoted arithmetic type T, there exist candidate +    //  operator functions of the form +    // +    //       T         operator+(T); +    //       T         operator-(T); +    for (unsigned Arith = FirstPromotedArithmeticType;  +         Arith < LastPromotedArithmeticType; ++Arith) { +      QualType ArithTy = ArithmeticTypes[Arith]; +      AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet); +    } +    break; + +  case OO_Tilde: +    // C++ [over.built]p10: +    //   For every promoted integral type T, there exist candidate +    //   operator functions of the form +    // +    //        T         operator~(T); +    for (unsigned Int = FirstPromotedIntegralType;  +         Int < LastPromotedIntegralType; ++Int) { +      QualType IntTy = ArithmeticTypes[Int]; +      AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet); +    } +    break; +    case OO_New:    case OO_Delete:    case OO_Array_New:    case OO_Array_Delete: -  case OO_Tilde: -  case OO_Exclaim: -  case OO_PlusPlus: -  case OO_MinusMinus: -  case OO_Arrow:    case OO_Call: -    assert(false && "Expected a binary operator"); +    assert(false && "Special operators don't use AddBuiltinOperatorCandidates");      break;    case OO_Comma: +  UnaryAmp: +  case OO_Arrow:      // C++ [over.match.oper]p3:      //   -- For the operator ',', the unary operator '&', or the      //      operator '->', the built-in candidates set is empty. -    // We don't check '&' or '->' here, since they are unary operators.      break;    case OO_Less: @@ -2156,8 +2315,8 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,      // Fall through.      isComparison = true; -  case OO_Plus: -  case OO_Minus: +  BinaryPlus: +  BinaryMinus:      if (!isComparison) {        // We didn't fall through, so we must have OO_Plus or OO_Minus. @@ -2201,8 +2360,8 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,      }      // Fall through -  case OO_Star:    case OO_Slash: +  BinaryStar:      // C++ [over.built]p12:      //      //   For every pair of promoted arithmetic types L and R, there @@ -2235,7 +2394,7 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,      break;    case OO_Percent: -  case OO_Amp: +  BinaryAmp:    case OO_Caret:    case OO_Pipe:    case OO_LessLess: @@ -2285,10 +2444,12 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,        ParamTypes[1] = *Enum;        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); -      // volatile T& operator=(volatile T&, T) -      ParamTypes[0] = Context.getReferenceType((*Enum).withVolatile()); -      ParamTypes[1] = *Enum; -      AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); +      if (!Context.getCanonicalType(*Enum).isVolatileQualified()) { +        // volatile T& operator=(volatile T&, T) +        ParamTypes[0] = Context.getReferenceType((*Enum).withVolatile()); +        ParamTypes[1] = *Enum; +        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); +      }      }      // Fall through. @@ -2319,9 +2480,11 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,        ParamTypes[0] = Context.getReferenceType(*Ptr);        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); -      // volatile version -      ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile()); -      AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); +      if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { +        // volatile version +        ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile()); +        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); +      }      }      // Fall through. @@ -2396,13 +2559,26 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,      }      break; +  case OO_Exclaim: { +    // C++ [over.operator]p23: +    // +    //   There also exist candidate operator functions of the form +    // +    //        bool        operator!(bool);             +    //        bool        operator&&(bool, bool);     [BELOW] +    //        bool        operator||(bool, bool);     [BELOW] +    QualType ParamTy = Context.BoolTy; +    AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet); +    break; +  } +    case OO_AmpAmp:    case OO_PipePipe: {      // C++ [over.operator]p23:      //      //   There also exist candidate operator functions of the form      // -    //        bool        operator!(bool);            [In Unary version] +    //        bool        operator!(bool);            [ABOVE]      //        bool        operator&&(bool, bool);      //        bool        operator||(bool, bool);      QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy }; diff --git a/clang/test/SemaCXX/overloaded-builtin-operators.cpp b/clang/test/SemaCXX/overloaded-builtin-operators.cpp index af328da212b..29d721c45bb 100644 --- a/clang/test/SemaCXX/overloaded-builtin-operators.cpp +++ b/clang/test/SemaCXX/overloaded-builtin-operators.cpp @@ -25,6 +25,14 @@ yes& islong(unsigned long); // FIXME: shouldn't be needed  no& islong(int);  void f(Short s, Long l, Enum1 e1, Enum2 e2) { +  // C++ [over.built]p8 +  int i1 = +e1; +  int i2 = -e2; + +  // C++  [over.built]p10: +  int i3 = ~s; +  bool b1 = !s; +    // C++ [over.built]p12    (void)static_cast<yes&>(islong(s + l));    (void)static_cast<no&>(islong(s + s)); @@ -46,6 +54,12 @@ struct LongRef {  };  void g(ShortRef sr, LongRef lr) { +  // C++ [over.built]p3 +  short s1 = sr++; + +  // C++ [over.built]p3 +  long l1 = lr--; +    // C++ [over.built]p18    short& sr1 = (sr *= lr);    volatile long& lr1 = (lr *= sr); @@ -65,7 +79,16 @@ struct ConstIntPtr {    operator int const *();  }; -void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr) { +struct VolatileIntPtrRef { +  operator int volatile *&(); +}; + +struct ConstIntPtrRef { +  operator int const *&(); +}; + +void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr, +                    VolatileIntPtrRef vipr, ConstIntPtrRef cipr) {  #if 0    // FIXME: Enable these tests once we have operator overloading for    // operator[]. @@ -76,4 +99,19 @@ void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr) {  #endif    bool b1 = (vip == cip);    long p1 = vip - cip; + +  // C++ [over.built]p5: +  int volatile *vip1 = vipr++; +  int const *cip1 = cipr++; +  int volatile *&vipr1 = ++vipr; +  int const *&cipr1 = --cipr; + +  // C++ [over.built]p6: +  int volatile &ivr = *vip; + +  // C++ [over.built]p8: +  int volatile *vip2 = +vip; +  int i1 = +sr; +  int i2 = -sr;  } + diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp index c540c2dafcb..29486568185 100644 --- a/clang/test/SemaCXX/overloaded-operator.cpp +++ b/clang/test/SemaCXX/overloaded-operator.cpp @@ -69,3 +69,31 @@ void enum_test(Enum1 enum1, Enum2 enum2, E1 e1, E2 e2) {    float &f3 = (e1 == enum2);     float &f4 = (enum1 == enum2);  // expected-error{{non-const reference to type 'float' cannot be initialized with a temporary of type '_Bool'}}  } + + +struct PostInc { +  PostInc operator++(int); +  PostInc& operator++(); +}; + +struct PostDec { +  PostDec operator--(int); +  PostDec& operator--(); +}; + +void incdec_test(PostInc pi, PostDec pd) { +  const PostInc& pi1 = pi++; +  const PostDec& pd1 = pd--; +  PostInc &pi2 = ++pi; +  PostDec &pd2 = --pd; +} + +struct SmartPtr { +  int& operator*(); +  // FIXME: spurious error:  long& operator*() const; +}; + +void test_smartptr(SmartPtr ptr, const SmartPtr cptr) { +  int &ir = *ptr; +  // FIXME: reinstate long &lr = *cptr; +} diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index c8b8d57ef0c..7c51fb387d0 100644 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -826,8 +826,8 @@ welcome!</p>  <tr>
    <td>      13.3.1.2 [over.match.oper]</td>
    <td class="complete" align="center">✓</td>  
 -  <td class="broken" align="center"></td>
 -  <td class="broken" align="center"></td>
 +  <td class="medium" align="center"></td>
 +  <td class="medium" align="center"></td>
    <td class="broken" align="center"></td>  
    <td></td>
  </tr>
 @@ -943,27 +943,27 @@ welcome!</p>    <td class="advanced" align="center"></td>
    <td class="medium" align="center"></td>
    <td class="broken" align="center"></td>  
 -  <td>Most overloaded operators can only be called with function syntax, e.g., <code>operator+(x)</code>.</td>
 +  <td>Some overloaded operators can only be called with function syntax, e.g., <code>operator[](x)</code>.</td>
  </tr>
  <tr>
    <td>    13.5.1 [over.unary]</td>
 -  <td class="advanced" align="center"></td>  
 +  <td class="na" align="center">N/A</td>  
 +  <td class="advanced" align="center"></td>
    <td class="advanced" align="center"></td>
 -  <td class="basic" align="center"></td>
    <td class="broken" align="center"></td>  
    <td></td>
  </tr>
  <tr>
    <td>    13.5.2 [over.binary]</td>
 -  <td class="advanced" align="center"></td>  
 +  <td class="na" align="center">N/A</td>  
 +  <td class="advanced" align="center"></td>
    <td class="advanced" align="center"></td>
 -  <td class="medium" align="center"></td>
    <td class="broken" align="center"></td>  
    <td></td>
  </tr>
  <tr>
    <td>    13.5.3 [over.ass]</td>
 -  <td class="advanced" align="center"></td>  
 +  <td class="na" align="center">N/A</td>  
    <td class="advanced" align="center"></td>
    <td class="basic" align="center"></td>
    <td class="broken" align="center"></td>  
 @@ -971,7 +971,7 @@ welcome!</p>  </tr>
  <tr>
    <td>    13.5.4 [over.call]</td>
 -  <td class="advanced" align="center"></td>  
 +  <td class="na" align="center">N/A</td>  
    <td class="advanced" align="center"></td>
    <td class="basic" align="center"></td>
    <td class="broken" align="center"></td>  
 @@ -979,7 +979,7 @@ welcome!</p>  </tr>
  <tr>
    <td>    13.5.5 [over.sub]</td>
 -  <td class="advanced" align="center"></td>  
 +  <td class="na" align="center">N/A</td>  
    <td class="advanced" align="center"></td>
    <td class="basic" align="center"></td>
    <td class="broken" align="center"></td>  
 @@ -987,21 +987,29 @@ welcome!</p>  </tr>
  <tr>
    <td>    13.5.6 [over.ref]</td>
 -  <td class="advanced" align="center"></td>  
 +  <td class="na" align="center">N/A</td>  
 +  <td class="advanced" align="center"></td>
    <td class="advanced" align="center"></td>
 -  <td class="basic" align="center"></td>
    <td class="broken" align="center"></td>  
    <td></td>
  </tr>
  <tr>
    <td>    13.5.7 [over.inc]</td>
 -  <td class="advanced" align="center"></td>  
 +  <td class="na" align="center">N/A</td>  
 +  <td class="advanced" align="center"></td>
    <td class="advanced" align="center"></td>
 -  <td class="basic" align="center"></td>
    <td class="broken" align="center"></td>  
    <td></td>
  </tr>
 -<tr><td>  13.6 [over.built]</td><td></td><td></td><td></td><td></td><td></td></tr>
 +<tr>
 +  <td>  13.6 [over.built]</td>
 +  <td class="na" align="center">N/A</td>  
 +  <td class="advanced" align="center"></td>
 +  <td class="medium" align="center"></td>
 +  <td class="broken" align="center"></td>  
 +  <td>Missing pointer-to-member versions (p11, p16) and support for
 +  the ternary operator (p24, p25).</td>
 +</tr>
  <tr><td>14 [temp]</td><td></td><td></td><td></td><td></td><td></td></tr>
  <tr><td>  14.1 [temp.param]</td><td></td><td></td><td></td><td></td><td></td></tr>
  <tr><td>  14.2 [temp.names]</td><td></td><td></td><td></td><td></td><td></td></tr>
  | 

