[cfe-commits] r129234 - in /cfe/trunk: include/clang/Basic/LangOptions.h include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Driver/CC1Options.td include/clang/Sema/DeclSpec.h lib/Basic/IdentifierTable.cpp lib/Frontend/CompilerInvocation.cpp lib/Parse/ParseDecl.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp test/CodeGenCXX/unknown-anytype.cpp test/SemaCXX/unknown-anytype.cpp
John McCall
rjmccall at apple.com
Sat Apr 9 15:50:59 PDT 2011
Author: rjmccall
Date: Sat Apr 9 17:50:59 2011
New Revision: 129234
URL: http://llvm.org/viewvc/llvm-project?rev=129234&view=rev
Log:
Fix a bunch of major problems with __unknown_anytype and properly test
for them. The only major missing feature is references.
Added:
cfe/trunk/test/CodeGenCXX/unknown-anytype.cpp
cfe/trunk/test/SemaCXX/unknown-anytype.cpp
Modified:
cfe/trunk/include/clang/Basic/LangOptions.h
cfe/trunk/include/clang/Basic/Specifiers.h
cfe/trunk/include/clang/Basic/TokenKinds.def
cfe/trunk/include/clang/Driver/CC1Options.td
cfe/trunk/include/clang/Sema/DeclSpec.h
cfe/trunk/lib/Basic/IdentifierTable.cpp
cfe/trunk/lib/Frontend/CompilerInvocation.cpp
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Sema/DeclSpec.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
cfe/trunk/lib/Sema/SemaType.cpp
Modified: cfe/trunk/include/clang/Basic/LangOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.h (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.h Sat Apr 9 17:50:59 2011
@@ -113,6 +113,7 @@
unsigned NoConstantCFStrings : 1; // Do not do CF strings
unsigned InlineVisibilityHidden : 1; // Whether inline C++ methods have
// hidden visibility by default.
+ unsigned ParseUnknownAnytype: 1; /// Let the user write __unknown_anytype.
unsigned SpellChecking : 1; // Whether to perform spell-checking for error
// recovery.
@@ -223,6 +224,7 @@
NoBitFieldTypeAlign = 0;
FakeAddressSpaceMap = 0;
MRTD = 0;
+ ParseUnknownAnytype = 0;
}
GCMode getGCMode() const { return (GCMode) GC; }
Modified: cfe/trunk/include/clang/Basic/Specifiers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Specifiers.h?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Specifiers.h (original)
+++ cfe/trunk/include/clang/Basic/Specifiers.h Sat Apr 9 17:50:59 2011
@@ -55,6 +55,7 @@
TST_typeofExpr,
TST_decltype, // C++0x decltype
TST_auto, // C++0x auto
+ TST_unknown_anytype, // __unknown_anytype extension
TST_error // erroneous type
};
Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Sat Apr 9 17:50:59 2011
@@ -38,6 +38,9 @@
#ifndef OBJC2_AT_KEYWORD
#define OBJC2_AT_KEYWORD(X)
#endif
+#ifndef TESTING_KEYWORD
+#define TESTING_KEYWORD(X, L) KEYWORD(X, L)
+#endif
#ifndef ANNOTATION
#define ANNOTATION(X) TOK(annot_ ## X)
#endif
@@ -416,6 +419,9 @@
ALIAS("__char16_t" , char16_t , KEYCXX)
ALIAS("__char32_t" , char32_t , KEYCXX)
+// Clang-specific keywords enabled only in testing.
+TESTING_KEYWORD(__unknown_anytype , KEYALL)
+
//===----------------------------------------------------------------------===//
// Objective-C @-preceeded keywords.
@@ -467,6 +473,7 @@
ANNOTATION(pragma_unused)
#undef ANNOTATION
+#undef TESTING_KEYWORD
#undef OBJC2_AT_KEYWORD
#undef OBJC1_AT_KEYWORD
#undef CXX_KEYWORD_OPERATOR
Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Sat Apr 9 17:50:59 2011
@@ -526,6 +526,8 @@
HelpText<"Enable some traditional CPP emulation">;
def ffake_address_space_map : Flag<"-ffake-address-space-map">,
HelpText<"Use a fake address space map; OpenCL testing purposes only">;
+def funknown_anytype : Flag<"-funknown-anytype">,
+ HelpText<"Enable parser support for the __unknown_anytype type; for testing purposes only">;
//===----------------------------------------------------------------------===//
// Header Search Options
Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Sat Apr 9 17:50:59 2011
@@ -250,6 +250,7 @@
static const TST TST_typeofExpr = clang::TST_typeofExpr;
static const TST TST_decltype = clang::TST_decltype;
static const TST TST_auto = clang::TST_auto;
+ static const TST TST_unknown_anytype = clang::TST_unknown_anytype;
static const TST TST_error = clang::TST_error;
// type-qualifiers
Modified: cfe/trunk/lib/Basic/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/IdentifierTable.cpp?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/IdentifierTable.cpp (original)
+++ cfe/trunk/lib/Basic/IdentifierTable.cpp Sat Apr 9 17:50:59 2011
@@ -162,7 +162,12 @@
#define OBJC2_AT_KEYWORD(NAME) \
if (LangOpts.ObjC2) \
AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this);
+#define TESTING_KEYWORD(NAME, FLAGS)
#include "clang/Basic/TokenKinds.def"
+
+ if (LangOpts.ParseUnknownAnytype)
+ AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL,
+ LangOpts, *this);
}
tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Sat Apr 9 17:50:59 2011
@@ -684,6 +684,8 @@
}
if (Opts.FakeAddressSpaceMap)
Res.push_back("-ffake-address-space-map");
+ if (Opts.ParseUnknownAnytype)
+ Res.push_back("-funknown-anytype");
}
static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
@@ -1507,6 +1509,7 @@
Opts.OptimizeSize = 0;
Opts.MRTD = Args.hasArg(OPT_mrtd);
Opts.FakeAddressSpaceMap = Args.hasArg(OPT_ffake_address_space_map);
+ Opts.ParseUnknownAnytype = Args.hasArg(OPT_funknown_anytype);
// FIXME: Eliminate this dependency.
unsigned Opt = getOptimizationLevel(Args, IK, Diags);
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Sat Apr 9 17:50:59 2011
@@ -1720,6 +1720,10 @@
case tok::kw___pixel:
isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
break;
+ case tok::kw___unknown_anytype:
+ isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
+ PrevSpec, DiagID);
+ break;
// class-specifier:
case tok::kw_class:
Modified: cfe/trunk/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Sema/DeclSpec.cpp Sat Apr 9 17:50:59 2011
@@ -309,6 +309,7 @@
case DeclSpec::TST_typeofExpr: return "typeof";
case DeclSpec::TST_auto: return "auto";
case DeclSpec::TST_decltype: return "(decltype)";
+ case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_error: return "(error)";
}
llvm_unreachable("Unknown typespec!");
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sat Apr 9 17:50:59 2011
@@ -4720,6 +4720,11 @@
/// yielding a value of unknown-any type.
static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn,
Expr **args, unsigned numArgs) {
+ // Strip an lvalue-to-rvalue conversion off.
+ if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(fn))
+ if (ice->getCastKind() == CK_LValueToRValue)
+ fn = ice->getSubExpr();
+
// Build a simple function type exactly matching the arguments.
llvm::SmallVector<QualType, 8> argTypes;
argTypes.reserve(numArgs);
@@ -4818,6 +4823,7 @@
ExprResult rewrite = rebuildUnknownAnyFunction(*this, Fn, Args, NumArgs);
if (rewrite.isInvalid()) return ExprError();
Fn = rewrite.take();
+ TheCall->setCallee(Fn);
NDecl = FDecl = 0;
goto retry;
}
@@ -10138,7 +10144,7 @@
namespace {
struct RebuildUnknownAnyExpr
- : StmtVisitor<RebuildUnknownAnyExpr, Expr*> {
+ : StmtVisitor<RebuildUnknownAnyExpr, ExprResult> {
Sema &S;
@@ -10148,57 +10154,123 @@
RebuildUnknownAnyExpr(Sema &S, QualType castType)
: S(S), DestType(castType) {}
- Expr *VisitStmt(Stmt *S) {
+ ExprResult VisitStmt(Stmt *S) {
llvm_unreachable("unexpected expression kind!");
- return 0;
+ return ExprError();
+ }
+
+ ExprResult VisitCallExpr(CallExpr *call) {
+ Expr *callee = call->getCallee();
+
+ bool wasBlock;
+ QualType type = callee->getType();
+ if (const PointerType *ptr = type->getAs<PointerType>()) {
+ type = ptr->getPointeeType();
+ wasBlock = false;
+ } else {
+ type = type->castAs<BlockPointerType>()->getPointeeType();
+ wasBlock = true;
+ }
+ const FunctionType *fnType = type->castAs<FunctionType>();
+
+ // Verify that this is a legal result type of a function.
+ if (DestType->isArrayType() || DestType->isFunctionType()) {
+ unsigned diagID = diag::err_func_returning_array_function;
+ if (wasBlock) diagID = diag::err_block_returning_array_function;
+
+ S.Diag(call->getExprLoc(), diagID)
+ << DestType->isFunctionType() << DestType;
+ return ExprError();
+ }
+
+ // Otherwise, go ahead and set DestType as the call's result.
+ call->setType(DestType.getNonLValueExprType(S.Context));
+ call->setValueKind(Expr::getValueKindForType(DestType));
+ assert(call->getObjectKind() == OK_Ordinary);
+
+ // Rebuild the function type, replacing the result type with DestType.
+ if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType))
+ DestType = S.Context.getFunctionType(DestType,
+ proto->arg_type_begin(),
+ proto->getNumArgs(),
+ proto->getExtProtoInfo());
+ else
+ DestType = S.Context.getFunctionNoProtoType(DestType,
+ fnType->getExtInfo());
+
+ // Rebuild the appropriate pointer-to-function type.
+ if (wasBlock)
+ DestType = S.Context.getBlockPointerType(DestType);
+ else
+ DestType = S.Context.getPointerType(DestType);
+
+ // Finally, we can recurse.
+ ExprResult calleeResult = Visit(callee);
+ if (!calleeResult.isUsable()) return ExprError();
+ call->setCallee(calleeResult.take());
+
+ // Bind a temporary if necessary.
+ return S.MaybeBindToTemporary(call);
}
- Expr *VisitCallExpr(CallExpr *call) {
- call->setCallee(Visit(call->getCallee()));
- return call;
+ /// Rebuild an expression which simply semantically wraps another
+ /// expression which it shares the type and value kind of.
+ template <class T> ExprResult rebuildSugarExpr(T *expr) {
+ ExprResult subResult = Visit(expr->getSubExpr());
+ if (!subResult.isUsable()) return ExprError();
+ Expr *subExpr = subResult.take();
+ expr->setSubExpr(subExpr);
+ expr->setType(subExpr->getType());
+ expr->setValueKind(subExpr->getValueKind());
+ assert(expr->getObjectKind() == OK_Ordinary);
+ return expr;
}
- Expr *VisitParenExpr(ParenExpr *paren) {
- paren->setSubExpr(Visit(paren->getSubExpr()));
- return paren;
+ ExprResult VisitParenExpr(ParenExpr *paren) {
+ return rebuildSugarExpr(paren);
}
- Expr *VisitUnaryExtension(UnaryOperator *op) {
- op->setSubExpr(Visit(op->getSubExpr()));
- return op;
+ ExprResult VisitUnaryExtension(UnaryOperator *op) {
+ return rebuildSugarExpr(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;
- }
+ ExprResult VisitImplicitCastExpr(ImplicitCastExpr *ice) {
+ // Rebuild an inner resolution by stripping it and propagating
+ // the new type down.
+ if (ice->getCastKind() == CK_ResolveUnknownAnyType)
+ return Visit(ice->getSubExpr());
+
+ // The only other case we should be able to get here is a
+ // function-to-pointer decay.
+ assert(ice->getCastKind() == CK_FunctionToPointerDecay);
+ ice->setType(DestType);
+ assert(ice->getValueKind() == VK_RValue);
+ assert(ice->getObjectKind() == OK_Ordinary);
- QualType type = ice->getType();
- assert(type.getUnqualifiedType() == type);
+ // Rebuild the sub-expression as the pointee (function) type.
+ DestType = DestType->castAs<PointerType>()->getPointeeType();
- // 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());
+ ExprResult result = Visit(ice->getSubExpr());
+ if (!result.isUsable()) return ExprError();
- // Strip the resolve cast when recursively rebuilding.
- return Visit(ice->getSubExpr());
+ ice->setSubExpr(result.take());
+ return S.Owned(ice);
}
- Expr *VisitDeclRefExpr(DeclRefExpr *ref) {
+ ExprResult VisitDeclRefExpr(DeclRefExpr *ref) {
ExprValueKind valueKind = VK_LValue;
- if (!S.getLangOptions().CPlusPlus && DestType->isFunctionType())
+ if (S.getLangOptions().CPlusPlus) {
+ // FIXME: if the value was resolved as a reference type, we
+ // should really remember that somehow, or else we'll be
+ // missing a load.
+ DestType = DestType.getNonReferenceType();
+ } else if (DestType->isFunctionType()) {
valueKind = VK_RValue;
+ }
- return ImplicitCastExpr::Create(S.Context, DestType,
- CK_ResolveUnknownAnyType,
- ref, 0, valueKind);
+ return S.Owned(ImplicitCastExpr::Create(S.Context, DestType,
+ CK_ResolveUnknownAnyType,
+ ref, 0, valueKind));
}
};
}
@@ -10208,12 +10280,15 @@
ExprResult 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);
+ ExprResult result = RebuildUnknownAnyExpr(*this, castType).Visit(castExpr);
+ if (!result.isUsable()) return ExprError();
+
+ castExpr = result.take();
+ VK = castExpr->getValueKind();
+ castKind = CK_NoOp;
- return CheckCastTypes(typeRange, castType, castExpr, castKind, VK, path);
+ return castExpr;
}
static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) {
Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Sat Apr 9 17:50:59 2011
@@ -649,6 +649,7 @@
case TST_struct:
case TST_class:
case TST_auto:
+ case TST_unknown_anytype:
case TST_error:
break;
}
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=129234&r1=129233&r2=129234&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sat Apr 9 17:50:59 2011
@@ -841,6 +841,10 @@
break;
}
+ case DeclSpec::TST_unknown_anytype:
+ Result = Context.UnknownAnyTy;
+ break;
+
case DeclSpec::TST_error:
Result = Context.IntTy;
declarator.setInvalidType(true);
Added: cfe/trunk/test/CodeGenCXX/unknown-anytype.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/unknown-anytype.cpp?rev=129234&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/unknown-anytype.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/unknown-anytype.cpp Sat Apr 9 17:50:59 2011
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -funknown-anytype -emit-llvm -o - %s | FileCheck %s
+
+int test0() {
+ extern __unknown_anytype test0_any;
+ // CHECK: load i32* @test0_any
+ return (int) test0_any;
+}
+
+int test1() {
+ extern __unknown_anytype test1_any;
+ // CHECK: call i32 @test1_any()
+ return (int) test1_any();
+}
+
+float test2() {
+ extern __unknown_anytype test2_any;
+ // CHECK: call float @test2_any(float {{[^,]+}})
+ return (float) test2_any(0.5f);
+}
+
+float test3() {
+ extern __unknown_anytype test3_any;
+ // CHECK: call float @test3_any(i32 5)
+ return ((float(int)) test3_any)(5);
+}
+
+namespace test4 {
+ extern __unknown_anytype test4_any1;
+ extern __unknown_anytype test4_any2;
+
+ int test() {
+ // CHECK: load i32* @_ZN5test410test4_any1E
+ // CHECK: call i32 @_ZN5test410test4_any2E
+ return (int) test4_any1 + (int) test4_any2();
+ }
+}
+
+void test5() {
+ extern __unknown_anytype test5_any;
+ // CHECK: call void @test5_any()
+ return (void) test5_any();
+}
+
+long test6() {
+ extern __unknown_anytype test6_any(float *);
+ // CHECK: call i64 @_Z9test6_anyPf(float* null)
+ return (long) test6_any(0);
+}
+
+struct Test7 {
+ ~Test7();
+};
+Test7 test7() {
+ extern __unknown_anytype test7_any;
+ // CHECK: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5)
+ return (Test7) test7_any(5);
+}
Added: cfe/trunk/test/SemaCXX/unknown-anytype.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/unknown-anytype.cpp?rev=129234&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/unknown-anytype.cpp (added)
+++ cfe/trunk/test/SemaCXX/unknown-anytype.cpp Sat Apr 9 17:50:59 2011
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -funknown-anytype -fsyntax-only -verify %s
+
+namespace test0 {
+ extern __unknown_anytype test0;
+ extern __unknown_anytype test1();
+ extern __unknown_anytype test2(int);
+}
+
+namespace test1 {
+ extern __unknown_anytype foo;
+ int test() {
+ // TODO: it would be great if the 'cannot initialize' errors
+ // turned into something more interesting. It's just a matter of
+ // making sure that these locations check for placeholder types
+ // properly.
+
+ int x = foo; // expected-error {{cannot initialize}}
+ int y = 0 + foo; // expected-error {{no known type for 'foo'; must explicitly cast this expression to use it}}
+ return foo; // expected-error {{cannot initialize}}
+ }
+}
More information about the cfe-commits
mailing list