diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -202,6 +202,7 @@ - Adjusted ``-Wformat`` warnings according to `WG14 N2562 `_. 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 `_. C2x Feature Support ------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2190,17 +2190,19 @@ /// out, there are other significant restrictions on specifiers than /// would be best implemented in the parser. enum class DeclSpecContext { - DSC_normal, // normal context - DSC_class, // class context, enables 'friend' + DSC_normal, // normal context + DSC_class, // class context, enables 'friend' DSC_type_specifier, // C++ type-specifier-seq or C specifier-qualifier-list DSC_trailing, // C++11 trailing-type-specifier in a trailing return type - DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration - DSC_top_level, // top-level/namespace declaration context - DSC_template_param, // template parameter context - DSC_template_type_arg, // template type argument context - DSC_objc_method_result, // ObjC method result context, enables 'instancetype' - DSC_condition, // condition declaration context - DSC_association // A _Generic selection expression's type association + DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration + DSC_top_level, // top-level/namespace declaration context + DSC_template_param, // template parameter context + DSC_template_type_arg, // template type argument context + DSC_objc_method_result, // ObjC method result context, enables + // 'instancetype' + DSC_condition, // condition declaration context + DSC_association, // A _Generic selection expression's type association + DSC_offsetof // Within __builtin_offsetof, reject definitions here }; /// Is this a context in which we are parsing just a type-specifier (or @@ -2220,6 +2222,7 @@ case DeclSpecContext::DSC_trailing: case DeclSpecContext::DSC_alias_declaration: case DeclSpecContext::DSC_association: + case DeclSpecContext::DSC_offsetof: return true; } llvm_unreachable("Missing DeclSpecContext case"); @@ -2259,6 +2262,7 @@ case DeclSpecContext::DSC_template_type_arg: case DeclSpecContext::DSC_type_specifier: + case DeclSpecContext::DSC_offsetof: return AllowDefiningTypeSpec::NoButErrorRecovery; case DeclSpecContext::DSC_association: @@ -2287,6 +2291,7 @@ case DeclSpecContext::DSC_type_specifier: case DeclSpecContext::DSC_trailing: case DeclSpecContext::DSC_association: + case DeclSpecContext::DSC_offsetof: return false; } llvm_unreachable("Missing DeclSpecContext case"); @@ -2303,6 +2308,7 @@ case DeclSpecContext::DSC_condition: case DeclSpecContext::DSC_type_specifier: case DeclSpecContext::DSC_association: + case DeclSpecContext::DSC_offsetof: return true; case DeclSpecContext::DSC_objc_method_result: diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1798,7 +1798,8 @@ AliasDecl, // C++11 alias-declaration. AliasTemplate, // C++11 alias-declaration template. RequiresExpr, // C++2a requires-expression. - Association // C11 _Generic selection expression association. + Association, // C11 _Generic selection expression association. + OffsetOf // Declaration within __builtin_offsetof }; /// Information about one declarator, including the parsed type @@ -2065,6 +2066,7 @@ case DeclaratorContext::TrailingReturnVar: case DeclaratorContext::RequiresExpr: case DeclaratorContext::Association: + case DeclaratorContext::OffsetOf: return true; } llvm_unreachable("unknown context kind!"); @@ -2105,6 +2107,7 @@ case DeclaratorContext::TrailingReturn: case DeclaratorContext::TrailingReturnVar: case DeclaratorContext::Association: + case DeclaratorContext::OffsetOf: return false; } llvm_unreachable("unknown context kind!"); @@ -2149,6 +2152,7 @@ case DeclaratorContext::TrailingReturn: case DeclaratorContext::TrailingReturnVar: case DeclaratorContext::Association: + case DeclaratorContext::OffsetOf: return false; } llvm_unreachable("unknown context kind!"); @@ -2206,6 +2210,7 @@ case DeclaratorContext::TrailingReturn: case DeclaratorContext::RequiresExpr: case DeclaratorContext::Association: + case DeclaratorContext::OffsetOf: return false; } llvm_unreachable("unknown context kind!"); @@ -2429,6 +2434,7 @@ case DeclaratorContext::TrailingReturnVar: case DeclaratorContext::RequiresExpr: case DeclaratorContext::Association: + case DeclaratorContext::OffsetOf: return false; } llvm_unreachable("unknown context kind!"); @@ -2464,6 +2470,7 @@ case DeclaratorContext::TemplateTypeArg: case DeclaratorContext::RequiresExpr: case DeclaratorContext::Association: + case DeclaratorContext::OffsetOf: return false; case DeclaratorContext::Block: diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/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 IsWithinBuiltinOffsetof = false); Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2893,6 +2893,8 @@ return DeclSpecContext::DSC_alias_declaration; if (Context == DeclaratorContext::Association) return DeclSpecContext::DSC_association; + if (Context == DeclaratorContext::OffsetOf) + return DeclSpecContext::DSC_offsetof; return DeclSpecContext::DSC_normal; } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/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, DSC == DeclSpecContext::DSC_offsetof); // If ActOnTag said the type was dependent, try again with the // less common call. diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -2579,7 +2579,8 @@ } case tok::kw___builtin_offsetof: { SourceLocation TypeLoc = Tok.getLocation(); - TypeResult Ty = ParseTypeName(); + TypeResult Ty = + ParseTypeName(/*Range=*/nullptr, DeclaratorContext::OffsetOf); if (Ty.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16257,7 +16257,7 @@ SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier, bool IsTemplateParamOrArg, - SkipBodyInfo *SkipBody) { + SkipBodyInfo *SkipBody, bool IsWithinBuiltinOffsetof) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; assert((Name != nullptr || TUK == TUK_Definition) && @@ -17030,6 +17030,12 @@ cast_or_null(PrevDecl)); } + if (IsWithinBuiltinOffsetof && 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) && diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3584,6 +3584,7 @@ [[fallthrough]]; case DeclaratorContext::TypeName: case DeclaratorContext::Association: + case DeclaratorContext::OffsetOf: Error = 15; // Generic break; case DeclaratorContext::File: @@ -3695,6 +3696,7 @@ case DeclaratorContext::TemplateArg: case DeclaratorContext::TemplateTypeArg: case DeclaratorContext::Association: + case DeclaratorContext::OffsetOf: DiagID = diag::err_type_defined_in_type_specifier; break; case DeclaratorContext::Prototype: @@ -4784,6 +4786,7 @@ case DeclaratorContext::FunctionalCast: case DeclaratorContext::RequiresExpr: case DeclaratorContext::Association: + case DeclaratorContext::OffsetOf: // Don't infer in these contexts. break; } @@ -5836,6 +5839,7 @@ case DeclaratorContext::TemplateArg: case DeclaratorContext::TemplateTypeArg: case DeclaratorContext::Association: + case DeclaratorContext::OffsetOf: // FIXME: We may want to allow parameter packs in block-literal contexts // in the future. S.Diag(D.getEllipsisLoc(), diff --git a/clang/test/Parser/declarators.c b/clang/test/Parser/declarators.c --- a/clang/test/Parser/declarators.c +++ b/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); diff --git a/clang/test/Sema/offsetof.c b/clang/test/Sema/offsetof.c --- a/clang/test/Sema/offsetof.c +++ b/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 // no-error, struct B is not defined within __builtin_offsetof directly + { + int c; + int d; + } x; + }, a); +}