Author: rtrieu Date: Fri Jan 19 12:46:19 2018 New Revision: 322984 URL: http://llvm.org/viewvc/llvm-project?rev=322984&view=rev Log: Allow BlockDecl in CXXRecord scope to have no access specifier.
Using a BlockDecl in a default member initializer causes it to be attached to CXXMethodDecl without its access specifier being set. This prevents a crash where getAccess is called on this BlockDecl, since that method expects any Decl in CXXRecord scope to have an access specifier. Added: cfe/trunk/test/Modules/odr_hash-blocks.cpp Modified: cfe/trunk/lib/AST/DeclBase.cpp Modified: cfe/trunk/lib/AST/DeclBase.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=322984&r1=322983&r2=322984&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclBase.cpp (original) +++ cfe/trunk/lib/AST/DeclBase.cpp Fri Jan 19 12:46:19 2018 @@ -891,12 +891,14 @@ bool Decl::AccessDeclContextSanity() con // 4. the context is not a record // 5. it's invalid // 6. it's a C++0x static_assert. + // 7. it's a block literal declaration if (isa<TranslationUnitDecl>(this) || isa<TemplateTypeParmDecl>(this) || isa<NonTypeTemplateParmDecl>(this) || !isa<CXXRecordDecl>(getDeclContext()) || isInvalidDecl() || isa<StaticAssertDecl>(this) || + isa<BlockDecl>(this) || // FIXME: a ParmVarDecl can have ClassTemplateSpecialization // as DeclContext (?). isa<ParmVarDecl>(this) || Added: cfe/trunk/test/Modules/odr_hash-blocks.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/odr_hash-blocks.cpp?rev=322984&view=auto ============================================================================== --- cfe/trunk/test/Modules/odr_hash-blocks.cpp (added) +++ cfe/trunk/test/Modules/odr_hash-blocks.cpp Fri Jan 19 12:46:19 2018 @@ -0,0 +1,119 @@ +// Clear and create directories +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: mkdir %t/cache +// RUN: mkdir %t/Inputs + +// Build first header file +// RUN: echo "#define FIRST" >> %t/Inputs/first.h +// RUN: cat %s >> %t/Inputs/first.h + +// Build second header file +// RUN: echo "#define SECOND" >> %t/Inputs/second.h +// RUN: cat %s >> %t/Inputs/second.h + +// Test that each header can compile +// RUN: %clang_cc1 -fsyntax-only -x c++ -std=c++11 -fblocks %t/Inputs/first.h +// RUN: %clang_cc1 -fsyntax-only -x c++ -std=c++11 -fblocks %t/Inputs/second.h + +// Build module map file +// RUN: echo "module FirstModule {" >> %t/Inputs/module.map +// RUN: echo " header \"first.h\"" >> %t/Inputs/module.map +// RUN: echo "}" >> %t/Inputs/module.map +// RUN: echo "module SecondModule {" >> %t/Inputs/module.map +// RUN: echo " header \"second.h\"" >> %t/Inputs/module.map +// RUN: echo "}" >> %t/Inputs/module.map + +// Run test +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps \ +// RUN: -fmodules-cache-path=%t/cache -x c++ -I%t/Inputs \ +// RUN: -verify %s -std=c++11 -fblocks + +#if !defined(FIRST) && !defined(SECOND) +#include "first.h" +#include "second.h" +#endif + +// Used for testing +#if defined(FIRST) +#define ACCESS public: +#elif defined(SECOND) +#define ACCESS private: +#endif + +// TODO: S1, S2, and S3 should generate errors. +namespace Blocks { +#if defined(FIRST) +struct S1 { + void (^block)(int x) = ^(int x) { }; +}; +#elif defined(SECOND) +struct S1 { + void (^block)(int x) = ^(int y) { }; +}; +#else +S1 s1; +#endif + +#if defined(FIRST) +struct S2 { + int (^block)(int x) = ^(int x) { return x + 1; }; +}; +#elif defined(SECOND) +struct S2 { + int (^block)(int x) = ^(int x) { return x; }; +}; +#else +S2 s2; +#endif + +#if defined(FIRST) +struct S3 { + void run(int (^block)(int x)); +}; +#elif defined(SECOND) +struct S3 { + void run(int (^block)(int x, int y)); +}; +#else +S3 s3; +#endif + +#define DECLS \ + int (^block)(int x) = ^(int x) { return x + x; }; \ + void run(int (^block)(int x, int y)); + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'Blocks::Invalid1' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}} +// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}} +#endif + +#undef DECLS +} + +// Keep macros contained to one file. +#ifdef FIRST +#undef FIRST +#endif + +#ifdef SECOND +#undef SECOND +#endif + +#ifdef ACCESS +#undef ACCESS +#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits