]> granicus.if.org Git - clang/commitdiff
Callback support for OpenCL extension pragmas.
authorPekka Jaaskelainen <pekka.jaaskelainen@tut.fi>
Sat, 12 Oct 2013 09:29:48 +0000 (09:29 +0000)
committerPekka Jaaskelainen <pekka.jaaskelainen@tut.fi>
Sat, 12 Oct 2013 09:29:48 +0000 (09:29 +0000)
Patch from Rami Ylimäki and Mikael Lepistö!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192531 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Lex/PPCallbacks.h
lib/Parse/ParsePragma.cpp
unittests/Lex/CMakeLists.txt
unittests/Lex/Makefile
unittests/Lex/PPCallbacksTest.cpp

index 73cfb0aefc75005873c88adb6a7294d0504e4f44..0e112182794d89757b3611f536785c63e6c40d70 100644 (file)
@@ -217,6 +217,13 @@ public:
                                 diag::Mapping mapping, StringRef Str) {
   }
 
+  /// \brief Called when an OpenCL extension is either disabled or
+  /// enabled with a pragma.
+  virtual void PragmaOpenCLExtension(SourceLocation NameLoc, 
+                                     const IdentifierInfo *Name,
+                                     SourceLocation StateLoc, unsigned State) {
+  }
+
   /// \brief Callback invoked when a \#pragma warning directive is read.
   virtual void PragmaWarning(SourceLocation Loc, StringRef WarningSpec,
                              ArrayRef<int> Ids) {
@@ -413,6 +420,13 @@ public:
     Second->PragmaDiagnostic(Loc, Namespace, mapping, Str);
   }
 
+  virtual void PragmaOpenCLExtension(SourceLocation NameLoc, 
+                                     const IdentifierInfo *Name,
+                                     SourceLocation StateLoc, unsigned State) {
+    First->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State);
+    Second->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State);
+  }
+
   virtual void PragmaWarning(SourceLocation Loc, StringRef WarningSpec,
                              ArrayRef<int> Ids) {
     First->PragmaWarning(Loc, WarningSpec, Ids);
index 10ad5df629e0389ea646ebe4ac27fdf18c8a82cf..8a374e0fce61aa7a67282cb8ebb8a236d13d69e4 100644 (file)
@@ -728,6 +728,7 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
     PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable);
     return;
   }
+  SourceLocation StateLoc = Tok.getLocation();
 
   PP.Lex(Tok);
   if (Tok.isNot(tok::eod)) {
@@ -747,6 +748,10 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
   Toks[0].setAnnotationValue(data.getOpaqueValue());
   PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
                       /*OwnsTokens=*/false);
+
+  if (PP.getPPCallbacks())
+    PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, ename, 
+                                               StateLoc, state);
 }
 
 /// \brief Handle '#pragma omp ...' when OpenMP is disabled.
index 78838c082981ac40a2daffd26455043a702e3a94..cb3b9275dbdd897eef2826b307b110d965634d87 100644 (file)
@@ -5,5 +5,5 @@ add_clang_unittest(LexTests
   )
 
 target_link_libraries(LexTests
-  clangLex
+  clangLex clangParse clangSema
   )
index bb9c6bc3901db401c1e313ba737028c5ceb2d63d..fa233ce25f3339c112bb8574cda87cbdbd1dec03 100644 (file)
@@ -9,7 +9,8 @@
 
 CLANG_LEVEL = ../..
 TESTNAME = Lex
-LINK_COMPONENTS := support mc
-USEDLIBS = clangLex.a clangBasic.a
+LINK_COMPONENTS := mcparser support mc
+USEDLIBS = clangParse.a clangSema.a clangAnalysis.a clangEdit.a \
+       clangAST.a clangLex.a clangBasic.a 
 
 include $(CLANG_LEVEL)/unittests/Makefile
