aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/Sema.h7
-rw-r--r--lib/Parse/ParseDecl.cpp6
-rw-r--r--lib/Parse/ParseTentative.cpp4
-rw-r--r--lib/Sema/SemaExpr.cpp16
-rw-r--r--lib/Sema/SemaExprObjC.cpp13
-rw-r--r--test/SemaObjCXX/unknown-anytype.mm45
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);
+}