inclyc updated this revision to Diff 459248.
inclyc added a comment.
Use RAII object to maintain the Parser state
> have you explored making a new DeclSpecContext and modifying
> isDefiningTypeSpecifierContext()? I think that would likely be a cleaner
> approach.
Emm, I've tried passing a DeclaratorContext into `ParseTypeName()`
SourceLocation TypeLoc = Tok.getLocation();
InBuiltInOffsetOfBaseRAIIObject InOffsetof(*this, true);
TypeResult Ty = ParseTypeName(nullptr, /*Context=???*/);
But defining a new DeclaratorContext I have to complete a bunch of `case`
statements.
// Parser.h
static bool isTypeSpecifier(DeclSpecContext DSC);
static AllowDefiningTypeSpec isDefiningTypeSpecifierContext(DeclSpecContext
DSC, bool IsCPlusPlus);
static bool isOpaqueEnumDeclarationContext(DeclSpecContext DSC);
/* ... */
And I think it is somehow strange to determine these properties within
__builtin_offsetof()? I'm not sure if it is really appropriate to define a
special context for a built-in function. This place should only need to
forbidden definitions, right?
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D133574/new/
https://reviews.llvm.org/D133574
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Parse/RAIIObjectsForParser.h
clang/include/clang/Sema/Sema.h
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Sema/SemaDecl.cpp
clang/test/Parser/declarators.c
clang/test/Sema/offsetof.c
Index: clang/test/Sema/offsetof.c
===================================================================
--- clang/test/Sema/offsetof.c
+++ clang/test/Sema/offsetof.c
@@ -70,3 +70,16 @@
return __builtin_offsetof(Array, array[*(int*)0]); // expected-warning{{indirection of non-volatile null pointer}} expected-note{{__builtin_trap}}
}
+// Reject definitions in __builtin_offsetof
+// https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2350.htm
+int test_definition(void) {
+ return __builtin_offsetof(struct A // expected-error{{'struct A' cannot be defined in '__builtin_offsetof'}}
+ {
+ int a;
+ struct B // expected-error{{'struct B' cannot be defined in '__builtin_offsetof'}}
+ {
+ int c;
+ int d;
+ } x;
+ }, a);
+}
Index: clang/test/Parser/declarators.c
===================================================================
--- clang/test/Parser/declarators.c
+++ clang/test/Parser/declarators.c
@@ -80,10 +80,6 @@
struct test10 { int a; } static test10x;
struct test11 { int a; } const test11x;
-// PR6216
-void test12(void) {
- (void)__builtin_offsetof(struct { char c; int i; }, i);
-}
// rdar://7608537
struct test13 { int a; } (test13x);
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -16254,7 +16254,7 @@
SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
bool IsTypeSpecifier, bool IsTemplateParamOrArg,
- SkipBodyInfo *SkipBody) {
+ SkipBodyInfo *SkipBody, bool IsWithinOffsetOf) {
// If this is not a definition, it must have a name.
IdentifierInfo *OrigName = Name;
assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -17027,6 +17027,12 @@
cast_or_null<RecordDecl>(PrevDecl));
}
+ if (IsWithinOffsetOf && TUK == TUK_Definition) {
+ Diag(New->getLocation(), diag::err_type_defined_in_offsetof)
+ << Context.getTagDeclType(New);
+ Invalid = true;
+ }
+
// C++11 [dcl.type]p3:
// A type-specifier-seq shall not define a class or enumeration [...].
if (getLangOpts().CPlusPlus && (IsTypeSpecifier || IsTemplateParamOrArg) &&
Index: clang/lib/Parse/ParseExpr.cpp
===================================================================
--- clang/lib/Parse/ParseExpr.cpp
+++ clang/lib/Parse/ParseExpr.cpp
@@ -2579,6 +2579,7 @@
}
case tok::kw___builtin_offsetof: {
SourceLocation TypeLoc = Tok.getLocation();
+ InBuiltInOffsetOfBaseRAIIObject InOffsetof(*this, true);
TypeResult Ty = ParseTypeName();
if (Ty.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -2030,7 +2030,7 @@
DSC == DeclSpecContext::DSC_type_specifier,
DSC == DeclSpecContext::DSC_template_param ||
DSC == DeclSpecContext::DSC_template_type_arg,
- &SkipBody);
+ &SkipBody, InBuiltInOffsetOfBase);
// If ActOnTag said the type was dependent, try again with the
// less common call.
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -3273,7 +3273,8 @@
bool &IsDependent, SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
bool IsTypeSpecifier, bool IsTemplateParamOrArg,
- SkipBodyInfo *SkipBody = nullptr);
+ SkipBodyInfo *SkipBody = nullptr,
+ bool IsWithinOffsetOf = false);
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
unsigned TagSpec, SourceLocation TagLoc,
Index: clang/include/clang/Parse/RAIIObjectsForParser.h
===================================================================
--- clang/include/clang/Parse/RAIIObjectsForParser.h
+++ clang/include/clang/Parse/RAIIObjectsForParser.h
@@ -341,6 +341,20 @@
}
};
+ class InBuiltInOffsetOfBaseRAIIObject {
+ bool &InBuiltInOffsetOfBase;
+ bool OldValue;
+
+ public:
+ InBuiltInOffsetOfBaseRAIIObject(Parser &P, bool Value)
+ : InBuiltInOffsetOfBase(P.InBuiltInOffsetOfBase),
+ OldValue(P.InBuiltInOffsetOfBase) {
+ InBuiltInOffsetOfBase = Value;
+ }
+
+ ~InBuiltInOffsetOfBaseRAIIObject() { InBuiltInOffsetOfBase = OldValue; }
+ };
+
/// RAII object that makes sure paren/bracket/brace count is correct
/// after declaration/statement parsing, even when there's a parsing error.
class ParenBraceBracketBalancer {
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -61,6 +61,7 @@
friend class ColonProtectionRAIIObject;
friend class ParsingOpenMPDirectiveRAII;
friend class InMessageExpressionRAIIObject;
+ friend class InBuiltInOffsetOfBaseRAIIObject;
friend class PoisonSEHIdentifiersRAIIObject;
friend class ObjCDeclContextSwitch;
friend class ParenBraceBracketBalancer;
@@ -246,6 +247,9 @@
/// function call.
bool CalledSignatureHelp = false;
+ /// Parsing a type within __builtin_offsetof.
+ bool InBuiltInOffsetOfBase = false;
+
/// The "depth" of the template parameters currently being parsed.
unsigned TemplateParameterDepth;
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1646,6 +1646,8 @@
"%0 cannot be defined in a condition">;
def err_type_defined_in_enum : Error<
"%0 cannot be defined in an enumeration">;
+def err_type_defined_in_offsetof : Error<
+ "%0 cannot be defined in '__builtin_offsetof'">;
def note_pure_virtual_function : Note<
"unimplemented pure virtual method %0 in %1">;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -191,6 +191,7 @@
- Adjusted ``-Wformat`` warnings according to `WG14 N2562 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2562.pdf>`_.
Clang will now consider default argument promotions in printf, and remove unnecessary warnings.
Especially ``int`` argument with specifier ``%hhd`` and ``%hd``.
+- Reject type definitions in the ``type`` argument of ``__builtin_offsetof`` according to `WG14 N2350 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2350.htm>`_.
C2x Feature Support
-------------------
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits