diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -7086,6 +7086,13 @@ /// Determines whether this is a type for which one can define /// an overloaded operator. inline bool Type::isOverloadableType() const { + // (16.5.6): An operator function [...] parameter whose type is a class, + // a reference to a class, an enumeration, or a reference to an + // enumeration. + if (isPointerType()) { + // If the type is a pointer, it cannot be overloaded. + return false; + } return isDependentType() || isRecordType() || isEnumeralType(); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -644,8 +644,7 @@ // expressions of certain types in C++. if (getLangOpts().CPlusPlus && (E->getType() == Context.OverloadTy || - T->isDependentType() || - T->isRecordType())) + (T->isDependentType() && !T->isPointerType()) || T->isRecordType())) return E; // The C standard is actually really unclear on this point, and @@ -10545,6 +10544,8 @@ if (!ResType->isAnyPointerType()) return true; QualType PointeeTy = ResType->getPointeeType(); + if (PointeeTy->isDependentType()) + return true; if (PointeeTy->isVoidType()) { diagnoseArithmeticOnVoidPointer(S, Loc, Operand); return !S.getLangOpts().CPlusPlus; @@ -10611,9 +10612,11 @@ return !S.getLangOpts().CPlusPlus; } - if (isLHSPointer && checkArithmeticIncompletePointerType(S, Loc, LHSExpr)) + if (isLHSPointer && !LHSPointeeTy->isDependentType() && + checkArithmeticIncompletePointerType(S, Loc, LHSExpr)) return false; - if (isRHSPointer && checkArithmeticIncompletePointerType(S, Loc, RHSExpr)) + if (isRHSPointer && !RHSPointeeTy->isDependentType() && + checkArithmeticIncompletePointerType(S, Loc, RHSExpr)) return false; return true; @@ -10897,7 +10900,9 @@ if (getLangOpts().CPlusPlus) { // Pointee types must be the same: C++ [expr.add] - if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) { + // If pointees are dependent types, we defer this to later. + if (!lpointee->isDependentType() && !rpointee->isDependentType() && + !Context.hasSameUnqualifiedType(lpointee, rpointee)) { diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get()); } } else { @@ -10928,7 +10933,8 @@ // The pointee type may have zero size. As an extension, a structure or // union may have zero size or an array may have zero length. In this // case subtraction does not make sense. - if (!rpointee->isVoidType() && !rpointee->isFunctionType()) { + if (!rpointee->isDependentType() && !rpointee->isVoidType() && + !rpointee->isFunctionType()) { CharUnits ElementSize = Context.getTypeSizeInChars(rpointee); if (ElementSize.isZero()) { Diag(Loc,diag::warn_sub_ptr_zero_size_types) @@ -11855,6 +11861,9 @@ auto computeResultTy = [&]() { if (Opc != BO_Cmp) return Context.getLogicalOperationType(); + if (LHS.get()->getType()->isDependentType() || + RHS.get()->getType()->isDependentType()) + return QualType(Context.DependentTy); assert(getLangOpts().CPlusPlus); assert(Context.hasSameType(LHS.get()->getType(), RHS.get()->getType())); @@ -13404,7 +13413,7 @@ ExprObjectKind &OK, SourceLocation OpLoc, bool IsInc, bool IsPrefix) { - if (Op->isTypeDependent()) + if (Op->isTypeDependent() && !Op->getType()->isPointerType()) return S.Context.DependentTy; QualType ResType = Op->getType(); @@ -13816,9 +13825,6 @@ /// CheckIndirectionOperand - Type check unary indirection (prefix '*'). static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, SourceLocation OpLoc) { - if (Op->isTypeDependent()) - return S.Context.DependentTy; - ExprResult ConvResult = S.UsualUnaryConversions(Op); if (ConvResult.isInvalid()) return QualType(); @@ -13832,14 +13838,14 @@ Op->getSourceRange()); } - if (const PointerType *PT = OpTy->getAs()) - { + if (const PointerType *PT = OpTy->getAs()) { Result = PT->getPointeeType(); - } - else if (const ObjCObjectPointerType *OPT = - OpTy->getAs()) + } else if (const ObjCObjectPointerType *OPT = + OpTy->getAs()) { Result = OPT->getPointeeType(); - else { + } else if (Op->isTypeDependent()) { + return S.Context.DependentTy; + } else { ExprResult PR = S.CheckPlaceholderExpr(Op); if (PR.isInvalid()) return QualType(); if (PR.get() != Op) @@ -14177,7 +14183,11 @@ switch (Opc) { case BO_Assign: - ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); + if (getLangOpts().CPlusPlus && + (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())) + ResultTy = LHSExpr->getType(); + else + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() != OK_ObjCProperty) { VK = LHS.get()->getValueKind(); @@ -14253,7 +14263,8 @@ case BO_Cmp: ConvertHalfVec = true; ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc); - assert(ResultTy.isNull() || ResultTy->getAsCXXRecordDecl()); + assert(ResultTy.isNull() || ResultTy->isDependentType() || + ResultTy->getAsCXXRecordDecl()); break; case BO_And: checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); @@ -14738,21 +14749,15 @@ } if (getLangOpts().CPlusPlus) { - // If either expression is type-dependent, always build an - // overloaded op. - if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) - return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); - - // Otherwise, build an overloaded op if either expression has an + // Build an overloaded op if either expression has an // overloadable type. if (LHSExpr->getType()->isOverloadableType() || RHSExpr->getType()->isOverloadableType()) return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); } - if (getLangOpts().RecoveryAST && + if (!getLangOpts().CPlusPlus && getLangOpts().RecoveryAST && (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())) { - assert(!getLangOpts().CPlusPlus); assert((LHSExpr->containsErrors() || RHSExpr->containsErrors()) && "Should only occur in error-recovery path."); if (BinaryOperator::isCompoundAssignmentOp(Opc)) @@ -14869,8 +14874,6 @@ if (ConvertHalfVec) Input = convertVector(Input.get(), Context.FloatTy, *this); resultType = Input.get()->getType(); - if (resultType->isDependentType()) - break; if (resultType->isArithmeticType()) // C99 6.5.3.3p1 break; else if (resultType->isVectorType() && @@ -14880,8 +14883,10 @@ VectorType::AltiVecBool)) break; else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6 - Opc == UO_Plus && - resultType->isPointerType()) + resultType->isPointerType()) { + if (Opc == UO_Plus) + break; + } else if (resultType->isDependentType()) break; return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) @@ -14892,27 +14897,26 @@ if (Input.isInvalid()) return ExprError(); resultType = Input.get()->getType(); - if (resultType->isDependentType()) - break; // C99 6.5.3.3p1. We allow complex int and float as a GCC extension. - if (resultType->isComplexType() || resultType->isComplexIntegerType()) + if (resultType->isComplexType() || resultType->isComplexIntegerType()) { // C99 does not support '~' for complex conjugation. Diag(OpLoc, diag::ext_integer_complement_complex) << resultType << Input.get()->getSourceRange(); - else if (resultType->hasIntegerRepresentation()) break; - else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) { + } else if (resultType->hasIntegerRepresentation()) { + break; + } else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) { // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate // on vector float types. QualType T = resultType->castAs()->getElementType(); - if (!T->isIntegerType()) - return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) - << resultType << Input.get()->getSourceRange()); - } else { - return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + if (T->isIntegerType()) + break; + } else if (resultType->isPointerType()) { + // Bitwise complement of pointers is invalid. + } else if (resultType->isDependentType()) + break; + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); - } - break; case UO_LNot: // logical negation // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5). @@ -14926,8 +14930,6 @@ resultType = Context.FloatTy; } - if (resultType->isDependentType()) - break; if (resultType->isScalarType() && !isScopedEnumerationType(resultType)) { // C99 6.5.3.3p1: ok, fallthrough; if (Context.getLangOpts().CPlusPlus) { @@ -14965,6 +14967,8 @@ // Vector logical not returns the signed variant of the operand type. resultType = GetSignedVectorType(resultType); break; + } else if (resultType->isDependentType()) { + break; } else { return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6605,6 +6605,14 @@ assert(!T1->isNullPtrType() && !T2->isNullPtrType() && "nullptr_t should be a null pointer constant"); + if (T1->getPointeeType()->isDependentType() || + T2->getPointeeType()->isDependentType()) { + // We can't do the conversion now. + // FIXME: We know that the composite pointer type is a pointer type, return + // pointer to dependant type. + return Context.DependentTy; + } + struct Step { enum Kind { Pointer, ObjCPointer, MemberPointer, Array } K; // Qualifiers to apply under the step kind. diff --git a/clang/test/AST/ast-dump-expr-json.cpp b/clang/test/AST/ast-dump-expr-json.cpp --- a/clang/test/AST/ast-dump-expr-json.cpp +++ b/clang/test/AST/ast-dump-expr-json.cpp @@ -4267,9 +4267,9 @@ // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "" +// CHECK-NEXT: "qualType": "V" // CHECK-NEXT: }, -// CHECK-NEXT: "valueCategory": "prvalue", +// CHECK-NEXT: "valueCategory": "lvalue", // CHECK-NEXT: "isPostfix": false, // CHECK-NEXT: "opcode": "*", // CHECK-NEXT: "canOverflow": false, diff --git a/clang/test/AST/ast-dump-expr.cpp b/clang/test/AST/ast-dump-expr.cpp --- a/clang/test/AST/ast-dump-expr.cpp +++ b/clang/test/AST/ast-dump-expr.cpp @@ -281,7 +281,7 @@ // CHECK-NEXT: CompoundStmt // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} col:8 implicit 'V' // CHECK-NEXT: ParenListExpr 0x{{[^ ]*}} 'NULL TYPE' - // CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} '' prefix '*' cannot overflow + // CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} 'V' lvalue prefix '*' cannot overflow // CHECK-NEXT: CXXThisExpr 0x{{[^ ]*}} 'V *' this } }; diff --git a/clang/test/AST/ast-dump-lambda.cpp b/clang/test/AST/ast-dump-lambda.cpp --- a/clang/test/AST/ast-dump-lambda.cpp +++ b/clang/test/AST/ast-dump-lambda.cpp @@ -81,7 +81,7 @@ // CHECK-NEXT: | | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | `-FieldDecl {{.*}} col:8{{( imported)?}} implicit 'V' // CHECK-NEXT: | |-ParenListExpr {{.*}} 'NULL TYPE' -// CHECK-NEXT: | | `-UnaryOperator {{.*}} '' prefix '*' cannot overflow +// CHECK-NEXT: | | `-UnaryOperator {{.*}} 'V' lvalue prefix '*' cannot overflow // CHECK-NEXT: | | `-CXXThisExpr {{.*}} 'V *' this // CHECK-NEXT: | `-CompoundStmt {{.*}} // CHECK-NEXT: |-DeclStmt {{.*}} diff --git a/clang/test/CXX/over/over.built/ast-20.cpp b/clang/test/CXX/over/over.built/ast-20.cpp --- a/clang/test/CXX/over/over.built/ast-20.cpp +++ b/clang/test/CXX/over/over.built/ast-20.cpp @@ -13,7 +13,9 @@ template auto Test(T* pt, U* pu) { // CHECK: BinaryOperator {{.*}} '' '<=>' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'U *' // CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *' (void)(pt <=> pu); diff --git a/clang/test/CXX/over/over.built/ast.cpp b/clang/test/CXX/over/over.built/ast.cpp --- a/clang/test/CXX/over/over.built/ast.cpp +++ b/clang/test/CXX/over/over.built/ast.cpp @@ -4,38 +4,46 @@ template auto Test(T* pt, U* pu) { - // CHECK: UnaryOperator {{.*}} '' prefix '*' + // CHECK: UnaryOperator {{.*}} 'T' lvalue prefix '*' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' (void)*pt; - // CHECK: UnaryOperator {{.*}} '' prefix '++' + // CHECK: UnaryOperator {{.*}} 'T *' lvalue prefix '++' // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' (void)(++pt); - // CHECK: UnaryOperator {{.*}} '' prefix '+' + // CHECK: UnaryOperator {{.*}} 'T *' prefix '+' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' (void)(+pt); - // CHECK: BinaryOperator {{.*}} '' '+' + // CHECK: BinaryOperator {{.*}} 'T *' '+' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' // CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3 (void)(pt + 3); - // CHECK: BinaryOperator {{.*}} '' '-' + // CHECK: BinaryOperator {{.*}} 'long' '-' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' (void)(pt - pt); - // CHECK: BinaryOperator {{.*}} '' '-' + // CHECK: BinaryOperator {{.*}} 'long' '-' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'U *' // CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *' (void)(pt - pu); - // CHECK: BinaryOperator {{.*}} '' '==' + // CHECK: BinaryOperator {{.*}} 'bool' '==' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'U *' // CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *' (void)(pt == pu); } - diff --git a/clang/test/CXX/over/over.built/p10.cpp b/clang/test/CXX/over/over.built/p10.cpp --- a/clang/test/CXX/over/over.built/p10.cpp +++ b/clang/test/CXX/over/over.built/p10.cpp @@ -3,7 +3,7 @@ struct A{}; template -void f(int i, float f, bool b, char c, int* pi, A* pa, T* pt) { +void f(int i, float f, bool b, char c, int* pi, A* pa, T* pt, T t) { (void)+i; (void)-i; (void)+f; @@ -12,9 +12,11 @@ (void)-b; (void)+c; (void)-c; + (void)+t; + (void)-t; (void)-pi; // expected-error {{invalid argument type}} (void)-pa; // expected-error {{invalid argument type}} - (void)-pt; // FIXME: we should be able to give an error here. + (void)-pt; // expected-error {{invalid argument type}} } diff --git a/clang/test/CXX/over/over.built/p11.cpp b/clang/test/CXX/over/over.built/p11.cpp --- a/clang/test/CXX/over/over.built/p11.cpp +++ b/clang/test/CXX/over/over.built/p11.cpp @@ -1,12 +1,13 @@ // RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare template -void f(int i, float f, bool b, char c, int* pi, T* pt) { +void f(int i, float f, bool b, char c, int* pi, T* pt, T t) { (void)~i; (void)~f; // expected-error {{invalid argument type}} (void)~b; (void)~c; (void)~pi; // expected-error {{invalid argument type}} - (void)~pt; // FIXME: we should be able to give an error here. + (void)~pt; // expected-error {{invalid argument type}} + (void)~t; } diff --git a/clang/test/CXX/over/over.built/p13.cpp b/clang/test/CXX/over/over.built/p13.cpp --- a/clang/test/CXX/over/over.built/p13.cpp +++ b/clang/test/CXX/over/over.built/p13.cpp @@ -1,40 +1,45 @@ // RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare template -void f(int i, float f, bool b, char c, int* pi, T* pt) { +void f(int i, float f, bool b, char c, int* pi, T* pt, T t) { (void)(i*i); (void)(i*f); (void)(i*b); (void)(i*c); (void)(i*pi); // expected-error {{invalid operands to binary expression}} - (void)(i*pt); // FIXME + (void)(i*pt); // expected-error {{invalid operands to binary expression}} + (void)(i*t); (void)(i/i); (void)(i/f); (void)(i/b); (void)(i/c); (void)(i/pi); // expected-error {{invalid operands to binary expression}} - (void)(i/pt); // FIXME + (void)(i/pt); // expected-error {{invalid operands to binary expression}} + (void)(i/t); (void)(i-i); (void)(i-f); (void)(i-b); (void)(i-c); (void)(i-pi); // expected-error {{invalid operands to binary expression}} - (void)(i-pt); // FIXME + (void)(i-pt); // expected-error {{invalid operands to binary expression}} + (void)(i-t); (void)(i -void f(int* pi, T* pt) { +void f(int* pi, T* pt, T t) { (void)(pi+3); (void)(3+pi); (void)(pi-3); @@ -13,5 +13,11 @@ (void)(pt-3); (void)(pt[3]); (void)(3[pt]); + + (void)(t+3); + (void)(3+t); + (void)(t-3); + (void)(t[3]); + (void)(3[t]); } // expected-no-diagnostics diff --git a/clang/test/CXX/over/over.built/p18.cpp b/clang/test/CXX/over/over.built/p18.cpp --- a/clang/test/CXX/over/over.built/p18.cpp +++ b/clang/test/CXX/over/over.built/p18.cpp @@ -6,77 +6,77 @@ (void)(f % 3); // expected-error {{invalid operands}} (void)(b % 3); (void)(pi % 3); // expected-error {{invalid operands}} - (void)(pt % 3); // FIXME + (void)(pt % 3); // expected-error {{invalid operands}} (void)(t % 3); (void)(3 % i); (void)(3 % f); // expected-error {{invalid operands}} (void)(3 % b); (void)(3 % pi); // expected-error {{invalid operands}} - (void)(3 % pt); // FIXME + (void)(3 % pt); // expected-error {{invalid operands}} (void)(3 % t); (void)(i & 3); (void)(f & 3); // expected-error {{invalid operands}} (void)(b & 3); (void)(pi & 3); // expected-error {{invalid operands}} - (void)(pt & 3); // FIXME + (void)(pt & 3); // expected-error {{invalid operands}} (void)(t & 3); (void)(3 & i); (void)(3 & f); // expected-error {{invalid operands}} (void)(3 & b); (void)(3 & pi); // expected-error {{invalid operands}} - (void)(3 & pt); // FIXME + (void)(3 & pt); // expected-error {{invalid operands}} (void)(3 & t); (void)(i ^ 3); (void)(f ^ 3); // expected-error {{invalid operands}} (void)(b ^ 3); (void)(pi ^ 3); // expected-error {{invalid operands}} - (void)(pt ^ 3); // FIXME + (void)(pt ^ 3); // expected-error {{invalid operands}} (void)(t ^ 3); (void)(3 ^ i); (void)(3 ^ f); // expected-error {{invalid operands}} (void)(3 ^ b); (void)(3 ^ pi); // expected-error {{invalid operands}} - (void)(3 ^ pt); // FIXME + (void)(3 ^ pt); // expected-error {{invalid operands}} (void)(3 ^ t); (void)(i | 3); (void)(f | 3); // expected-error {{invalid operands}} (void)(b | 3); (void)(pi | 3); // expected-error {{invalid operands}} - (void)(pt | 3); // FIXME + (void)(pt | 3); // expected-error {{invalid operands}} (void)(t | 3); (void)(3 | i); (void)(3 | f); // expected-error {{invalid operands}} (void)(3 | b); (void)(3 | pi); // expected-error {{invalid operands}} - (void)(3 | pt); // FIXME + (void)(3 | pt); // expected-error {{invalid operands}} (void)(3 | t); (void)(i << 3); (void)(f << 3); // expected-error {{invalid operands}} (void)(b << 3); (void)(pi << 3); // expected-error {{invalid operands}} - (void)(pt << 3); // FIXME + (void)(pt << 3); // expected-error {{invalid operands}} (void)(t << 3); (void)(3 << i); (void)(3 << f); // expected-error {{invalid operands}} (void)(3 << b); (void)(3 << pi); // expected-error {{invalid operands}} - (void)(3 << pt); // FIXME + (void)(3 << pt); // expected-error {{invalid operands}} (void)(3 << t); (void)(i >> 3); (void)(f >> 3); // expected-error {{invalid operands}} (void)(b >> 3); (void)(pi >> 3); // expected-error {{invalid operands}} - (void)(pt >> 3); // FIXME + (void)(pt >> 3); // expected-error {{invalid operands}} (void)(t >> 3); (void)(3 >> i); (void)(3 >> f); // expected-error {{invalid operands}} (void)(3 >> b); (void)(3 >> pi); // expected-error {{invalid operands}} - (void)(3 >> pt); // FIXME + (void)(3 >> pt); // expected-error {{invalid operands}} (void)(3 >> t); } diff --git a/clang/test/CXX/over/over.built/p19.cpp b/clang/test/CXX/over/over.built/p19.cpp --- a/clang/test/CXX/over/over.built/p19.cpp +++ b/clang/test/CXX/over/over.built/p19.cpp @@ -9,7 +9,7 @@ i -= i; i -= f; i -= pi; // expected-error {{invalid operands}} - i -= pt; // FIXME + i -= pt; // expected-error {{invalid operands}} i -= t; f = f; @@ -19,6 +19,6 @@ f -= f; f -= i; f -= pi; // expected-error {{invalid operands}} - f -= pt; // FIXME + f -= pt; // expected-error {{invalid operands}} f -= t; } diff --git a/clang/test/CXX/over/over.built/p20.cpp b/clang/test/CXX/over/over.built/p20.cpp --- a/clang/test/CXX/over/over.built/p20.cpp +++ b/clang/test/CXX/over/over.built/p20.cpp @@ -1,12 +1,15 @@ // RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare -template -void f(int* pi, float* pf, T* pt, U* pu, T t) { +template +void f(int i, int* pi, T* pt, T t) { + i = i; pi = pi; - pi = pf; // expected-error {{incompatible pointer types}} - pi = pt; - pu = pi; - pu = pt; - pi = t; - pu = t; + pt = pt; + i = pi; // expected-error {{incompatible pointer to integer}} + i = pt; // FIXME + pi = i; // expected-error {{incompatible integer to pointer}} + pt = i; // FIXME + pi = pt; // Checked during instantiation. + pi = t; // Checked during instantiation. } + diff --git a/clang/test/CXX/over/over.built/p22.cpp b/clang/test/CXX/over/over.built/p22.cpp --- a/clang/test/CXX/over/over.built/p22.cpp +++ b/clang/test/CXX/over/over.built/p22.cpp @@ -6,7 +6,7 @@ pi += pi; // expected-error {{invalid operands}} pt += 3; pi += t; - pi += pt; // FIXME - pt += pi; //FIXME - pt += pt; //FIXME + pi += pt; // expected-error {{invalid operands}} + pt += pi; // expected-error {{invalid operands}} + pt += pt; // expected-error {{invalid operands}} } diff --git a/clang/test/CXX/over/over.built/p23.cpp b/clang/test/CXX/over/over.built/p23.cpp --- a/clang/test/CXX/over/over.built/p23.cpp +++ b/clang/test/CXX/over/over.built/p23.cpp @@ -6,41 +6,41 @@ f %= 3; // expected-error {{invalid operands}} b %= 3; pi %= 3; // expected-error {{invalid operands}} - pt %= 3; // FIXME + pt %= 3; // expected-error {{invalid operands}} t %= 3; i &= 3; f &= 3; // expected-error {{invalid operands}} b &= 3; pi &= 3; // expected-error {{invalid operands}} - pt &= 3; // FIXME + pt &= 3; // expected-error {{invalid operands}} t &= 3; i ^= 3; f ^= 3; // expected-error {{invalid operands}} b ^= 3; pi ^= 3; // expected-error {{invalid operands}} - pt ^= 3; // FIXME + pt ^= 3; // expected-error {{invalid operands}} t ^= 3; i |= 3; f |= 3; // expected-error {{invalid operands}} b |= 3; pi |= 3; // expected-error {{invalid operands}} - pt |= 3; // FIXME + pt |= 3; // expected-error {{invalid operands}} t |= 3; i <<= 3; f <<= 3; // expected-error {{invalid operands}} b <<= 3; pi <<= 3; // expected-error {{invalid operands}} - pt <<= 3; // FIXME + pt <<= 3; // expected-error {{invalid operands}} t <<= 3; i >>= 3; f >>= 3; // expected-error {{invalid operands}} b >>= 3; pi >>= 3; // expected-error {{invalid operands}} - pt >>= 3; // FIXME + pt >>= 3; // expected-error {{invalid operands}} t >>= 3; } diff --git a/clang/test/CXX/over/over.built/p4.cpp b/clang/test/CXX/over/over.built/p4.cpp --- a/clang/test/CXX/over/over.built/p4.cpp +++ b/clang/test/CXX/over/over.built/p4.cpp @@ -1,10 +1,14 @@ // RUN: %clang_cc1 -std=c++17 -verify %s -Wno-tautological-compare -void f(int i, bool b) { +template +void f(int i, bool b, T t) { (void)++i; (void)i++; (void)++b; // expected-error {{ISO C++17 does not allow incrementing expression of type bool}} (void)b++; // expected-error {{ISO C++17 does not allow incrementing expression of type bool}} + + (void)++t; + (void)t++; } diff --git a/clang/test/CXX/over/over.built/p5.cpp b/clang/test/CXX/over/over.built/p5.cpp --- a/clang/test/CXX/over/over.built/p5.cpp +++ b/clang/test/CXX/over/over.built/p5.cpp @@ -1,10 +1,14 @@ // RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare -void f(int i, bool b) { +template +void f(int i, bool b, T t) { (void)--i; (void)i--; (void)--b; // expected-error {{cannot decrement expression of type bool}} (void)b--; // expected-error {{cannot decrement expression of type bool}} + + (void)--t; + (void)t--; } diff --git a/clang/test/CXX/over/over.built/p7.cpp b/clang/test/CXX/over/over.built/p7.cpp --- a/clang/test/CXX/over/over.built/p7.cpp +++ b/clang/test/CXX/over/over.built/p7.cpp @@ -3,10 +3,11 @@ struct A{}; template -void f(int* pi, A* pa, T* pt) { +void f(int* pi, A* pa, T* pt, T t) { (void)*pi; (void)*pa; (void)*pt; + (void)*t; // `T` might be a `U*`. } // expected-no-diagnostics diff --git a/clang/test/CXX/over/over.built/spaceship.cpp b/clang/test/CXX/over/over.built/spaceship.cpp --- a/clang/test/CXX/over/over.built/spaceship.cpp +++ b/clang/test/CXX/over/over.built/spaceship.cpp @@ -11,11 +11,10 @@ } template -void f(int i, float f, int* pi, T* pt, T t) { +void f(int i, int* pi, T* pt, T t) { (void)(i <=> i); - (void)(i <=> f); // expected-error {{invalid argument type}} - (void)(i <=> pi); // expected-error {{invalid argument type}} - (void)(i <=> pt); // expected-error {{invalid argument type}} + (void)(i <=> pi); // expected-error {{comparison between pointer and integer}} + (void)(i <=> pt); // expected-error {{comparison between pointer and integer}} (void)(pi <=> pt); (void)(pi <=> t); } diff --git a/clang/test/Frontend/noderef_templates.cpp b/clang/test/Frontend/noderef_templates.cpp --- a/clang/test/Frontend/noderef_templates.cpp +++ b/clang/test/Frontend/noderef_templates.cpp @@ -3,8 +3,8 @@ #define NODEREF __attribute__((noderef)) template -int func(T NODEREF *a) { // expected-note 2 {{a declared here}} - return *a + 1; // expected-warning 2 {{dereferencing a; was declared with a 'noderef' type}} +int func(T NODEREF *a) { // expected-note 3 {{a declared here}} + return *a + 1; // expected-warning 3 {{dereferencing a; was declared with a 'noderef' type}} } void func() { diff --git a/clang/test/SemaTemplate/dependent-type-identity.cpp b/clang/test/SemaTemplate/dependent-type-identity.cpp --- a/clang/test/SemaTemplate/dependent-type-identity.cpp +++ b/clang/test/SemaTemplate/dependent-type-identity.cpp @@ -69,6 +69,16 @@ void f8(typename N::X2::template apply *); void f8(typename N::X2::template apply *); void f8(typename ::Nalias::X2::template apply *); // expected-error{{redeclar}} + + // (17.4.2): If an expression e is type-dependent (17.6.2.2), decltype(e) + // denotes a unique dependent type. Two such decltype-specifiers refer to the + // same type only if their expressions are equivalent (17.5.6.1) + T* a; + T* b; + using V = decltype(*a); + void f9(decltype(*a)); // expected-note{{previous}} + void f9(decltype(*b)); + void f9(V); // expected-error{{redeclar}} }; namespace PR6851 {