index 4e0a4331dc4bc985f3a0d65edc467199699b6ac0..8c6df1d00af329014f1a5808a0cd560089db2e4d 100644 (file)
 #include "clang/Lex/HeaderSearchOptions.h"
 #include "clang/Lex/ModuleLoader.h"
 #include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/Path.h"
 #include "gtest/gtest.h"
@@ -77,6 +81,31 @@ public:
   const Module* Imported;
 };
 
+// Stub to collect data from PragmaOpenCLExtension callbacks.
+class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
+public:
+  typedef struct {
+    StringRef Name;
+    unsigned State;
+  } CallbackParameters;
+
+  PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {};
+
+  void PragmaOpenCLExtension(
+    clang::SourceLocation NameLoc, const clang::IdentifierInfo *Name,
+    clang::SourceLocation StateLoc, unsigned State) {
+      this->NameLoc = NameLoc;
+      this->Name = Name->getName().str();
+      this->StateLoc = StateLoc;
+      this->State = State;
+  };
+
+  SourceLocation NameLoc;
+  StringRef Name;
+  SourceLocation StateLoc;
+  unsigned State;
+};
+
 // PPCallbacks test fixture.
 class PPCallbacksTest : public ::testing::Test {
 protected:
@@ -159,6 +188,53 @@ protected:
     // Callbacks have been executed at this point -- return filename range.
     return Callbacks->FilenameRange;
   }
+
+  PragmaOpenCLExtensionCallbacks::CallbackParameters 
+  PragmaOpenCLExtensionCall(const char* SourceText) {
+    LangOptions OpenCLLangOpts;
+    OpenCLLangOpts.OpenCL = 1;
+
+    MemoryBuffer* sourceBuf = MemoryBuffer::getMemBuffer(SourceText, "test.cl");
+    (void)SourceMgr.createMainFileIDForMemBuffer(sourceBuf);
+
+    VoidModuleLoader ModLoader;
+    HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, 
+                            OpenCLLangOpts, Target.getPtr());
+
+    Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, 
+                    Target.getPtr(),
+                    SourceMgr, HeaderInfo, ModLoader,
+                   /*IILookup =*/ 0,
+                    /*OwnsHeaderSearch =*/false,
+                    /*DelayInitialization =*/ false);
+
+    // parser actually sets correct pragma handlers for preprocessor
+    // according to LangOptions, so we init Parser to register opencl
+    // pragma handlers
+    ASTContext Context(OpenCLLangOpts, SourceMgr, Target.getPtr(), 
+                       PP.getIdentifierTable(), PP.getSelectorTable(), 
+                       PP.getBuiltinInfo(), 0);    
+    ASTConsumer Consumer;
+    Sema S(PP, Context, Consumer);
+    Parser P(PP, S, false);
+    PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
+    PP.addPPCallbacks(Callbacks); // Takes ownership.
+
+    // Lex source text.
+    PP.EnterMainSourceFile();
+    while (true) {
+      Token Tok;
+      PP.Lex(Tok);
+      if (Tok.is(tok::eof))
+        break;
+    }
+
+    PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
+      Callbacks->Name.str(),
+      Callbacks->State
+    };
+    return RetVal;    
+  }
 };
 
 TEST_F(PPCallbacksTest, QuotedFilename) {
@@ -247,4 +323,28 @@ TEST_F(PPCallbacksTest, TrigraphInMacro) {
   ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
 }
 
+TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
+  const char* Source =
+    "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
+
+  PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
+    PragmaOpenCLExtensionCall(Source);
+
+  ASSERT_EQ("cl_khr_fp64", Parameters.Name);
+  unsigned ExpectedState = 1;
+  ASSERT_EQ(ExpectedState, Parameters.State);
+}
+
+TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
+  const char* Source =
+    "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
+
+  PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
+    PragmaOpenCLExtensionCall(Source);
+
+  ASSERT_EQ("cl_khr_fp16", Parameters.Name);
+  unsigned ExpectedState = 0;
+  ASSERT_EQ(ExpectedState, Parameters.State);
+}
+
 } // anonoymous namespace