r356148 - Objective-C++11: Support static_assert() in @interface/@implementation ivar lists and method declarations
Nico Weber via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 14 07:18:56 PDT 2019
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
+
+ at 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, "");
+
+ at 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
+
+ at interface A {
+ int a;
+ _Static_assert(1, "");
+ _Static_assert(0, ""); // expected-error {{static_assert failed}}
+}
+
+_Static_assert(1, "");
+
+ at 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
+
+ at 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;
+ at end
+
+ at 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, "");
+}
+ at end
+
+ at interface B
+ at end
+
+ at interface B () {
+ int b;
+ static_assert(sizeof(b) == 4, "");
+ static_assert(sizeof(b) == 3, ""); // expected-error {{static_assert failed}}
+}
+ at end
+
+#else
+
+#if __has_feature(objc_cxx_static_assert)
+#error failed
+#endif
+
+// C++98
+ at 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}}
+}
+ at end
+#endif
More information about the cfe-commits
mailing list