diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 7 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 13 | ||||
-rw-r--r-- | test/SemaObjCXX/unknown-anytype.mm | 45 |
6 files changed, 91 insertions, 0 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 9b572d8b4d..587203e752 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6812,6 +6812,13 @@ public: /// given type. ExprResult forceUnknownAnyToType(Expr *E, QualType ToType); + /// \brief Handle an expression that's being passed to an + /// __unknown_anytype parameter. + /// + /// \return the effective parameter type to use, or null if the + /// argument is invalid. + QualType checkUnknownAnyArg(Expr *&result); + // 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. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f73907a7c4..d898447ab5 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3652,6 +3652,9 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_volatile: case tok::kw_restrict: + // Debugger support. + case tok::kw___unknown_anytype: + // typedef-name case tok::annot_typename: return true; @@ -3751,6 +3754,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // Modules case tok::kw___module_private__: + // Debugger support + case tok::kw___unknown_anytype: + // type-specifiers case tok::kw_short: case tok::kw_long: diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 40c4eee199..b26181f08e 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -837,6 +837,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___vector: case tok::kw___pixel: case tok::kw__Atomic: + case tok::kw___unknown_anytype: return TPResult::False(); default: @@ -1056,6 +1057,9 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // Modules case tok::kw___module_private__: + + // Debugger support + case tok::kw___unknown_anytype: // type-specifier: // simple-type-specifier diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index bf4abfcb74..58c212b62f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -11850,6 +11850,22 @@ ExprResult Sema::forceUnknownAnyToType(Expr *E, QualType ToType) { return RebuildUnknownAnyExpr(*this, ToType).Visit(E); } +QualType Sema::checkUnknownAnyArg(Expr *&arg) { + // Filter out placeholders. + ExprResult argR = CheckPlaceholderExpr(arg); + if (argR.isInvalid()) return QualType(); + arg = argR.take(); + + // If the argument is an explicit cast, use that exact type as the + // effective parameter type. + if (ExplicitCastExpr *castArg = dyn_cast<ExplicitCastExpr>(arg)) { + return castArg->getTypeAsWritten(); + } + + // Otherwise, try to pass by value. + return arg->getType().getUnqualifiedType(); +} + static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) { Expr *orig = E; unsigned diagID = diag::err_uncasted_use_of_unknown_any; diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index e43b6bff55..b0f9958bb5 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1196,6 +1196,19 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, !param->hasAttr<CFConsumedAttr>()) argExpr = stripARCUnbridgedCast(argExpr); + // If the parameter is __unknown_anytype, infer its type + // from the argument. + if (param->getType() == Context.UnknownAnyTy) { + QualType paramType = checkUnknownAnyArg(argExpr); + if (paramType.isNull()) { + IsError = true; + continue; + } + + // Update the parameter type in-place. + param->setType(paramType); + } + if (RequireCompleteType(argExpr->getSourceRange().getBegin(), param->getType(), diag::err_call_incomplete_argument, argExpr)) diff --git a/test/SemaObjCXX/unknown-anytype.mm b/test/SemaObjCXX/unknown-anytype.mm index b28b1355ef..e89dee1e2c 100644 --- a/test/SemaObjCXX/unknown-anytype.mm +++ b/test/SemaObjCXX/unknown-anytype.mm @@ -7,3 +7,48 @@ namespace test0 { [x foo]; // expected-error {{no known method '-foo'; cast the message send to the method's return type}} } } + +// rdar://problem/12565338 +@interface Test1 +- (void) test_a: (__unknown_anytype)foo; +- (void) test_b: (__unknown_anytype)foo; +- (void) test_c: (__unknown_anytype)foo; +@end +namespace test1 { + struct POD { + int x; + }; + + void a(Test1 *obj) { + POD v; + [obj test_a: v]; + } + + struct Uncopyable { + Uncopyable(); + private: + Uncopyable(const Uncopyable &); // expected-note {{declared private here}} + }; + + void b(Test1 *obj) { + Uncopyable v; + [obj test_b: v]; // expected-error {{calling a private constructor}} + } + + void c(Test1 *obj) { + Uncopyable v; + [obj test_c: (const Uncopyable&) v]; + } +} + +// Just test that we can declare a function taking __unknown_anytype. +// For now, we don't actually need to make calling something like this +// work; if that changes, here's what's required: +// - get this call through overload resolution somehow, +// - update the function-call argument-passing code like the +// message-send code, and +// - rewrite the function expression to have a type that doesn't +// involving __unknown_anytype. +namespace test2 { + void foo(__unknown_anytype x); +} |