mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-26 05:18:46 +00:00
Fix a bunch of major problems with __unknown_anytype and properly test
for them. The only major missing feature is references. llvm-svn: 129234
This commit is contained in:
parent
b799b2d4be
commit
39439739cf
@ -113,6 +113,7 @@ public:
|
||||
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 @@ public:
|
||||
NoBitFieldTypeAlign = 0;
|
||||
FakeAddressSpaceMap = 0;
|
||||
MRTD = 0;
|
||||
ParseUnknownAnytype = 0;
|
||||
}
|
||||
|
||||
GCMode getGCMode() const { return (GCMode) GC; }
|
||||
|
@ -55,6 +55,7 @@ namespace clang {
|
||||
TST_typeofExpr,
|
||||
TST_decltype, // C++0x decltype
|
||||
TST_auto, // C++0x auto
|
||||
TST_unknown_anytype, // __unknown_anytype extension
|
||||
TST_error // erroneous type
|
||||
};
|
||||
|
||||
|
@ -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("_pascal" , __pascal , KEYBORLAND)
|
||||
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(template_id) // annotation for a C++ template-id that names a
|
||||
ANNOTATION(pragma_unused)
|
||||
|
||||
#undef ANNOTATION
|
||||
#undef TESTING_KEYWORD
|
||||
#undef OBJC2_AT_KEYWORD
|
||||
#undef OBJC1_AT_KEYWORD
|
||||
#undef CXX_KEYWORD_OPERATOR
|
||||
|
@ -526,6 +526,8 @@ def traditional_cpp : Flag<"-traditional-cpp">,
|
||||
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
|
||||
|
@ -250,6 +250,7 @@ public:
|
||||
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
|
||||
|
@ -162,7 +162,12 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
|
||||
#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 {
|
||||
|
@ -684,6 +684,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
|
||||
}
|
||||
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 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
||||
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);
|
||||
|
@ -1720,6 +1720,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||
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:
|
||||
|
@ -309,6 +309,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
|
||||
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!");
|
||||
|
@ -4720,6 +4720,11 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
|
||||
/// 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 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
|
||||
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 @@ ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc,
|
||||
|
||||
namespace {
|
||||
struct RebuildUnknownAnyExpr
|
||||
: StmtVisitor<RebuildUnknownAnyExpr, Expr*> {
|
||||
: StmtVisitor<RebuildUnknownAnyExpr, ExprResult> {
|
||||
|
||||
Sema &S;
|
||||
|
||||
@ -10148,57 +10154,123 @@ namespace {
|
||||
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();
|
||||
}
|
||||
|
||||
Expr *VisitCallExpr(CallExpr *call) {
|
||||
call->setCallee(Visit(call->getCallee()));
|
||||
return call;
|
||||
}
|
||||
ExprResult VisitCallExpr(CallExpr *call) {
|
||||
Expr *callee = call->getCallee();
|
||||
|
||||
Expr *VisitParenExpr(ParenExpr *paren) {
|
||||
paren->setSubExpr(Visit(paren->getSubExpr()));
|
||||
return paren;
|
||||
}
|
||||
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>();
|
||||
|
||||
Expr *VisitUnaryExtension(UnaryOperator *op) {
|
||||
op->setSubExpr(Visit(op->getSubExpr()));
|
||||
return op;
|
||||
}
|
||||
// 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;
|
||||
|
||||
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;
|
||||
S.Diag(call->getExprLoc(), diagID)
|
||||
<< DestType->isFunctionType() << DestType;
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
QualType type = ice->getType();
|
||||
assert(type.getUnqualifiedType() == type);
|
||||
// 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);
|
||||
|
||||
// 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());
|
||||
// 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());
|
||||
|
||||
// Strip the resolve cast when recursively rebuilding.
|
||||
return Visit(ice->getSubExpr());
|
||||
// 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 *VisitDeclRefExpr(DeclRefExpr *ref) {
|
||||
ExprValueKind valueKind = VK_LValue;
|
||||
if (!S.getLangOptions().CPlusPlus && DestType->isFunctionType())
|
||||
valueKind = VK_RValue;
|
||||
/// 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;
|
||||
}
|
||||
|
||||
return ImplicitCastExpr::Create(S.Context, DestType,
|
||||
CK_ResolveUnknownAnyType,
|
||||
ref, 0, valueKind);
|
||||
ExprResult VisitParenExpr(ParenExpr *paren) {
|
||||
return rebuildSugarExpr(paren);
|
||||
}
|
||||
|
||||
ExprResult VisitUnaryExtension(UnaryOperator *op) {
|
||||
return rebuildSugarExpr(op);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Rebuild the sub-expression as the pointee (function) type.
|
||||
DestType = DestType->castAs<PointerType>()->getPointeeType();
|
||||
|
||||
ExprResult result = Visit(ice->getSubExpr());
|
||||
if (!result.isUsable()) return ExprError();
|
||||
|
||||
ice->setSubExpr(result.take());
|
||||
return S.Owned(ice);
|
||||
}
|
||||
|
||||
ExprResult VisitDeclRefExpr(DeclRefExpr *ref) {
|
||||
ExprValueKind valueKind = VK_LValue;
|
||||
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 S.Owned(ImplicitCastExpr::Create(S.Context, DestType,
|
||||
CK_ResolveUnknownAnyType,
|
||||
ref, 0, valueKind));
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -10208,12 +10280,15 @@ namespace {
|
||||
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();
|
||||
|
||||
return CheckCastTypes(typeRange, castType, castExpr, castKind, VK, path);
|
||||
castExpr = result.take();
|
||||
VK = castExpr->getValueKind();
|
||||
castKind = CK_NoOp;
|
||||
|
||||
return castExpr;
|
||||
}
|
||||
|
||||
static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) {
|
||||
|
@ -649,6 +649,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
|
||||
case TST_struct:
|
||||
case TST_class:
|
||||
case TST_auto:
|
||||
case TST_unknown_anytype:
|
||||
case TST_error:
|
||||
break;
|
||||
}
|
||||
|
@ -841,6 +841,10 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) {
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclSpec::TST_unknown_anytype:
|
||||
Result = Context.UnknownAnyTy;
|
||||
break;
|
||||
|
||||
case DeclSpec::TST_error:
|
||||
Result = Context.IntTy;
|
||||
declarator.setInvalidType(true);
|
||||
|
57
clang/test/CodeGenCXX/unknown-anytype.cpp
Normal file
57
clang/test/CodeGenCXX/unknown-anytype.cpp
Normal file
@ -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);
|
||||
}
|
21
clang/test/SemaCXX/unknown-anytype.cpp
Normal file
21
clang/test/SemaCXX/unknown-anytype.cpp
Normal file
@ -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}}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user