Merge "Fix expected stderr to refer to version 21." into lmp-dev
diff --git a/slang_rs_context.cpp b/slang_rs_context.cpp
index e9bb008..24fc204 100644
--- a/slang_rs_context.cpp
+++ b/slang_rs_context.cpp
@@ -61,20 +61,7 @@
       mMangleCtx(Ctx.createMangleContext()),
       mIs64Bit(Target.getPointerWidth(0) == 64) {
 
-  // For #pragma rs export_type
-  PP.AddPragmaHandler(
-      "rs", RSPragmaHandler::CreatePragmaExportTypeHandler(this));
-
-  // For #pragma rs java_package_name
-  PP.AddPragmaHandler(
-      "rs", RSPragmaHandler::CreatePragmaJavaPackageNameHandler(this));
-
-  // For #pragma rs set_reflect_license
-  PP.AddPragmaHandler(
-      "rs", RSPragmaHandler::CreatePragmaReflectLicenseHandler(this));
-
-  // For #pragma version
-  PP.AddPragmaHandler(RSPragmaHandler::CreatePragmaVersionHandler(this));
+  AddPragmaHandlers(PP, this);
 
   // Prepare target data
   mDataLayout = new llvm::DataLayout(Target.getTargetDescription());
diff --git a/slang_rs_context.h b/slang_rs_context.h
index 41f5979..82cee40 100644
--- a/slang_rs_context.h
+++ b/slang_rs_context.h
@@ -67,6 +67,9 @@
   clang::Preprocessor &mPP;
   clang::ASTContext &mCtx;
   PragmaList *mPragmas;
+  // Precision specified via pragma, either rs_fp_full or rs_fp_relaxed. If
+  // empty, rs_fp_full is assumed.
+  std::string mPrecision;
   unsigned int mTargetAPI;
   bool mVerbose;
 
@@ -234,6 +237,8 @@
   void addPragma(const std::string &T, const std::string &V) {
     mPragmas->push_back(make_pair(T, V));
   }
+  void setPrecision(const std::string &P) { mPrecision = P; }
+  std::string getPrecision() { return mPrecision; }
 
   // Report an error or a warning to the user.
   template <unsigned N>
diff --git a/slang_rs_pragma_handler.cpp b/slang_rs_pragma_handler.cpp
index c562ec3..03e2161 100644
--- a/slang_rs_pragma_handler.cpp
+++ b/slang_rs_pragma_handler.cpp
@@ -167,28 +167,48 @@
   }
 };
 
+// Handles the pragmas rs_fp_full, rs_fp_relaxed, and rs_fp_imprecise.
+// There's one instance of this handler for each of the above values.
+// Only getName() differs between the instances.
+class RSPrecisionPragmaHandler : public RSPragmaHandler {
+public:
+  RSPrecisionPragmaHandler(llvm::StringRef Name, RSContext *Context)
+      : RSPragmaHandler(Name, Context) {}
+
+  void HandlePragma(clang::Preprocessor &PP,
+                    clang::PragmaIntroducerKind Introducer,
+                    clang::Token &Token) {
+    std::string Precision = getName();
+    // We are deprecating rs_fp_imprecise.
+    if (Precision == "rs_fp_imprecise") {
+      PP.Diag(Token, PP.getDiagnostics().getCustomDiagID(
+                         clang::DiagnosticsEngine::Warning,
+                         "rs_fp_imprecise is deprecated.  Assuming "
+                         "rs_fp_relaxed instead."));
+      Precision = "rs_fp_relaxed";
+    }
+    // Check if we have already encountered a precision pragma already.
+    std::string PreviousPrecision = mContext->getPrecision();
+    if (!PreviousPrecision.empty()) {
+      // If the previous specified a different value, it's an error.
+      if (PreviousPrecision != Precision) {
+        PP.Diag(Token, PP.getDiagnostics().getCustomDiagID(
+                           clang::DiagnosticsEngine::Error,
+                           "Multiple float precisions specified.  Encountered "
+                           "%0 previously."))
+            << PreviousPrecision;
+      }
+      // Otherwise we ignore redundant entries.
+      return;
+    }
+
+    mContext->addPragma(Precision, "");
+    mContext->setPrecision(Precision);
+  }
+};
+
 }  // namespace
 
-RSPragmaHandler *
-RSPragmaHandler::CreatePragmaExportTypeHandler(RSContext *Context) {
-  return new RSExportTypePragmaHandler("export_type", Context);
-}
-
-RSPragmaHandler *
-RSPragmaHandler::CreatePragmaJavaPackageNameHandler(RSContext *Context) {
-  return new RSJavaPackageNamePragmaHandler("java_package_name", Context);
-}
-
-RSPragmaHandler *
-RSPragmaHandler::CreatePragmaReflectLicenseHandler(RSContext *Context) {
-  return new RSReflectLicensePragmaHandler("set_reflect_license", Context);
-}
-
-RSPragmaHandler *
-RSPragmaHandler::CreatePragmaVersionHandler(RSContext *Context) {
-  return new RSVersionPragmaHandler("version", Context);
-}
-
 void RSPragmaHandler::handleItemListPragma(clang::Preprocessor &PP,
                                            clang::Token &FirstToken) {
   clang::Token &PragmaToken = FirstToken;
@@ -321,4 +341,27 @@
   } while (PragmaToken.isNot(clang::tok::eod));
 }
 
