Author: nico Date: Thu Mar 14 07:18:56 2019 New Revision: 356148 URL: http://llvm.org/viewvc/llvm-project?rev=356148&view=rev Log: Objective-C++11: Support static_assert() in @interface/@implementation ivar lists and method declarations
This adds support for static_assert() (and _Static_assert()) in @interface/@implementation ivar lists and in @interface method declarations. It was already supported in @implementation blocks outside of the ivar lists. The assert AST nodes are added at file scope, matching where other (non-Objective-C) declarations at @interface / @implementation level go (cf `allTUVariables`). Also add a `__has_feature(objc_c_static_assert)` that's true in C11 (and `__has_extension(objc_c_static_assert)` that's always true) and `__has_feature(objc_cxx_static_assert)` that's true in C++11 modea fter this patch, so it's possible to check if this is supported. Differential Revision: https://reviews.llvm.org/D59223 Added: cfe/trunk/test/Parser/objc-static-assert.m cfe/trunk/test/Parser/objc-static-assert.mm Modified: cfe/trunk/include/clang/Basic/Features.def cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/lib/Parse/ParseObjc.cpp cfe/trunk/lib/Sema/SemaExpr.cpp Modified: cfe/trunk/include/clang/Basic/Features.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Features.def?rev=356148&r1=356147&r2=356148&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Features.def (original) +++ cfe/trunk/include/clang/Basic/Features.def Thu Mar 14 07:18:56 2019 @@ -116,6 +116,9 @@ FEATURE(objc_bridge_id_on_typedefs, true FEATURE(objc_generics, LangOpts.ObjC) FEATURE(objc_generics_variance, LangOpts.ObjC) FEATURE(objc_class_property, LangOpts.ObjC) +FEATURE(objc_c_static_assert, LangOpts.C11) +FEATURE(objc_cxx_static_assert, LangOpts.CPlusPlus11) +EXTENSION(objc_c_static_assert, true) // C11 features FEATURE(c_alignas, LangOpts.C11) FEATURE(c_alignof, LangOpts.C11) Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=356148&r1=356147&r2=356148&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Mar 14 07:18:56 2019 @@ -3889,6 +3889,9 @@ void Parser::ParseDeclarationSpecifiers( /// ParseStructDeclaration - Parse a struct declaration without the terminating /// semicolon. /// +/// Note that a struct declaration refers to a declaration in a struct, +/// not to the declaration of a struct. +/// /// struct-declaration: /// [C2x] attributes-specifier-seq[opt] /// specifier-qualifier-list struct-declarator-list Modified: cfe/trunk/lib/Parse/ParseObjc.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=356148&r1=356147&r2=356148&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseObjc.cpp (original) +++ cfe/trunk/lib/Parse/ParseObjc.cpp Thu Mar 14 07:18:56 2019 @@ -623,6 +623,8 @@ void Parser::ParseObjCInterfaceDeclList( } // Ignore excess semicolons. if (Tok.is(tok::semi)) { + // FIXME: This should use ConsumeExtraSemi() for extraneous semicolons, + // to make -Wextra-semi diagnose them. ConsumeToken(); continue; } @@ -646,7 +648,19 @@ void Parser::ParseObjCInterfaceDeclList( // erroneous r_brace would cause an infinite loop if not handled here. if (Tok.is(tok::r_brace)) break; + ParsedAttributesWithRange attrs(AttrFactory); + + // Since we call ParseDeclarationOrFunctionDefinition() instead of + // ParseExternalDeclaration() below (so that this doesn't parse nested + // @interfaces), this needs to duplicate some code from the latter. + if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) { + SourceLocation DeclEnd; + allTUVariables.push_back( + ParseDeclaration(DeclaratorContext::FileContext, DeclEnd, attrs)); + continue; + } + allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs)); continue; } @@ -1875,6 +1889,7 @@ void Parser::HelperActionsForIvarDeclara /// ';' /// objc-instance-variable-decl-list objc-visibility-spec /// objc-instance-variable-decl-list objc-instance-variable-decl ';' +/// objc-instance-variable-decl-list static_assert-declaration /// objc-instance-variable-decl-list ';' /// /// objc-visibility-spec: @@ -1945,6 +1960,15 @@ void Parser::ParseObjCClassInstanceVaria return cutOffParsing(); } + // This needs to duplicate a small amount of code from + // ParseStructUnionBody() for things that should work in both + // C struct and in Objective-C class instance variables. + if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) { + SourceLocation DeclEnd; + ParseStaticAssertDeclaration(DeclEnd); + continue; + } + auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) { Actions.ActOnObjCContainerStartDefinition(interfaceDecl); // Install the declarator into the interface decl. Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=356148&r1=356147&r2=356148&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Mar 14 07:18:56 2019 @@ -2998,7 +2998,6 @@ ExprResult Sema::BuildDeclarationNameExp // These shouldn't make it here. case Decl::ObjCAtDefsField: - case Decl::ObjCIvar: llvm_unreachable("forming non-member reference to ivar?"); // Enum constants are always r-values and never references. @@ -3016,6 +3015,7 @@ ExprResult Sema::BuildDeclarationNameExp // exist in the high-level semantics. case Decl::Field: case Decl::IndirectField: + case Decl::ObjCIvar: assert(getLangOpts().CPlusPlus && "building reference to field in C?"); Added: cfe/trunk/test/Parser/objc-static-assert.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objc-static-assert.m?rev=356148&view=auto ============================================================================== --- cfe/trunk/test/Parser/objc-static-assert.m (added) +++ cfe/trunk/test/Parser/objc-static-assert.m Thu Mar 14 07:18:56 2019 @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -fobjc-runtime=macosx-fragile -fsyntax-only -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -std=c89 -fobjc-runtime=macosx-fragile -fsyntax-only -verify -Wno-objc-root-class %s + + +#if __STDC_VERSION__ >= 201112L + +#if !__has_feature(objc_c_static_assert) +#error failed +#endif + +#if !__has_extension(objc_c_static_assert) +#error failed +#endif + +@interface A { + int a; + _Static_assert(1, ""); + _Static_assert(0, ""); // expected-error {{static_assert failed}} + + _Static_assert(a, ""); // expected-error {{use of undeclared identifier 'a'}} + _Static_assert(sizeof(a), ""); // expected-error {{use of undeclared identifier 'a'}} +} + +_Static_assert(1, ""); + +@end + +struct S { + @defs(A); +}; + +#else + +// _Static_assert is available before C11 as an extension, but -pedantic +// warns on it. +#if __has_feature(objc_c_static_assert) +#error failed +#endif + +#if !__has_extension(objc_c_static_assert) +#error failed +#endif + +@interface A { + int a; + _Static_assert(1, ""); + _Static_assert(0, ""); // expected-error {{static_assert failed}} +} + +_Static_assert(1, ""); + +@end + +#endif Added: cfe/trunk/test/Parser/objc-static-assert.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objc-static-assert.mm?rev=356148&view=auto ============================================================================== --- cfe/trunk/test/Parser/objc-static-assert.mm (added) +++ cfe/trunk/test/Parser/objc-static-assert.mm Thu Mar 14 07:18:56 2019 @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify -Wno-objc-root-class %s + +#if !__has_feature(objc_c_static_assert) +#error failed +#endif + +#if __cplusplus >= 201103L + +#if !__has_feature(objc_cxx_static_assert) +#error failed +#endif + +// C++11 + +@interface A { + int a; + static_assert(1, ""); + _Static_assert(1, ""); + + static_assert(0, ""); // expected-error {{static_assert failed}} + _Static_assert(0, ""); // expected-error {{static_assert failed}} + + static_assert(a, ""); // expected-error {{static_assert expression is not an integral constant expression}} + static_assert(sizeof(a) == 4, ""); + static_assert(sizeof(a) == 3, ""); // expected-error {{static_assert failed}} +} + +static_assert(1, ""); +_Static_assert(1, ""); + +- (void)f; +@end + +@implementation A { + int b; + static_assert(1, ""); + _Static_assert(1, ""); + static_assert(sizeof(b) == 4, ""); + static_assert(sizeof(b) == 3, ""); // expected-error {{static_assert failed}} +} + +static_assert(1, ""); + +- (void)f { + static_assert(1, ""); +} +@end + +@interface B +@end + +@interface B () { + int b; + static_assert(sizeof(b) == 4, ""); + static_assert(sizeof(b) == 3, ""); // expected-error {{static_assert failed}} +} +@end + +#else + +#if __has_feature(objc_cxx_static_assert) +#error failed +#endif + +// C++98 +@interface A { + int a; + static_assert(1, ""); // expected-error {{type name requires a specifier or qualifier}} expected-error{{expected parameter declarator}} expected-error {{expected ')'}} expected-note {{to match this '('}} + _Static_assert(1, ""); + _Static_assert(0, ""); // expected-error {{static_assert failed}} +} +@end +#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits