Validate FS (and RS) ASTs.

This change adds a new RSCheckAST class that is used to handle validation
of the final AST. The checks include existing RS checks (for accepted types)
and new checks for Filterscript (like disallowing pointers, unions and
> 32 bit types completely). The refactoring also fixes a subtle union bug
that existed in prior versions of llvm-rs-cc. We also add an implicit
pragma for "rs_fp_relaxed" by default on Filterscript.

Bug: 7166741

Change-Id: Ia077783b4caba0bbd89df2ab3827e9f4d1009eea
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