+void AddPragmaHandlers(clang::Preprocessor &PP, RSContext *RsContext) {
+  // For #pragma rs export_type
+  PP.AddPragmaHandler("rs",
+                      new RSExportTypePragmaHandler("export_type", RsContext));
+
+  // For #pragma rs java_package_name
+  PP.AddPragmaHandler(
+      "rs", new RSJavaPackageNamePragmaHandler("java_package_name", RsContext));
+
+  // For #pragma rs set_reflect_license
+  PP.AddPragmaHandler(
+      "rs", new RSReflectLicensePragmaHandler("set_reflect_license", RsContext));
+
+  // For #pragma version
+  PP.AddPragmaHandler(new RSVersionPragmaHandler("version", RsContext));
+
+  // For #pragma rs_fp*
+  PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_full", RsContext));
+  PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_relaxed", RsContext));
+  PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_imprecise", RsContext));
+}
+
+
 }  // namespace slang
diff --git a/slang_rs_pragma_handler.h b/slang_rs_pragma_handler.h
index c960842..1b6fbe6 100644
--- a/slang_rs_pragma_handler.h
+++ b/slang_rs_pragma_handler.h
@@ -64,17 +64,15 @@
                                 clang::Token &FirstToken);
 
  public:
-  static RSPragmaHandler *CreatePragmaExportTypeHandler(RSContext *Context);
-  static RSPragmaHandler *CreatePragmaJavaPackageNameHandler(
-      RSContext *Context);
-  static RSPragmaHandler *CreatePragmaReflectLicenseHandler(RSContext *Context);
-  static RSPragmaHandler *CreatePragmaVersionHandler(RSContext *Context);
-
   virtual void HandlePragma(clang::Preprocessor &PP,
                             clang::PragmaIntroducerKind Introducer,
                             clang::Token &FirstToken) = 0;
 };
 
+// Add handlers for the RS pragmas to the preprocessor.  These handlers
+// validate the pragmas and, if valid, set fields of the RSContext.
+void AddPragmaHandlers(clang::Preprocessor &PP, RSContext *RsContext);
+
 }   // namespace slang
 
 #endif  // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_PRAGMA_HANDLER_H_  NOLINT
diff --git a/tests/F_rs_fp_two_pragmas/rs_fp_two_pragmas.rs b/tests/F_rs_fp_two_pragmas/rs_fp_two_pragmas.rs
new file mode 100644
index 0000000..b07091c
--- /dev/null
+++ b/tests/F_rs_fp_two_pragmas/rs_fp_two_pragmas.rs
@@ -0,0 +1,8 @@
+#pragma version(1)
+#pragma rs java_package_name(android.renderscript.cts)
+
+#pragma rs_fp_relaxed
+#pragma rs_fp_full
+
+
+
diff --git a/tests/F_rs_fp_two_pragmas/stderr.txt.expect b/tests/F_rs_fp_two_pragmas/stderr.txt.expect
new file mode 100644
index 0000000..6ad9b66
--- /dev/null
+++ b/tests/F_rs_fp_two_pragmas/stderr.txt.expect
@@ -0,0 +1 @@
+rs_fp_two_pragmas.rs:5:9: error: Multiple float precisions specified.  Encountered rs_fp_relaxed previously.
diff --git a/tests/F_rs_fp_two_pragmas/stdout.txt.expect b/tests/F_rs_fp_two_pragmas/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_rs_fp_two_pragmas/stdout.txt.expect
diff --git a/tests/P_rs_fp_full/rs_fp_full.rs b/tests/P_rs_fp_full/rs_fp_full.rs
new file mode 100644
index 0000000..35050fc
--- /dev/null
+++ b/tests/P_rs_fp_full/rs_fp_full.rs
@@ -0,0 +1,5 @@
+#pragma version(1)
+#pragma rs java_package_name(android.renderscript.cts)
+
+#pragma rs_fp_full
+
diff --git a/tests/P_rs_fp_full/stderr.txt.expect b/tests/P_rs_fp_full/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_rs_fp_full/stderr.txt.expect
diff --git a/tests/P_rs_fp_full/stdout.txt.expect b/tests/P_rs_fp_full/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_rs_fp_full/stdout.txt.expect
diff --git a/tests/P_rs_fp_imprecise/stderr.txt.expect b/tests/P_rs_fp_imprecise/stderr.txt.expect
index e69de29..0d86335 100644
--- a/tests/P_rs_fp_imprecise/stderr.txt.expect
+++ b/tests/P_rs_fp_imprecise/stderr.txt.expect
@@ -0,0 +1 @@
+rs_fp_imprecise.rs:4:9: warning: rs_fp_imprecise is deprecated.  Assuming rs_fp_relaxed instead.