diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 0b14ed702412..1eedf639cecb 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -443,5 +443,9 @@ def warn_pragma_unused_expected_var : Warning< def warn_pragma_unused_expected_punc : Warning< "expected ')' or ',' in '#pragma unused'">; +// OpenCL Section 6.8.g +def err_not_opencl_storage_class_specifier : Error< + "OpenCL does not support the '%0' storage class specifier">; + } // end of Parse Issue category. } // end of Parser diagnostics diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index d95f3f78ca4b..9c4bb646949b 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -403,7 +403,7 @@ public: /// TODO: use a more general approach that still allows these /// diagnostics to be ignored when desired. bool SetStorageClassSpec(SCS S, SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID); + unsigned &DiagID, const LangOptions &Lang); bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index dfac16a082f1..d97b4e30a0ae 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1204,23 +1204,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // storage-class-specifier case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw_extern: if (DS.isThreadSpecified()) Diag(Tok, diag::ext_thread_before) << "extern"; isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw___private_extern__: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc, - PrevSpec, DiagID); + PrevSpec, DiagID, getLang()); break; case tok::kw_static: if (DS.isThreadSpecified()) Diag(Tok, diag::ext_thread_before) << "static"; isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw_auto: if (getLang().CPlusPlus0x) @@ -1228,15 +1228,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DiagID); else isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw_register: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw_mutable: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec, - DiagID); + DiagID, getLang()); break; case tok::kw___thread: isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID); diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 8a35ab70923f..bc289ec42c99 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -226,7 +226,25 @@ const char *DeclSpec::getSpecifierName(TQ T) { bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID) { + unsigned &DiagID, + const LangOptions &Lang) { + // OpenCL prohibits extern, auto, register, and static + // It seems sensible to prohibit private_extern too + if (Lang.OpenCL) { + switch (S) { + case SCS_extern: + case SCS_private_extern: + case SCS_auto: + case SCS_register: + case SCS_static: + DiagID = diag::err_not_opencl_storage_class_specifier; + PrevSpec = getSpecifierName(S); + return true; + default: + break; + } + } + if (StorageClassSpec != SCS_unspecified) { // Changing storage class is allowed only if the previous one // was the 'extern' that is part of a linkage specification and diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index d756de5e2db5..2807e759b56d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1922,7 +1922,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Recover by adding 'static'. DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), - PrevSpec, DiagID); + PrevSpec, DiagID, getLangOptions()); } // C++ [class.union]p3: // A storage class is not allowed in a declaration of an @@ -1935,7 +1935,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Recover by removing the storage specifier. DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(), - PrevSpec, DiagID); + PrevSpec, DiagID, getLangOptions()); } // C++ [class.union]p2: diff --git a/clang/test/Parser/cl_storage_class.cl b/clang/test/Parser/cl_storage_class.cl new file mode 100644 index 000000000000..5db8f4befa08 --- /dev/null +++ b/clang/test/Parser/cl_storage_class.cl @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 %s -x cl -verify -fsyntax-only + +void test_storage_class_specs() +{ + static int a; // expected-error {{OpenCL does not support the 'static' storage class specifier}} + register int b; // expected-error {{OpenCL does not support the 'register' storage class specifier}} + extern int c; // expected-error {{OpenCL does not support the 'extern' storage class specifier}} + auto int d; // expected-error {{OpenCL does not support the 'auto' storage class specifier}} +} diff --git a/clang/test/lit.cfg b/clang/test/lit.cfg index 13986a069b9f..6567c6d229cb 100644 --- a/clang/test/lit.cfg +++ b/clang/test/lit.cfg @@ -28,7 +28,7 @@ execute_external = platform.system() != 'Windows' config.test_format = lit.formats.ShTest(execute_external) # suffixes: A list of file extensions to treat as test files. -config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll'] +config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl'] # test_source_root: The root path where tests are located. config.test_source_root = os.path.dirname(__file__)