forked from OSchip/llvm-project
Resolve placeholder expressions before trying to deduce
'auto'. Introduce a convenience method to make this a bit easier, and use it elsewhere. llvm-svn: 144605
This commit is contained in:
parent
9957e8b789
commit
d5c98ae695
|
@ -170,6 +170,9 @@ BUILTIN_TYPE(Dependent, DependentTy)
|
|||
// &x->foo # only if might be a static member function
|
||||
// &Class::foo # when a pointer-to-member; sub-expr also has this type
|
||||
// OverloadExpr::find can be used to analyze the expression.
|
||||
//
|
||||
// Overload should be the first placeholder type, or else change
|
||||
// BuiltinType::isNonOverloadPlaceholderType()
|
||||
PLACEHOLDER_TYPE(Overload, OverloadTy)
|
||||
|
||||
// The type of a bound C++ non-static member function.
|
||||
|
|
|
@ -1367,6 +1367,10 @@ public:
|
|||
/// isSpecificPlaceholderType - Test for a specific placeholder type.
|
||||
bool isSpecificPlaceholderType(unsigned K) const;
|
||||
|
||||
/// isNonOverloadPlaceholderType - Test for a placeholder type
|
||||
/// other than Overload; see BuiltinType::isNonOverloadPlaceholderType.
|
||||
bool isNonOverloadPlaceholderType() const;
|
||||
|
||||
/// isIntegerType() does *not* include complex integers (a GCC extension).
|
||||
/// isComplexIntegerType() can be used to test for complex integers.
|
||||
bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
|
||||
|
@ -1725,6 +1729,19 @@ public:
|
|||
return isPlaceholderTypeKind(getKind());
|
||||
}
|
||||
|
||||
/// Determines whether this type is a placeholder type other than
|
||||
/// Overload. Most placeholder types require only syntactic
|
||||
/// information about their context in order to be resolved (e.g.
|
||||
/// whether it is a call expression), which means they can (and
|
||||
/// should) be resolved in an earlier "phase" of analysis.
|
||||
/// Overload expressions sometimes pick up further information
|
||||
/// from their context, like whether the context expects a
|
||||
/// specific function-pointer type, and so frequently need
|
||||
/// special treatment.
|
||||
bool isNonOverloadPlaceholderType() const {
|
||||
return getKind() > Overload;
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
|
||||
static bool classof(const BuiltinType *) { return true; }
|
||||
};
|
||||
|
@ -4710,6 +4727,12 @@ inline bool Type::isSpecificPlaceholderType(unsigned K) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
inline bool Type::isNonOverloadPlaceholderType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
|
||||
return BT->isNonOverloadPlaceholderType();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this is a type for which one can define
|
||||
/// an overloaded operator.
|
||||
inline bool Type::isOverloadableType() const {
|
||||
|
|
|
@ -4624,7 +4624,7 @@ public:
|
|||
FunctionDecl *&Specialization,
|
||||
sema::TemplateDeductionInfo &Info);
|
||||
|
||||
bool DeduceAutoType(TypeSourceInfo *AutoType, Expr *Initializer,
|
||||
bool DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer,
|
||||
TypeSourceInfo *&Result);
|
||||
|
||||
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
|
||||
|
|
|
@ -3976,10 +3976,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
|
|||
// Immediately handle non-overload placeholders. Overloads can be
|
||||
// resolved contextually, but everything else here can't.
|
||||
for (unsigned I = 0; I != NumInit; ++I) {
|
||||
if (const BuiltinType *pty
|
||||
= InitList[I]->getType()->getAsPlaceholderType()) {
|
||||
if (pty->getKind() == BuiltinType::Overload) continue;
|
||||
|
||||
if (InitList[I]->getType()->isNonOverloadPlaceholderType()) {
|
||||
ExprResult result = CheckPlaceholderExpr(InitList[I]);
|
||||
|
||||
// Ignore failures; dropping the entire initializer list because
|
||||
|
|
|
@ -3795,17 +3795,14 @@ InitializationSequence::InitializationSequence(Sema &S,
|
|||
setSequenceKind(NormalSequence);
|
||||
|
||||
for (unsigned I = 0; I != NumArgs; ++I)
|
||||
if (const BuiltinType *PlaceholderTy
|
||||
= Args[I]->getType()->getAsPlaceholderType()) {
|
||||
if (Args[I]->getType()->isNonOverloadPlaceholderType()) {
|
||||
// FIXME: should we be doing this here?
|
||||
if (PlaceholderTy->getKind() != BuiltinType::Overload) {
|
||||
ExprResult result = S.CheckPlaceholderExpr(Args[I]);
|
||||
if (result.isInvalid()) {
|
||||
SetFailed(FK_PlaceholderType);
|
||||
return;
|
||||
}
|
||||
Args[I] = result.take();
|
||||
ExprResult result = S.CheckPlaceholderExpr(Args[I]);
|
||||
if (result.isInvalid()) {
|
||||
SetFailed(FK_PlaceholderType);
|
||||
return;
|
||||
}
|
||||
Args[I] = result.take();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -775,12 +775,10 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
|
|||
VK_RValue, OK_Ordinary, opcLoc);
|
||||
|
||||
// Filter out non-overload placeholder types in the RHS.
|
||||
if (const BuiltinType *PTy = RHS->getType()->getAsPlaceholderType()) {
|
||||
if (PTy->getKind() != BuiltinType::Overload) {
|
||||
ExprResult result = CheckPlaceholderExpr(RHS);
|
||||
if (result.isInvalid()) return ExprError();
|
||||
RHS = result.take();
|
||||
}
|
||||
if (RHS->getType()->isNonOverloadPlaceholderType()) {
|
||||
ExprResult result = CheckPlaceholderExpr(RHS);
|
||||
if (result.isInvalid()) return ExprError();
|
||||
RHS = result.take();
|
||||
}
|
||||
|
||||
Expr *opaqueRef = LHS->IgnoreParens();
|
||||
|
|
|
@ -3342,8 +3342,14 @@ namespace {
|
|||
///
|
||||
/// \returns true if deduction succeeded, false if it failed.
|
||||
bool
|
||||
Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init,
|
||||
Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
|
||||
TypeSourceInfo *&Result) {
|
||||
if (Init->getType()->isNonOverloadPlaceholderType()) {
|
||||
ExprResult result = CheckPlaceholderExpr(Init);
|
||||
if (result.isInvalid()) return false;
|
||||
Init = result.take();
|
||||
}
|
||||
|
||||
if (Init->isTypeDependent()) {
|
||||
Result = Type;
|
||||
return true;
|
||||
|
|
|
@ -92,7 +92,8 @@ namespace PR10939 {
|
|||
template<typename T> T g(T);
|
||||
|
||||
void f(X *x) {
|
||||
auto value = x->method; // expected-error{{variable 'value' with type 'auto' has incompatible initializer of type '<bound member function type>'}}
|
||||
// FIXME: we should really only get the first diagnostic here.
|
||||
auto value = x->method; // expected-error {{reference to non-static member function must be called}} expected-error{{variable 'value' with type 'auto' has incompatible initializer of type '<bound member function type>'}}
|
||||
if (value) { }
|
||||
|
||||
auto funcptr = &g<int>;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
|
||||
|
||||
struct X {
|
||||
void f() const;
|
||||
|
@ -19,6 +19,15 @@ struct X {
|
|||
- (void)setx:(const X&)other { x_ = other; }
|
||||
- (void)method {
|
||||
self.x.f();
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
// rdar://problem/10444030
|
||||
@interface Test2
|
||||
- (void) setY: (int) y;
|
||||
- (int) z;
|
||||
@end
|
||||
void test2(Test2 *a) {
|
||||
auto y = a.y; // expected-error {{expected getter method not found on object of type 'Test2 *'}} expected-error {{variable 'y' with type 'auto' has incompatible initializer of type}}
|
||||
auto z = a.z;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue