summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2012-11-14 00:49:39 +0000
committerJohn McCall <rjmccall@apple.com>2012-11-14 00:49:39 +0000
commitea0a39e7ad3ca90a13ed22826e1f5e9edbd40659 (patch)
treeb71f1e2121054359d5f985903b5157ac8544416a
parentdffc54be70540c81db0fed20489de30e914e05ce (diff)
downloadbcm5719-llvm-ea0a39e7ad3ca90a13ed22826e1f5e9edbd40659.tar.gz
bcm5719-llvm-ea0a39e7ad3ca90a13ed22826e1f5e9edbd40659.zip
Accept and pass arguments to __unknown_anytype in argument
positions of Objective-C methods. It is possible to recover a lot of type information about Objective-C methods from the reflective metadata for their implementations. This information is not rich when it comes to struct types, however, and it is not possible to produce a type in the debugger's round-tripped AST which will really do anything useful during type-checking. Therefore we allow __unknown_anytype in these positions, which essentially disables type-checking for that argument. We infer the parameter type to be the unqualified type of the argument expression unless that expression is an explicit cast, in which case it becomes the type-as-written of that cast. rdar://problem/12565338 llvm-svn: 167896
-rw-r--r--clang/include/clang/Sema/Sema.h7
-rw-r--r--clang/lib/Parse/ParseDecl.cpp6
-rw-r--r--clang/lib/Parse/ParseTentative.cpp4
-rw-r--r--clang/lib/Sema/SemaExpr.cpp16
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp13
-rw-r--r--clang/test/SemaObjCXX/unknown-anytype.mm45
6 files changed, 91 insertions, 0 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9b572d8b4d7..587203e7521 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/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/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index f73907a7c40..d898447ab5c 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/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/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 40c4eee1994..b26181f08ea 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bf4abfcb746..58c212b62f9 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/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/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index e43b6bff558..b0f9958bb52 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/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/clang/test/SemaObjCXX/unknown-anytype.mm b/clang/test/SemaObjCXX/unknown-anytype.mm
index b28b1355efc..e89dee1e2c7 100644
--- a/clang/test/SemaObjCXX/unknown-anytype.mm
+++ b/clang/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);
+}
OpenPOWER on IntegriCloud