inclyc updated this revision to Diff 461463.
inclyc added a comment.
Switch back to RAIIObject.
Currently clang could not generate diagnostic messages for nested definitions
in C++. I believe using RAIIObject here is logically correct, but in C++ mode,
`ActOnTag` returns `nullptr`, and the comment says
> We can't recover well from the cases where we make the type anonymous
/* SemaDecl.cpp Sema::ActOnTag Ln 17189 */
// In C++, don't return an invalid declaration. We can't recover well from
// the cases where we make the type anonymous.
if (Invalid && getLangOpts().CPlusPlus) {
if (New->isBeingDefined())
if (auto RD = dyn_cast<RecordDecl>(New))
RD->completeDefinition();
return nullptr;
} else if (SkipBody && SkipBody->ShouldSkip) {
return SkipBody->Previous;
} else {
return New;
}
I believe the state "ParsingBuiltinOffsetof" is correctly passed into
`ParseCXXMemberSpecification` (parsing nested definition), and if clang
recovers invalid declaration in the furture, nested definitions will be caught.
if (TUK == Sema::TUK_Definition) {
assert(Tok.is(tok::l_brace) ||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
isClassCompatibleKeyword());
if (SkipBody.ShouldSkip)
SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType,
TagOrTempResult.get());
else if (getLangOpts().CPlusPlus)
ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType,
TagOrTempResult.get()); // <---- nullptr,
nested declaration skipped
else {
Decl *D =
SkipBody.CheckSameAsPrevious ? SkipBody.New : TagOrTempResult.get();
// Parse the definition body.
ParseStructUnionBody(StartLoc, TagType, cast<RecordDecl>(D));
if (SkipBody.CheckSameAsPrevious &&
!Actions.ActOnDuplicateDefinition(TagOrTempResult.get(), SkipBody)) {
DS.SetTypeSpecError();
return;
}
}
}
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
clang/test/SemaCXX/offsetof.cpp
Index: clang/test/SemaCXX/offsetof.cpp
===================================================================
--- clang/test/SemaCXX/offsetof.cpp
+++ clang/test/SemaCXX/offsetof.cpp
@@ -83,3 +83,18 @@
expected-error {{invalid application of 'offsetof' to a field of a virtual base}}
};
}
+
+// 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{{'A' cannot be defined in '__builtin_offsetof'}}
+ {
+ int a;
+ struct B
+ {
+ int c;
+ int d;
+ };
+ B x;
+ }, a);
+}
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,10 +17027,16 @@
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) &&
- TUK == TUK_Definition) {
+ if (!Invalid && getLangOpts().CPlusPlus &&
+ (IsTypeSpecifier || IsTemplateParamOrArg) && TUK == TUK_Definition) {
Diag(New->getLocation(), diag::err_type_defined_in_type_specifier)
<< Context.getTagDeclType(New);
Invalid = true;
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