CanQualType FloatTy, DoubleTy, LongDoubleTy;
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
- CanQualType OverloadTy;
- CanQualType DependentTy;
+ CanQualType OverloadTy, DependentTy, UnknownAnyTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t,
case CK_MemberPointerToBoolean:
case CK_FloatingComplexToBoolean:
case CK_IntegralComplexToBoolean:
+ case CK_ResolveUnknownAnyType:
case CK_LValueBitCast: // -> bool&
case CK_UserDefinedConversion: // operator bool()
assert(path_empty() && "Cast kind should not have a base path!");
/// \brief Converts from an integral complex to a floating complex.
/// _Complex unsigned -> _Complex float
- CK_IntegralComplexToFloatingComplex
+ CK_IntegralComplexToFloatingComplex,
+
+ /// \brief Assign an unknown-any declaration a type.
+ CK_ResolveUnknownAnyType
};
#define CK_Invalid ((CastKind) -1)
/// theoretically deducible.
Dependent,
- Overload, // This represents the type of an overloaded function declaration.
+ /// The type of an unresolved overload set.
+ Overload,
+
+ /// __builtin_any_type. Useful for clients like debuggers
+ /// that don't know what type to give something. Only a small
+ /// number of operations are valid on expressions of unknown type;
+ /// notable among them, calls and explicit casts.
+ UnknownAny,
/// The primitive Objective C 'id' type. The type pointed to by the
/// user-visible 'id' type. Only ever shows up in an AST as the base
/// i.e. a type which cannot appear in arbitrary positions in a
/// fully-formed expression.
bool isPlaceholderType() const {
- return getKind() == Overload;
+ return getKind() == Overload || getKind() == UnknownAny;
}
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
"%0 does not refer to the name of a parameter pack; did you mean %1?">;
def note_parameter_pack_here : Note<"parameter pack %0 declared here">;
+def err_bad_use_of_unknown_any : Error<
+ "no known type for %0; must explicitly cast this expression to use it">;
+
} // end of sema category
} // end of sema component.
CastKind &Kind, ExprValueKind &VK, CXXCastPath &BasePath,
bool FunctionalStyle = false);
+ bool checkUnknownAnyCast(SourceRange TyRange, QualType castType,
+ Expr *&castExpr, CastKind &castKind,
+ ExprValueKind &valueKind, CXXCastPath &BasePath);
+
// CheckVectorCast - check type constraints for vectors.
// Since vectors are an extension, there are no C standard reference for this.
// We allow casting between vectors and integer datatypes of the same size.
/// \brief The ObjC 'Class' type.
PREDEF_TYPE_OBJC_CLASS = 27,
/// \brief The ObjC 'SEL' type.
- PREDEF_TYPE_OBJC_SEL = 28
+ PREDEF_TYPE_OBJC_SEL = 28,
+ /// \brief The 'unknown any' type.
+ PREDEF_TYPE_UNKNOWN_ANY = 29
};
/// \brief The number of predefined type IDs that are reserved for
// Placeholder type for functions.
InitBuiltinType(OverloadTy, BuiltinType::Overload);
+ // "any" type; useful for debugger-like clients.
+ InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny);
+
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
case BuiltinType::Overload: return Importer.getToContext().OverloadTy;
case BuiltinType::Dependent: return Importer.getToContext().DependentTy;
+ case BuiltinType::UnknownAny: return Importer.getToContext().UnknownAnyTy;
case BuiltinType::ObjCId:
// FIXME: Make sure that the "to" context supports Objective-C!
return "IntegralComplexCast";
case CK_IntegralComplexToFloatingComplex:
return "IntegralComplexToFloatingComplex";
+ case CK_ResolveUnknownAnyType:
+ return "ResolveUnknownAnyType";
}
llvm_unreachable("Unhandled cast kind!");
case CK_GetObjCProperty:
case CK_LValueBitCast:
case CK_UserDefinedConversion:
+ case CK_ResolveUnknownAnyType:
return false;
case CK_LValueToRValue:
case CK_GetObjCProperty:
case CK_LValueBitCast:
case CK_UserDefinedConversion:
+ case CK_ResolveUnknownAnyType:
return false;
case CK_FloatingRealToComplex: {
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::UnknownAny:
assert(false &&
"Overloaded and dependent types shouldn't get to name mangling");
break;
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::UnknownAny:
assert(false &&
"Overloaded and dependent types shouldn't get to name mangling");
break;
case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>";
case Dependent: return "<dependent type>";
+ case UnknownAny: return "<unknown type>";
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
case BuiltinType::NullPtr:
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::UnknownAny:
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
ConvertType(ToType));
return MakeAddrLValue(V, E->getType());
}
+ case CK_ResolveUnknownAnyType: {
+ const DeclRefExpr *declRef = cast<DeclRefExpr>(E->getSubExpr());
+ llvm::Constant *addr = CGM.getAddrOfUnknownAnyDecl(declRef->getDecl(),
+ E->getType());
+ return MakeAddrLValue(addr, E->getType());
+ }
}
llvm_unreachable("Unhandled lvalue cast kind?");
case CK_LValueBitCast:
llvm_unreachable("should not be emitting lvalue bitcast as rvalue");
break;
+
+ case CK_ResolveUnknownAnyType:
+ EmitAggLoadOfLValue(E);
+ break;
case CK_Dependent:
case CK_BitCast:
case CK_GetObjCProperty:
case CK_ToVoid:
case CK_Dynamic:
+ case CK_ResolveUnknownAnyType:
return 0;
// These might need to be supported for constexpr.
RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getType());
return RV.getScalarVal();
}
+
+ case CK_ResolveUnknownAnyType:
+ return EmitLoadOfLValue(CE);
case CK_LValueToRValue:
assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy));
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::UnknownAny:
assert(false && "Should not see this type here!");
case BuiltinType::ObjCId:
return GetOrCreateLLVMGlobal(MangledName, PTy, D);
}
+/// getAddrOfUnknownAnyDecl - Return an llvm::Constant for the address
+/// of a global which was declared with unknown type. It is possible
+/// for a VarDecl to end up getting resolved to have function type,
+/// which complicates this substantially; on the other hand, these are
+/// always external references, which does simplify the logic a lot.
+llvm::Constant *
+CodeGenModule::getAddrOfUnknownAnyDecl(const NamedDecl *decl, QualType type) {
+ GlobalDecl global;
+
+ // FunctionDecls will always end up with function types, but
+ // VarDecls can end up with them too.
+ if (isa<FunctionDecl>(decl))
+ global = GlobalDecl(cast<FunctionDecl>(decl));
+ else
+ global = GlobalDecl(cast<VarDecl>(decl));
+ llvm::StringRef mangledName = getMangledName(global);
+
+ const llvm::Type *ty = getTypes().ConvertTypeForMem(type);
+ const llvm::PointerType *pty =
+ llvm::PointerType::get(ty, getContext().getTargetAddressSpace(type));
+
+
+ // Check for an existing global value with this name.
+ llvm::GlobalValue *entry = GetGlobalValue(mangledName);
+ if (entry)
+ return llvm::ConstantExpr::getBitCast(entry, pty);
+
+ // If we're creating something with function type, go ahead and
+ // create a function.
+ if (const llvm::FunctionType *fnty = dyn_cast<llvm::FunctionType>(ty)) {
+ llvm::Function *fn = llvm::Function::Create(fnty,
+ llvm::Function::ExternalLinkage,
+ mangledName, &getModule());
+ return fn;
+
+ // Otherwise, make a global variable.
+ } else {
+ llvm::GlobalVariable *var
+ = new llvm::GlobalVariable(getModule(), ty, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, mangledName, 0,
+ false, pty->getAddressSpace());
+ if (isa<VarDecl>(decl) && cast<VarDecl>(decl)->isThreadSpecified())
+ var->setThreadLocal(true);
+ return var;
+ }
+}
+
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *
CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty,
llvm::StringRef Name) {
- return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0,
+ return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0,
true);
}
llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D,
const llvm::Type *Ty = 0);
+ llvm::Constant *getAddrOfUnknownAnyDecl(const NamedDecl *D, QualType type);
+
/// GetAddrOfFunction - Return the address of the given function. If Ty is
/// non-null, then this function will use the specified type if it has to
/// create it.
case BuiltinType::Overload:
case BuiltinType::Dependent:
- assert(0 && "Unexpected builtin type!");
+ case BuiltinType::UnknownAny:
+ llvm_unreachable("Unexpected builtin type!");
break;
}
- assert(0 && "Unknown builtin type!");
+ llvm_unreachable("Unknown builtin type!");
break;
}
case Type::Complex: {
return tcr != TC_Success;
}
+
return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0);
}
+/// Given a function expression of unknown-any type, rebuild it to
+/// have a type appropriate for being called with the given arguments,
+/// yielding a value of unknown-any type.
+static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn,
+ Expr **args, unsigned numArgs) {
+ // Build a simple function type exactly matching the arguments.
+ llvm::SmallVector<QualType, 8> argTypes;
+ argTypes.reserve(numArgs);
+ for (unsigned i = 0; i != numArgs; ++i) {
+ // Require all the sub-expression to not be placeholders.
+ ExprResult result = S.CheckPlaceholderExpr(args[i], SourceLocation());
+ if (result.isInvalid()) return ExprError();
+ args[i] = result.take();
+
+ // Do l2r conversions on all the arguments.
+ S.DefaultLvalueConversion(args[i]);
+
+ argTypes.push_back(args[i]->getType());
+ }
+
+ // Resolve the symbol to a function type that returns an unknown-any
+ // type. In the fully resolved expression, this cast will surround
+ // the DeclRefExpr.
+ FunctionProtoType::ExtProtoInfo extInfo;
+ QualType fnType = S.Context.getFunctionType(S.Context.UnknownAnyTy,
+ argTypes.data(), numArgs,
+ extInfo);
+ fn = ImplicitCastExpr::Create(S.Context, fnType,
+ CK_ResolveUnknownAnyType,
+ fn, /*path*/ 0,
+ (S.getLangOptions().CPlusPlus ? VK_LValue : VK_RValue));
+
+ // Decay that to a pointer.
+ fnType = S.Context.getPointerType(fnType);
+ fn = ImplicitCastExpr::Create(S.Context, fnType,
+ CK_FunctionToPointerDecay,
+ fn, /*path*/ 0, VK_RValue);
+
+ return S.Owned(fn);
+}
+
/// BuildResolvedCallExpr - Build a call to a resolved expression,
/// i.e. an expression not of \p OverloadTy. The expression should
/// unary-convert to an expression of function-pointer or
if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID))
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
+ retry:
const FunctionType *FuncT;
if (const PointerType *PT = Fn->getType()->getAs<PointerType>()) {
// C99 6.5.2.2p1 - "The expression that denotes the called function shall
Fn->getType()->getAs<BlockPointerType>()) {
FuncT = BPT->getPointeeType()->castAs<FunctionType>();
} else {
+ // Handle calls to expressions of unknown-any type.
+ if (Fn->getType() == Context.UnknownAnyTy) {
+ ExprResult rewrite = rebuildUnknownAnyFunction(*this, Fn, Args, NumArgs);
+ if (rewrite.isInvalid()) return ExprError();
+ Fn = rewrite.take();
+ NDecl = FDecl = 0;
+ goto retry;
+ }
+
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
<< Fn->getType() << Fn->getSourceRange());
}
bool Sema::CheckCastTypes(SourceRange TyR, QualType castType,
Expr *&castExpr, CastKind& Kind, ExprValueKind &VK,
CXXCastPath &BasePath, bool FunctionalStyle) {
+ if (castExpr->getType() == Context.UnknownAnyTy)
+ return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath);
+
if (getLangOptions().CPlusPlus)
return CXXCheckCStyleCast(SourceRange(TyR.getBegin(),
castExpr->getLocEnd()),
SourceLocation QuestionLoc) {
// If either LHS or RHS are overloaded functions, try to resolve them.
- if (LHS->getType() == Context.OverloadTy ||
- RHS->getType() == Context.OverloadTy) {
- ExprResult LHSResult = CheckPlaceholderExpr(LHS, QuestionLoc);
- if (LHSResult.isInvalid())
- return QualType();
-
- ExprResult RHSResult = CheckPlaceholderExpr(RHS, QuestionLoc);
- if (RHSResult.isInvalid())
- return QualType();
+ ExprResult lhsResult = CheckPlaceholderExpr(LHS, QuestionLoc);
+ if (!lhsResult.isUsable()) return QualType();
+ LHS = lhsResult.take();
- LHS = LHSResult.take();
- RHS = RHSResult.take();
- }
+ ExprResult rhsResult = CheckPlaceholderExpr(RHS, QuestionLoc);
+ if (!rhsResult.isUsable()) return QualType();
+ RHS = rhsResult.take();
// C++ is sufficiently different to merit its own checker.
if (getLangOptions().CPlusPlus)
// f<int> == 0; // resolve f<int> blindly
// void (*p)(int); p = f<int>; // resolve f<int> using target
if (Opc != BO_Assign) {
- if (lhs->getType() == Context.OverloadTy) {
- ExprResult resolvedLHS =
- ResolveAndFixSingleFunctionTemplateSpecialization(lhs);
- if (resolvedLHS.isUsable()) lhs = resolvedLHS.release();
- }
- if (rhs->getType() == Context.OverloadTy) {
- ExprResult resolvedRHS =
- ResolveAndFixSingleFunctionTemplateSpecialization(rhs);
- if (resolvedRHS.isUsable()) rhs = resolvedRHS.release();
- }
+ ExprResult resolvedLHS = CheckPlaceholderExpr(lhs, OpLoc);
+ if (!resolvedLHS.isUsable()) return ExprError();
+ lhs = resolvedLHS.take();
+
+ ExprResult resolvedRHS = CheckPlaceholderExpr(rhs, OpLoc);
+ if (!resolvedRHS.isUsable()) return ExprError();
+ rhs = resolvedRHS.take();
}
switch (Opc) {
case UO_AddrOf:
resultType = CheckAddressOfOperand(*this, Input, OpLoc);
break;
- case UO_Deref:
- if (Input->getType() == Context.OverloadTy ) {
- ExprResult er = ResolveAndFixSingleFunctionTemplateSpecialization(Input);
- if (er.isUsable())
- Input = er.release();
- }
+ case UO_Deref: {
+ ExprResult resolved = CheckPlaceholderExpr(Input, OpLoc);
+ if (!resolved.isUsable()) return ExprError();
+ Input = resolved.take();
DefaultFunctionArrayLvalueConversion(Input);
resultType = CheckIndirectionOperand(*this, Input, VK, OpLoc);
break;
+ }
case UO_Plus:
case UO_Minus:
UsualUnaryConversions(Input);
return Owned(Sub);
}
+namespace {
+ struct RebuildUnknownAnyExpr
+ : StmtVisitor<RebuildUnknownAnyExpr, Expr*> {
+
+ Sema &S;
+
+ /// The current destination type.
+ QualType DestType;
+
+ RebuildUnknownAnyExpr(Sema &S, QualType castType)
+ : S(S), DestType(castType) {}
+
+ Expr *VisitStmt(Stmt *S) {
+ llvm_unreachable("unexpected expression kind!");
+ return 0;
+ }
+
+ Expr *VisitCallExpr(CallExpr *call) {
+ call->setCallee(Visit(call->getCallee()));
+ return call;
+ }
+
+ Expr *VisitParenExpr(ParenExpr *paren) {
+ paren->setSubExpr(Visit(paren->getSubExpr()));
+ return paren;
+ }
+
+ Expr *VisitUnaryExtension(UnaryOperator *op) {
+ op->setSubExpr(Visit(op->getSubExpr()));
+ return op;
+ }
+
+ Expr *VisitImplicitCastExpr(ImplicitCastExpr *ice) {
+ // If this isn't an inner resolution, just recurse down.
+ if (ice->getCastKind() != CK_ResolveUnknownAnyType) {
+ assert(ice->getCastKind() == CK_FunctionToPointerDecay);
+ ice->setSubExpr(Visit(ice->getSubExpr()));
+ return ice;
+ }
+
+ QualType type = ice->getType();
+ assert(type.getUnqualifiedType() == type);
+
+ // The only time it should be possible for this to appear
+ // internally to an unknown-any expression is when handling a call.
+ const FunctionProtoType *proto = type->castAs<FunctionProtoType>();
+ DestType = S.Context.getFunctionType(DestType,
+ proto->arg_type_begin(),
+ proto->getNumArgs(),
+ proto->getExtProtoInfo());
+
+ // Strip the resolve cast when recursively rebuilding.
+ return Visit(ice->getSubExpr());
+ }
+
+ Expr *VisitDeclRefExpr(DeclRefExpr *ref) {
+ ExprValueKind valueKind = VK_LValue;
+ if (!S.getLangOptions().CPlusPlus && DestType->isFunctionType())
+ valueKind = VK_RValue;
+
+ return ImplicitCastExpr::Create(S.Context, DestType,
+ CK_ResolveUnknownAnyType,
+ ref, 0, valueKind);
+ }
+ };
+}
+
+/// Check a cast of an unknown-any type. We intentionally only
+/// trigger this for C-style casts.
+bool Sema::checkUnknownAnyCast(SourceRange typeRange, QualType castType,
+ Expr *&castExpr, CastKind &castKind,
+ ExprValueKind &VK, CXXCastPath &path) {
+ VK = Expr::getValueKindForType(castType);
+
+ // Rewrite the casted expression from scratch.
+ castExpr = RebuildUnknownAnyExpr(*this, castType).Visit(castExpr);
+
+ return CheckCastTypes(typeRange, castType, castExpr, castKind, VK, path);
+}
+
+static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) {
+ Expr *orig = e;
+ while (true) {
+ e = e->IgnoreParenImpCasts();
+ if (CallExpr *call = dyn_cast<CallExpr>(e))
+ e = call->getCallee();
+ else
+ break;
+ }
+
+ assert(isa<DeclRefExpr>(e) && "unexpected form of unknown-any expression");
+ DeclRefExpr *ref = cast<DeclRefExpr>(e);
+ S.Diag(ref->getLocation(), diag::err_bad_use_of_unknown_any)
+ << ref->getDecl() << orig->getSourceRange();
+
+ // Never recoverable.
+ return ExprError();
+}
+
/// Check for operands with placeholder types and complain if found.
/// Returns true if there was an error and no recovery was possible.
ExprResult Sema::CheckPlaceholderExpr(Expr *E, SourceLocation Loc) {
- const BuiltinType *BT = E->getType()->getAs<BuiltinType>();
- if (!BT || !BT->isPlaceholderType()) return Owned(E);
+ // Placeholder types are always *exactly* the appropriate builtin type.
+ QualType type = E->getType();
- // If this is overload, check for a single overload.
- assert(BT->getKind() == BuiltinType::Overload);
- return ResolveAndFixSingleFunctionTemplateSpecialization(E, false, true,
+ // Overloaded expressions.
+ if (type == Context.OverloadTy)
+ return ResolveAndFixSingleFunctionTemplateSpecialization(E, false, true,
E->getSourceRange(),
- QualType(),
- diag::err_ovl_unresolvable);
+ QualType(),
+ diag::err_ovl_unresolvable);
+
+ // Expressions of unknown type.
+ if (type == Context.UnknownAnyTy)
+ return diagnoseUnknownAnyExpr(*this, E);
+
+ assert(!type->isPlaceholderType());
+ return Owned(E);
}
case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break;
case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break;
case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break;
+ case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break;
case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break;
case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break;
case PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break;
case PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break;
case PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break;
+ case PREDEF_TYPE_UNKNOWN_ANY: T = Context->UnknownAnyTy; break;
case PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break;
case PREDEF_TYPE_CHAR16_ID: T = Context->Char16Ty; break;
case PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break;
continue;
}
// Various C++ casts that are not handled yet.
- case CK_Dynamic:
+ case CK_ResolveUnknownAnyType:
+ case CK_Dynamic:
case CK_ToUnion:
case CK_BaseToDerived:
case CK_NullToMemberPointer:
namespace rdar9136502 {
struct X {
- int i();
- int i(int);
+ int i(); // expected-note {{candidate function}}
+ int i(int); // expected-note {{candidate function}}
};
struct Y {
};
void f(X x, Y y) {
- // FIXME: This diagnostic is non-awesome.
- y << x.i; // expected-error{{invalid operands to binary expression ('rdar9136502::Y' and '<overloaded function type>')}}
+ y << x.i; // expected-error{{cannot resolve overloaded function 'i' from context}}
}
}
}
void one() { }
-void two() { } // expected-note 2{{candidate}}
-void two(int) { } // expected-note 2{{candidate}}
+void two() { } // expected-note 3{{candidate}}
+void two(int) { } // expected-note 3{{candidate}}
-template<class T> void twoT() { } // expected-note 3{{candidate}}
-template<class T> void twoT(int) { } // expected-note 3{{candidate}}
+template<class T> void twoT() { } // expected-note 5{{candidate}}
+template<class T> void twoT(int) { } // expected-note 5{{candidate}}
template<class T> void oneT() { }
template<class T, class U> void oneT(U) { }
void (*p1)(int); p1 = oneT<int>;
int i = (int) (false ? (void (*)(int))twoT<int> : oneT<int>); //expected-error {{incompatible operand}}
- (twoT<int>) == oneT<int>; //expected-error {{invalid operands to binary expression}}
+ (twoT<int>) == oneT<int>; //expected-error {{cannot resolve overloaded function 'twoT' from context}}
bool b = oneT<int>;
void (*p)() = oneT<int>;
test<oneT<int> > ti;
oneT<int> < oneT<int>; //expected-warning {{self-comparison always evaluates to false}} \
//expected-warning {{expression result unused}}
- two < two; //expected-error {{invalid operands to binary expression}}
- twoT<int> < twoT<int>; //expected-error {{invalid operands to binary expression}}
+ two < two; //expected-error {{cannot resolve overloaded function 'two' from context}}
+ twoT<int> < twoT<int>; //expected-error {{cannot resolve overloaded function 'twoT' from context}}
oneT<int> == 0; // expected-warning {{expression result unused}}
}
case BuiltinType::NullPtr:
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::UnknownAny:
break;
case BuiltinType::ObjCId:
c = 'n'; break;
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::UnknownAny:
IgnoreResults = true;
return;
case BuiltinType::ObjCId: