am 11274a73: Validate FS (and RS) ASTs.
* commit '11274a7324b478ec13e1d10a1b81350b34a65ab1':
Validate FS (and RS) ASTs.
diff --git a/Android.mk b/Android.mk
index 748665a..da28351 100644
--- a/Android.mk
+++ b/Android.mk
@@ -231,6 +231,7 @@
llvm-rs-cc.cpp \
slang_rs.cpp \
slang_rs_ast_replace.cpp \
+ slang_rs_check_ast.cpp \
slang_rs_context.cpp \
slang_rs_pragma_handler.cpp \
slang_rs_backend.cpp \
diff --git a/slang_rs.cpp b/slang_rs.cpp
index af86e78..98b9771 100644
--- a/slang_rs.cpp
+++ b/slang_rs.cpp
@@ -40,6 +40,8 @@
namespace slang {
+#define FS_SUFFIX "fs"
+
#define RS_HEADER_SUFFIX "rsh"
/* RS_HEADER_ENTRY(name) */
@@ -61,6 +63,15 @@
RS_HEADER_ENTRY(rs_time) \
RS_HEADER_ENTRY(rs_types) \
+// Returns true if \p Filename ends in ".fs".
+bool SlangRS::isFilterscript(const char *Filename) {
+ const char *c = strrchr(Filename, '.');
+ if (c && !strncmp(FS_SUFFIX, c + 1, strlen(FS_SUFFIX) + 1)) {
+ return true;
+ } else {
+ return false;
+ }
+}
bool SlangRS::reflectToJava(const std::string &OutputPathBase,
const std::string &OutputPackageName,
@@ -233,7 +244,8 @@
OS,
OT,
getSourceManager(),
- mAllowRSPrefix);
+ mAllowRSPrefix,
+ mIsFilterscript);
}
bool SlangRS::IsRSHeaderFile(const char *File) {
@@ -245,9 +257,9 @@
return false;
}
-bool SlangRS::IsFunctionInRSHeaderFile(const clang::FunctionDecl *FD,
- const clang::SourceManager &SourceMgr) {
- clang::FullSourceLoc FSL(FD->getLocStart(), SourceMgr);
+bool SlangRS::IsLocInRSHeaderFile(const clang::SourceLocation &Loc,
+ const clang::SourceManager &SourceMgr) {
+ clang::FullSourceLoc FSL(Loc, SourceMgr);
clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL);
const char *Filename = PLoc.getFilename();
@@ -259,7 +271,8 @@
}
SlangRS::SlangRS()
- : Slang(), mRSContext(NULL), mAllowRSPrefix(false), mTargetAPI(0) {
+ : Slang(), mRSContext(NULL), mAllowRSPrefix(false), mTargetAPI(0),
+ mIsFilterscript(false) {
}
bool SlangRS::compile(
@@ -329,6 +342,8 @@
JavaReflectionPackageName);
}
+ mIsFilterscript = isFilterscript(InputFile);
+
if (Slang::compile() > 0)
return false;
diff --git a/slang_rs.h b/slang_rs.h
index 571f1fa..8ad70de 100644
--- a/slang_rs.h
+++ b/slang_rs.h
@@ -29,10 +29,6 @@
#include "slang_rs_reflect_utils.h"
#include "slang_version.h"
-namespace clang {
- class FunctionDecl;
-}
-
namespace slang {
class RSContext;
class RSExportRecordType;
@@ -46,6 +42,8 @@
unsigned int mTargetAPI;
+ bool mIsFilterscript;
+
// Custom diagnostic identifiers
unsigned mDiagErrorInvalidOutputDepParameter;
unsigned mDiagErrorODR;
@@ -77,6 +75,9 @@
// and is valid before compile() ends.
bool checkODR(const char *CurInputFile);
+ // Returns true if this is a Filterscript file.
+ static bool isFilterscript(const char *Filename);
+
protected:
virtual void initDiagnostic();
virtual void initPreprocessor();
@@ -90,11 +91,11 @@
public:
static bool IsRSHeaderFile(const char *File);
- // FIXME: Determine whether a function is in RS header (i.e., one of the RS
+ // FIXME: Determine whether a location is in RS header (i.e., one of the RS
// built-in APIs) should only need its names (we need a "list" of RS
// built-in APIs).
- static bool IsFunctionInRSHeaderFile(const clang::FunctionDecl *FD,
- const clang::SourceManager &SourceMgr);
+ static bool IsLocInRSHeaderFile(const clang::SourceLocation &Loc,
+ const clang::SourceManager &SourceMgr);
SlangRS();
diff --git a/slang_rs_backend.cpp b/slang_rs_backend.cpp
index a1efad1..c643908 100644
--- a/slang_rs_backend.cpp
+++ b/slang_rs_backend.cpp
@@ -54,25 +54,29 @@
llvm::raw_ostream *OS,
Slang::OutputType OT,
clang::SourceManager &SourceMgr,
- bool AllowRSPrefix)
+ bool AllowRSPrefix,
+ bool IsFilterscript)
: Backend(DiagEngine, CodeGenOpts, TargetOpts, Pragmas, OS, OT),
mContext(Context),
mSourceMgr(SourceMgr),
mAllowRSPrefix(AllowRSPrefix),
+ mIsFilterscript(IsFilterscript),
mExportVarMetadata(NULL),
mExportFuncMetadata(NULL),
mExportForEachNameMetadata(NULL),
mExportForEachSignatureMetadata(NULL),
mExportTypeMetadata(NULL),
mRSObjectSlotsMetadata(NULL),
- mRefCount(mContext->getASTContext()) {
+ mRefCount(mContext->getASTContext()),
+ mASTChecker(mContext->getASTContext(), mContext->getTargetAPI(),
+ IsFilterscript) {
}
// 1) Add zero initialization of local RS object types
void RSBackend::AnnotateFunction(clang::FunctionDecl *FD) {
if (FD &&
FD->hasBody() &&
- !SlangRS::IsFunctionInRSHeaderFile(FD, mSourceMgr)) {
+ !SlangRS::IsLocInRSHeaderFile(FD->getLocation(), mSourceMgr)) {
mRefCount.Init();
mRefCount.Visit(FD->getBody());
}
@@ -90,7 +94,7 @@
continue;
if (!FD->getName().startswith("rs")) // Check prefix
continue;
- if (!SlangRS::IsFunctionInRSHeaderFile(FD, mSourceMgr))
+ if (!SlangRS::IsLocInRSHeaderFile(FD->getLocation(), mSourceMgr))
mDiagEngine.Report(
clang::FullSourceLoc(FD->getLocation(), mSourceMgr),
mDiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
@@ -125,53 +129,19 @@
return Backend::HandleTopLevelDecl(D);
}
-namespace {
-
-static bool ValidateVarDecl(clang::VarDecl *VD, unsigned int TargetAPI) {
- if (!VD) {
- return true;
- }
-
- clang::ASTContext &C = VD->getASTContext();
- const clang::Type *T = VD->getType().getTypePtr();
- bool valid = true;
-
- if (VD->getLinkage() == clang::ExternalLinkage) {
- llvm::StringRef TypeName;
- if (!RSExportType::NormalizeType(T, TypeName, &C.getDiagnostics(), VD)) {
- valid = false;
- }
- }
- valid &= RSExportType::ValidateVarDecl(VD, TargetAPI);
-
- return valid;
-}
-
-static bool ValidateASTContext(clang::ASTContext &C, unsigned int TargetAPI) {
- bool valid = true;
- clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
- for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
- DE = TUDecl->decls_end();
- DI != DE;
- DI++) {
- clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI);
- if (VD && !ValidateVarDecl(VD, TargetAPI)) {
- valid = false;
- }
- }
-
- return valid;
-}
-
-} // namespace
void RSBackend::HandleTranslationUnitPre(clang::ASTContext &C) {
clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
- if (!ValidateASTContext(C, getTargetAPI())) {
+ // If we have an invalid RS/FS AST, don't check further.
+ if (!mASTChecker.Validate()) {
return;
}
+ if (mIsFilterscript) {
+ mContext->addPragma("rs_fp_relaxed", "");
+ }
+
int version = mContext->getVersion();
if (version == 0) {
// Not setting a version is an error
diff --git a/slang_rs_backend.h b/slang_rs_backend.h
index 0dc70e6..80c643d 100644
--- a/slang_rs_backend.h
+++ b/slang_rs_backend.h
@@ -19,6 +19,7 @@
#include "slang_backend.h"
#include "slang_pragma_recorder.h"
+#include "slang_rs_check_ast.h"
#include "slang_rs_object_ref_count.h"
namespace llvm {
@@ -47,6 +48,8 @@
bool mAllowRSPrefix;
+ bool mIsFilterscript;
+
llvm::NamedMDNode *mExportVarMetadata;
llvm::NamedMDNode *mExportFuncMetadata;
llvm::NamedMDNode *mExportForEachNameMetadata;
@@ -57,6 +60,8 @@
RSObjectRefCount mRefCount;
+ RSCheckAST mASTChecker;
+
void AnnotateFunction(clang::FunctionDecl *FD);
protected:
@@ -79,7 +84,8 @@
llvm::raw_ostream *OS,
Slang::OutputType OT,
clang::SourceManager &SourceMgr,
- bool AllowRSPrefix);
+ bool AllowRSPrefix,
+ bool IsFilterscript);
virtual ~RSBackend();
};
diff --git a/slang_rs_check_ast.cpp b/slang_rs_check_ast.cpp
new file mode 100644
index 0000000..118bda7
--- /dev/null
+++ b/slang_rs_check_ast.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "slang_rs_check_ast.h"
+
+#include "slang_assert.h"
+#include "slang_rs.h"
+#include "slang_rs_export_type.h"
+
+namespace slang {
+
+void RSCheckAST::VisitStmt(clang::Stmt *S) {
+ // This function does the actual iteration through all sub-Stmt's within
+ // a given Stmt. Note that this function is skipped by all of the other
+ // Visit* functions if we have already found a higher-level match.
+ for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
+ I != E;
+ I++) {
+ if (clang::Stmt *Child = *I) {
+ Visit(Child);
+ }
+ }
+}
+
+void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) {
+ if (!FD) {
+ return;
+ }
+
+ if (!mIsFilterscript) {
+ // No additional validation for non-Filterscript functions.
+ if (clang::Stmt *Body = FD->getBody()) {
+ Visit(Body);
+ }
+ return;
+ }
+
+ size_t numParams = FD->getNumParams();
+
+ clang::QualType resultType = FD->getResultType().getCanonicalType();
+
+ // We use FD as our NamedDecl in the case of a bad return type.
+ if (!RSExportType::ValidateType(C, resultType, FD,
+ FD->getLocStart(), mTargetAPI,
+ mIsFilterscript)) {
+ mValid = false;
+ }
+
+ for (size_t i = 0; i < numParams; i++) {
+ clang::ParmVarDecl *PVD = FD->getParamDecl(i);
+ clang::QualType QT = PVD->getType().getCanonicalType();
+ if (!RSExportType::ValidateType(C, QT, PVD, PVD->getLocStart(),
+ mTargetAPI, mIsFilterscript)) {
+ mValid = false;
+ }
+ }
+
+ if (clang::Stmt *Body = FD->getBody()) {
+ Visit(Body);
+ }
+}
+
+
+void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) {
+ if (!VD) {
+ return;
+ }
+
+ const clang::Type *T = VD->getType().getTypePtr();
+
+ if (VD->getLinkage() == clang::ExternalLinkage) {
+ llvm::StringRef TypeName;
+ if (!RSExportType::NormalizeType(T, TypeName, &mDiagEngine, VD)) {
+ mValid = false;
+ }
+ }
+
+ if (!RSExportType::ValidateVarDecl(VD, mTargetAPI, mIsFilterscript)) {
+ mValid = false;
+ } else if (clang::Expr *Init = VD->getInit()) {
+ // Only check the initializer if the decl is already ok.
+ Visit(Init);
+ }
+}
+
+
+void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) {
+ if (!SlangRS::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) {
+ for (clang::DeclStmt::decl_iterator I = DS->decl_begin(),
+ E = DS->decl_end();
+ I != E;
+ ++I) {
+ if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) {
+ ValidateVarDecl(VD);
+ } else if (clang::FunctionDecl *FD =
+ llvm::dyn_cast<clang::FunctionDecl>(*I)) {
+ ValidateFunctionDecl(FD);
+ }
+ }
+ }
+}
+
+
+void RSCheckAST::VisitExpr(clang::Expr *E) {
+ // This is where FS checks for code using pointer and/or 64-bit expressions
+ // (i.e. things like casts).
+
+ // First we skip implicit casts (things like function calls and explicit
+ // array accesses rely heavily on them and they are valid.
+ E = E->IgnoreImpCasts();
+ if (mIsFilterscript &&
+ !SlangRS::IsLocInRSHeaderFile(E->getExprLoc(), mSM) &&
+ !RSExportType::ValidateType(C, E->getType(), NULL, E->getExprLoc(),
+ mTargetAPI, mIsFilterscript)) {
+ mValid = false;
+ } else {
+ // Only visit sub-expressions if we haven't already seen a violation.
+ VisitStmt(E);
+ }
+}
+
+
+bool RSCheckAST::Validate() {
+ clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
+ for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
+ DE = TUDecl->decls_end();
+ DI != DE;
+ DI++) {
+ if (!SlangRS::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) {
+ if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI)) {
+ ValidateVarDecl(VD);
+ } else if (clang::FunctionDecl *FD =
+ llvm::dyn_cast<clang::FunctionDecl>(*DI)) {
+ ValidateFunctionDecl(FD);
+ } else if (clang::Stmt *Body = (*DI)->getBody()) {
+ Visit(Body);
+ }
+ }
+ }
+
+ return mValid;
+}
+
+} // namespace slang
diff --git a/slang_rs_check_ast.h b/slang_rs_check_ast.h
new file mode 100644
index 0000000..6a76360
--- /dev/null
+++ b/slang_rs_check_ast.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_CHECK_AST_H_ // NOLINT
+#define _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_CHECK_AST_H_
+
+#include "slang_assert.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/StmtVisitor.h"
+
+namespace slang {
+
+// This class is designed to walk a Renderscript/Filterscript AST looking for
+// violations. Examples of violations for FS are pointer declarations and
+// casts (i.e. no pointers allowed in FS whatsoever).
+class RSCheckAST : public clang::StmtVisitor<RSCheckAST> {
+ private:
+ clang::ASTContext &C;
+ clang::DiagnosticsEngine &mDiagEngine;
+ clang::SourceManager &mSM;
+ bool mValid;
+ unsigned int mTargetAPI;
+ bool mIsFilterscript;
+
+ public:
+ explicit RSCheckAST(clang::ASTContext &Con, unsigned int TargetAPI,
+ bool IsFilterscript)
+ : C(Con), mDiagEngine(Con.getDiagnostics()), mSM(C.getSourceManager()),
+ mValid(true), mTargetAPI(TargetAPI), mIsFilterscript(IsFilterscript) {
+ return;
+ }
+
+ void VisitStmt(clang::Stmt *S);
+
+ void VisitExpr(clang::Expr *E);
+
+ void VisitDeclStmt(clang::DeclStmt *DS);
+
+ void ValidateFunctionDecl(clang::FunctionDecl *FD);
+
+ void ValidateVarDecl(clang::VarDecl *VD);
+
+ bool Validate();
+};
+
+} // namespace slang
+
+#endif // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_CHECK_AST_H_ NOLINT
diff --git a/slang_rs_export_type.cpp b/slang_rs_export_type.cpp
index 2d35ef6..94bd6bb 100644
--- a/slang_rs_export_type.cpp
+++ b/slang_rs_export_type.cpp
@@ -89,7 +89,7 @@
const clang::RecordDecl *TopLevelRecord);
static void ReportTypeError(clang::DiagnosticsEngine *DiagEngine,
- const clang::VarDecl *VD,
+ const clang::NamedDecl *ND,
const clang::RecordDecl *TopLevelRecord,
const char *Message,
unsigned int TargetAPI = 0) {
@@ -107,11 +107,11 @@
clang::FullSourceLoc(TopLevelRecord->getLocation(), SM),
DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, Message))
<< TopLevelRecord->getName() << TargetAPI;
- } else if (VD) {
+ } else if (ND) {
DiagEngine->Report(
- clang::FullSourceLoc(VD->getLocation(), SM),
+ clang::FullSourceLoc(ND->getLocation(), SM),
DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, Message))
- << VD->getName() << TargetAPI;
+ << ND->getName() << TargetAPI;
} else {
slangAssert(false && "Variables should be validated before exporting");
}
@@ -337,7 +337,7 @@
// Only if we are already in a composite type (like an array or structure).
if (InCompositeType) {
// Only if we are actually exported (i.e. non-static).
- if (VD->getLinkage() == clang::ExternalLinkage) {
+ if (VD->hasLinkage() && (VD->getLinkage() == clang::ExternalLinkage)) {
// Only if we are not a pointer to an object.
const clang::Type *T = GET_CANONICAL_TYPE(VD->getType().getTypePtr());
if (T->getTypeClass() != clang::Type::Pointer) {
@@ -355,25 +355,30 @@
return true;
}
-// Helper function for ValidateVarDecl(). We do a recursive descent on the
+// Helper function for ValidateType(). We do a recursive descent on the
// type hierarchy to ensure that we can properly export/handle the
// declaration.
// \return true if the variable declaration is valid,
// false if it is invalid (along with proper diagnostics).
//
-// VD - top-level variable declaration that we are validating.
-// T - sub-type of VD's type that we are validating.
+// C - ASTContext (for diagnostics + builtin types).
+// T - sub-type that we are validating.
+// ND - (optional) top-level named declaration that we are validating.
// SPS - set of types we have already seen/validated.
// InCompositeType - true if we are within an outer composite type.
// UnionDecl - set if we are in a sub-type of a union.
// TargetAPI - target SDK API level.
-static bool ValidateVarDeclHelper(
- clang::VarDecl *VD,
+// IsFilterscript - whether or not we are compiling for Filterscript
+static bool ValidateTypeHelper(
+ clang::ASTContext &C,
const clang::Type *&T,
+ clang::NamedDecl *ND,
+ clang::SourceLocation Loc,
llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
bool InCompositeType,
clang::RecordDecl *UnionDecl,
- unsigned int TargetAPI) {
+ unsigned int TargetAPI,
+ bool IsFilterscript) {
if ((T = GET_CANONICAL_TYPE(T)) == NULL)
return true;
@@ -383,7 +388,8 @@
switch (T->getTypeClass()) {
case clang::Type::Record: {
if (RSExportPrimitiveType::IsRSObjectType(T)) {
- if (!ValidateRSObjectInVarDecl(VD, InCompositeType, TargetAPI)) {
+ clang::VarDecl *VD = (ND ? llvm::dyn_cast<clang::VarDecl>(ND) : NULL);
+ if (VD && !ValidateRSObjectInVarDecl(VD, InCompositeType, TargetAPI)) {
return false;
}
}
@@ -393,8 +399,7 @@
if (!UnionDecl) {
return true;
} else if (RSExportPrimitiveType::IsRSObjectType(T)) {
- clang::ASTContext &C = VD->getASTContext();
- ReportTypeError(&C.getDiagnostics(), VD, UnionDecl,
+ ReportTypeError(&C.getDiagnostics(), NULL, UnionDecl,
"unions containing RS object types are not allowed");
return false;
}
@@ -437,7 +442,8 @@
const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
FT = GET_CANONICAL_TYPE(FT);
- if (!ValidateVarDeclHelper(VD, FT, SPS, true, UnionDecl, TargetAPI)) {
+ if (!ValidateTypeHelper(C, FT, ND, Loc, SPS, true, UnionDecl,
+ TargetAPI, IsFilterscript)) {
return false;
}
}
@@ -446,16 +452,58 @@
}
case clang::Type::Builtin: {
+ if (IsFilterscript) {
+ clang::QualType QT = T->getCanonicalTypeInternal();
+ if (QT == C.DoubleTy ||
+ QT == C.LongDoubleTy ||
+ QT == C.LongTy ||
+ QT == C.LongLongTy) {
+ clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
+ if (ND) {
+ DiagEngine.Report(
+ clang::FullSourceLoc(Loc, C.getSourceManager()),
+ DiagEngine.getCustomDiagID(
+ clang::DiagnosticsEngine::Error,
+ "Builtin types > 32 bits in size are forbidden in "
+ "Filterscript: '%0'")) << ND->getName();
+ } else {
+ DiagEngine.Report(
+ clang::FullSourceLoc(Loc, C.getSourceManager()),
+ DiagEngine.getCustomDiagID(
+ clang::DiagnosticsEngine::Error,
+ "Builtin types > 32 bits in size are forbidden in "
+ "Filterscript"));
+ }
+ return false;
+ }
+ }
break;
}
case clang::Type::Pointer: {
+ if (IsFilterscript) {
+ if (ND) {
+ clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
+ DiagEngine.Report(
+ clang::FullSourceLoc(Loc, C.getSourceManager()),
+ DiagEngine.getCustomDiagID(
+ clang::DiagnosticsEngine::Error,
+ "Pointers are forbidden in Filterscript: '%0'")) << ND->getName();
+ return false;
+ } else {
+ // TODO(srhines): Find a better way to handle expressions (i.e. no
+ // NamedDecl) involving pointers in FS that should be allowed.
+ // An example would be calls to library functions like
+ // rsMatrixMultiply() that take rs_matrixNxN * types.
+ }
+ }
+
const clang::PointerType *PT =
UNSAFE_CAST_TYPE(const clang::PointerType, T);
const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
- return ValidateVarDeclHelper(VD, PointeeType, SPS, InCompositeType,
- UnionDecl, TargetAPI);
+ return ValidateTypeHelper(C, PointeeType, ND, Loc, SPS, InCompositeType,
+ UnionDecl, TargetAPI, IsFilterscript);
}
case clang::Type::ExtVector: {
@@ -465,22 +513,21 @@
if (TargetAPI < SLANG_ICS_TARGET_API &&
InCompositeType &&
EVT->getNumElements() == 3) {
- clang::ASTContext &C = VD->getASTContext();
- ReportTypeError(&C.getDiagnostics(), VD, NULL,
+ ReportTypeError(&C.getDiagnostics(), ND, NULL,
"structs containing vectors of dimension 3 cannot "
"be exported at this API level: '%0'");
return false;
}
- return ValidateVarDeclHelper(VD, ElementType, SPS, true, UnionDecl,
- TargetAPI);
+ return ValidateTypeHelper(C, ElementType, ND, Loc, SPS, true, UnionDecl,
+ TargetAPI, IsFilterscript);
}
case clang::Type::ConstantArray: {
const clang::ConstantArrayType *CAT =
UNSAFE_CAST_TYPE(const clang::ConstantArrayType, T);
const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
- return ValidateVarDeclHelper(VD, ElementType, SPS, true, UnionDecl,
- TargetAPI);
+ return ValidateTypeHelper(C, ElementType, ND, Loc, SPS, true, UnionDecl,
+ TargetAPI, IsFilterscript);
}
default: {
@@ -523,12 +570,22 @@
return true;
}
-bool RSExportType::ValidateVarDecl(clang::VarDecl *VD, unsigned int TargetAPI) {
- const clang::Type *T = VD->getType().getTypePtr();
+bool RSExportType::ValidateType(clang::ASTContext &C, clang::QualType QT,
+ clang::NamedDecl *ND, clang::SourceLocation Loc, unsigned int TargetAPI,
+ bool IsFilterscript) {
+ const clang::Type *T = QT.getTypePtr();
llvm::SmallPtrSet<const clang::Type*, 8> SPS =
llvm::SmallPtrSet<const clang::Type*, 8>();
- return ValidateVarDeclHelper(VD, T, SPS, false, NULL, TargetAPI);
+ return ValidateTypeHelper(C, T, ND, Loc, SPS, false, NULL, TargetAPI,
+ IsFilterscript);
+ return true;
+}
+
+bool RSExportType::ValidateVarDecl(clang::VarDecl *VD, unsigned int TargetAPI,
+ bool IsFilterscript) {
+ return ValidateType(VD->getASTContext(), VD->getType(), VD,
+ VD->getLocation(), TargetAPI, IsFilterscript);
}
const clang::Type
diff --git a/slang_rs_export_type.h b/slang_rs_export_type.h
index ea1a885..e9af953 100644
--- a/slang_rs_export_type.h
+++ b/slang_rs_export_type.h
@@ -157,9 +157,18 @@
clang::DiagnosticsEngine *Diags,
const clang::VarDecl *VD);
+ // This function checks whether the specified type can be handled by RS/FS.
+ // If it cannot, this function returns false. Otherwise it returns true.
+ // Filterscript has additional restrictions on supported types.
+ static bool ValidateType(clang::ASTContext &C, clang::QualType QT,
+ clang::NamedDecl *ND, clang::SourceLocation Loc,
+ unsigned int TargetAPI, bool IsFilterscript);
+
// This function ensures that the VarDecl can be properly handled by RS.
// If it cannot, this function returns false. Otherwise it returns true.
- static bool ValidateVarDecl(clang::VarDecl *VD, unsigned int TargetAPI);
+ // Filterscript has additional restrictions on supported types.
+ static bool ValidateVarDecl(clang::VarDecl *VD, unsigned int TargetAPI,
+ bool IsFilterscript);
// @T may not be normalized
static RSExportType *Create(RSContext *Context, const clang::Type *T);
diff --git a/tests/F_fs_oldkernel/fs_oldkernel.fs b/tests/F_fs_oldkernel/fs_oldkernel.fs
new file mode 100644
index 0000000..4f607a5
--- /dev/null
+++ b/tests/F_fs_oldkernel/fs_oldkernel.fs
@@ -0,0 +1,10 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void old_kernel(const uint32_t *ain, uint32_t x, uint32_t y) {
+}
+
+uint32_t* bad_kernel(const uint32_t *ain, uint32_t x, uint32_t y) {
+ return 0;
+}
+
diff --git a/tests/F_fs_oldkernel/stderr.txt.expect b/tests/F_fs_oldkernel/stderr.txt.expect
new file mode 100644
index 0000000..5b53b56
--- /dev/null
+++ b/tests/F_fs_oldkernel/stderr.txt.expect
@@ -0,0 +1,3 @@
+fs_oldkernel.fs:4:17: error: Pointers are forbidden in Filterscript: 'ain'
+fs_oldkernel.fs:7:1: error: Pointers are forbidden in Filterscript: 'bad_kernel'
+fs_oldkernel.fs:7:22: error: Pointers are forbidden in Filterscript: 'ain'
diff --git a/tests/F_fs_oldkernel/stdout.txt.expect b/tests/F_fs_oldkernel/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_fs_oldkernel/stdout.txt.expect
diff --git a/tests/F_fs_ptr/fs_ptr.fs b/tests/F_fs_ptr/fs_ptr.fs
new file mode 100644
index 0000000..7ae49eb
--- /dev/null
+++ b/tests/F_fs_ptr/fs_ptr.fs
@@ -0,0 +1,39 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int *i;
+
+struct f {
+ int i;
+ float *pf;
+ char c;
+ short *ps;
+};
+
+int ia[10];
+
+int __attribute__((kernel)) root(uint32_t ain) {
+ char *c;
+
+ c = (char*) ain; // TODO(srhines): This is ok today.
+ return 0;
+}
+
+void __attribute__((kernel)) in_only(uint32_t ain) {
+}
+
+int __attribute__((kernel)) out_only() {
+ return 0;
+}
+
+int __attribute__((kernel)) everything(uint32_t ain, uint32_t x, uint32_t y) {
+ return (int)&ain; // TODO(srhines): This is ok today.
+}
+
+void old_kernel(const uint32_t *ain, uint32_t x, uint32_t y) {
+}
+
+void test_call() {
+ int i = root(ia[4]);
+}
+
diff --git a/tests/F_fs_ptr/stderr.txt.expect b/tests/F_fs_ptr/stderr.txt.expect
new file mode 100644
index 0000000..2ff21f9
--- /dev/null
+++ b/tests/F_fs_ptr/stderr.txt.expect
@@ -0,0 +1,3 @@
+fs_ptr.fs:4:6: error: Pointers are forbidden in Filterscript: 'i'
+fs_ptr.fs:16:9: error: Pointers are forbidden in Filterscript: 'c'
+fs_ptr.fs:33:17: error: Pointers are forbidden in Filterscript: 'ain'
diff --git a/tests/F_fs_ptr/stdout.txt.expect b/tests/F_fs_ptr/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_fs_ptr/stdout.txt.expect
diff --git a/tests/F_fs_types/fs_types.fs b/tests/F_fs_types/fs_types.fs
new file mode 100644
index 0000000..12c22ce
--- /dev/null
+++ b/tests/F_fs_types/fs_types.fs
@@ -0,0 +1,38 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+double d;
+
+struct s {
+ int i;
+ double d;
+ char c;
+ long l;
+};
+
+struct s myS;
+
+void foo_d(double d) {
+ double e;
+ float f = 0.0;
+ e = d;
+}
+
+void foo_l(long l) {
+ long m;
+ int i = 1l;
+ m = l;
+}
+
+void foo_ll(long long l) {
+ long long m;
+ int i = 1ll;
+ m = l;
+}
+
+void foo_ld(long double l) {
+ long double m;
+ float f = 0.0L;
+ m = l;
+}
+
diff --git a/tests/F_fs_types/stderr.txt.expect b/tests/F_fs_types/stderr.txt.expect
new file mode 100644
index 0000000..9422d76
--- /dev/null
+++ b/tests/F_fs_types/stderr.txt.expect
@@ -0,0 +1,18 @@
+fs_types.fs:4:8: error: Builtin types > 32 bits in size are forbidden in Filterscript: 'd'
+fs_types.fs:13:10: error: Builtin types > 32 bits in size are forbidden in Filterscript: 'myS'
+fs_types.fs:15:12: error: Builtin types > 32 bits in size are forbidden in Filterscript: 'd'
+fs_types.fs:16:12: error: Builtin types > 32 bits in size are forbidden in Filterscript: 'e'
+fs_types.fs:17:15: error: Builtin types > 32 bits in size are forbidden in Filterscript
+fs_types.fs:18:7: error: Builtin types > 32 bits in size are forbidden in Filterscript
+fs_types.fs:21:12: error: Builtin types > 32 bits in size are forbidden in Filterscript: 'l'
+fs_types.fs:22:10: error: Builtin types > 32 bits in size are forbidden in Filterscript: 'm'
+fs_types.fs:23:13: error: Builtin types > 32 bits in size are forbidden in Filterscript
+fs_types.fs:24:7: error: Builtin types > 32 bits in size are forbidden in Filterscript
+fs_types.fs:27:13: error: Builtin types > 32 bits in size are forbidden in Filterscript: 'l'
+fs_types.fs:28:15: error: Builtin types > 32 bits in size are forbidden in Filterscript: 'm'
+fs_types.fs:29:13: error: Builtin types > 32 bits in size are forbidden in Filterscript
+fs_types.fs:30:7: error: Builtin types > 32 bits in size are forbidden in Filterscript
+fs_types.fs:33:13: error: Builtin types > 32 bits in size are forbidden in Filterscript: 'l'
+fs_types.fs:34:17: error: Builtin types > 32 bits in size are forbidden in Filterscript: 'm'
+fs_types.fs:35:15: error: Builtin types > 32 bits in size are forbidden in Filterscript
+fs_types.fs:36:7: error: Builtin types > 32 bits in size are forbidden in Filterscript
diff --git a/tests/F_fs_types/stdout.txt.expect b/tests/F_fs_types/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_fs_types/stdout.txt.expect
diff --git a/tests/F_union/stderr.txt.expect b/tests/F_union/stderr.txt.expect
index 1848917..2bf177d 100644
--- a/tests/F_union/stderr.txt.expect
+++ b/tests/F_union/stderr.txt.expect
@@ -1,2 +1,3 @@
union.rs:4:7: error: unions cannot be exported: 'u'
union.rs:9:14: error: unions containing RS object types are not allowed
+union.rs:16:11: error: unions containing RS object types are not allowed
diff --git a/tests/F_union/union.rs b/tests/F_union/union.rs
index aee4948..c6d423c 100644
--- a/tests/F_union/union.rs
+++ b/tests/F_union/union.rs
@@ -11,3 +11,11 @@
rs_font f;
} myUnion2;
+
+void foo() {
+ union iu {
+ rs_font f;
+ int i;
+ } v;
+ (void) v;
+}
diff --git a/tests/P_fs_kernel/fs_kernel.fs b/tests/P_fs_kernel/fs_kernel.fs
new file mode 100644
index 0000000..d8f0c4d
--- /dev/null
+++ b/tests/P_fs_kernel/fs_kernel.fs
@@ -0,0 +1,18 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int __attribute__((kernel)) root(uint32_t ain) {
+ return 0;
+}
+
+void __attribute__((kernel)) in_only(uint32_t ain) {
+}
+
+int __attribute__((kernel)) out_only() {
+ return 0;
+}
+
+int __attribute__((kernel)) everything(uint32_t ain, uint32_t x, uint32_t y) {
+ return 0;
+}
+
diff --git a/tests/P_fs_kernel/stderr.txt.expect b/tests/P_fs_kernel/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_fs_kernel/stderr.txt.expect
diff --git a/tests/P_fs_kernel/stdout.txt.expect b/tests/P_fs_kernel/stdout.txt.expect
new file mode 100644
index 0000000..4a8eafd
--- /dev/null
+++ b/tests/P_fs_kernel/stdout.txt.expect
@@ -0,0 +1 @@
+Generating ScriptC_fs_kernel.java ...
diff --git a/tests/test.py b/tests/test.py
index 44327e8..7392cf6 100755
--- a/tests/test.py
+++ b/tests/test.py
@@ -75,6 +75,8 @@
'-I ../../../../../external/clang/lib/Headers/')
base_args = cmd_string.split()
rs_files = glob.glob('*.rs')
+ fs_files = glob.glob('*.fs')
+ rs_files += fs_files;
rs_files.sort()
# Extra command line arguments can be placed as // comments at the start of