inclyc updated this revision to Diff 462680.
inclyc added a comment.

Address comments.

Clang will now consider __builtin_offsetof #defined from "offsetof" to improve
diagnostic message.

For example:

  #define offsetof(t, d) __builtin_offsetof(t, d)
  
  int main() {
    return offsetof(struct S { int a; }, a);
  }



  local/offsetof.c:4:26: error: 'S' cannot be defined in 'offsetof'
    return offsetof(struct S { int a; }, a);
                           ^
  1 error generated.

Emm, the "expected-error" of struct B within a macro seems have to be annotated
at the same line as"struct A".

  int macro(void) {
    return offsetof(struct A // expected-error{{'A' cannot be defined in 
'offsetof'}}
                             // expected-error@-1{{'B' cannot be defined in 
'offsetof'}}     <---- Have to write this here, but I believe the line number 
is correct
    { 
      int a;
      struct B // FIXME: verifier seems to think the error is emitted by the 
macro
               // In fact the location of the error is "B" on the line above
      {
        int c;
        int d;
      } x;
    }, a);
  }



  clang/test/C/C2x/n2350.c:11:36: error: 'A' cannot be defined in 
'__builtin_offsetof'
    return __builtin_offsetof(struct A // expected-error{{'A' cannot be defined 
in '__builtin_offsetof'}} 
                                     ^
  clang/test/C/C2x/n2350.c:14:12: error: 'B' cannot be defined in 
'__builtin_offsetof'
      struct B // expected-error{{'B' cannot be defined in 
'__builtin_offsetof'}} 
             ^
  clang/test/C/C2x/n2350.c:26:26: error: 'A' cannot be defined in 'offsetof'
    return offsetof(struct A // expected-error{{'A' cannot be defined in 
'offsetof'}}
                           ^
  clang/test/C/C2x/n2350.c:30:12: error: 'B' cannot be defined in 'offsetof' 
<-- note that this line number is "30" (not "26")
      struct B // FIXME: verifier seems to think the error is emitted by the 
macro
             ^
  4 errors generated.


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/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExpr.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/C/C2x/n2350.c
  clang/test/Parser/declarators.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,20 @@
                                                               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 // FIXME: error diagnostic message for nested definitions 
+             // https://reviews.llvm.org/D133574 
+             // fixme-error{{'A' cannot be defined in '__builtin_offsetof'}} 
+    {
+      int c;
+      int d;
+    };
+    B 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/test/C/C2x/n2350.c
===================================================================
--- /dev/null
+++ clang/test/C/C2x/n2350.c
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c89 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c99 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c17 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c2x -verify %s
+
+// Reject definitions in __builtin_offsetof
+// https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2350.htm
+int simple(void) {
+  return __builtin_offsetof(struct A // expected-error{{'A' cannot be defined in '__builtin_offsetof'}} 
+  { 
+    int a;
+    struct B // expected-error{{'B' cannot be defined in '__builtin_offsetof'}} 
+    {
+      int c;
+      int d;
+    } x;
+  }, a);
+}
+
+#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
+
+
+int macro(void) {
+  return offsetof(struct A // expected-error{{'A' cannot be defined in 'offsetof'}}
+                           // expected-error@-1{{'B' cannot be defined in 'offsetof'}}
+  { 
+    int a;
+    struct B // FIXME: verifier seems to think the error is emitted by the macro
+             // In fact the location of the error is "B" on the line above
+    {
+      int c;
+      int d;
+    } x;
+  }, a);
+}
+
+#undef offsetof
+
+#define offsetof(TYPE, MEMBER) (&((TYPE *)0)->MEMBER)
+
+// no warning for traditional offsetof as a function-like macro
+int * macro_func(void) {
+  return offsetof(struct A // no-warning
+  { 
+    int a;
+    int b;
+  }, a);
+}
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -9978,13 +9978,13 @@
 
   bool Owned = false;
   bool IsDependent = false;
-  Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference,
-                        KWLoc, SS, Name, NameLoc, Attr, AS_none,
-                        /*ModulePrivateLoc=*/SourceLocation(),
-                        MultiTemplateParamsArg(), Owned, IsDependent,
-                        SourceLocation(), false, TypeResult(),
-                        /*IsTypeSpecifier*/false,
-                        /*IsTemplateParamOrArg*/false);
+  Decl *TagD = ActOnTag(
+      S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr, AS_none,
+      /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(), Owned,
+      IsDependent, SourceLocation(), false, TypeResult(),
+      /*IsTypeSpecifier*/ false,
+      /*IsTemplateParamOrArg*/ false, /*IsWithinOffsetOf=*/false,
+      /*IsOffsetOfInMacro=*/false);
   assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
 
   if (!TagD)
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -16917,15 +16917,16 @@
     if (SS.isEmpty()) {
       bool Owned = false;
       bool IsDependent = false;
-      return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc,
-                      Attr, AS_public,
-                      /*ModulePrivateLoc=*/SourceLocation(),
-                      MultiTemplateParamsArg(), Owned, IsDependent,
-                      /*ScopedEnumKWLoc=*/SourceLocation(),
-                      /*ScopedEnumUsesClassTag=*/false,
-                      /*UnderlyingType=*/TypeResult(),
-                      /*IsTypeSpecifier=*/false,
-                      /*IsTemplateParamOrArg=*/false);
+      return ActOnTag(
+          S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, AS_public,
+          /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(),
+          Owned, IsDependent,
+          /*ScopedEnumKWLoc=*/SourceLocation(),
+          /*ScopedEnumUsesClassTag=*/false,
+          /*UnderlyingType=*/TypeResult(),
+          /*IsTypeSpecifier=*/false,
+          /*IsTemplateParamOrArg=*/false, /*IsWithinOffsetOf=*/false,
+          /*IsOffsetOfInMacro=*/false);
     }
 
     NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -16256,6 +16256,7 @@
                      SourceLocation ScopedEnumKWLoc,
                      bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
                      bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+                     bool IsWithinOffsetOf, bool IsOffsetOfInMacro,
                      SkipBodyInfo *SkipBody) {
   // If this is not a definition, it must have a name.
   IdentifierInfo *OrigName = Name;
@@ -17029,10 +17030,16 @@
                                cast_or_null<RecordDecl>(PrevDecl));
   }
 
+  if (IsWithinOffsetOf && TUK == TUK_Definition) {
+    Diag(New->getLocation(), diag::err_type_defined_in_offsetof)
+        << New << IsOffsetOfInMacro;
+    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,14 @@
   }
   case tok::kw___builtin_offsetof: {
     SourceLocation TypeLoc = Tok.getLocation();
+    auto K = OffsetOfStateKind::Builtin;
+    if (Tok.getLocation().isMacroID()) {
+      StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
+          Tok.getLocation(), PP.getSourceManager(), getLangOpts());
+      if (MacroName == "offsetof")
+        K = OffsetOfStateKind::Macro;
+    }
+    OffsetOfStateRAIIObject InOffsetof(*this, K);
     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,8 @@
         DSC == DeclSpecContext::DSC_type_specifier,
         DSC == DeclSpecContext::DSC_template_param ||
             DSC == DeclSpecContext::DSC_template_type_arg,
-        &SkipBody);
+        OffsetOfState != OffsetOfStateKind::Outside,
+        OffsetOfState == OffsetOfStateKind::Macro, &SkipBody);
 
     // If ActOnTag said the type was dependent, try again with the
     // less common call.
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -4886,7 +4886,8 @@
       DSC == DeclSpecContext::DSC_type_specifier,
       DSC == DeclSpecContext::DSC_template_param ||
           DSC == DeclSpecContext::DSC_template_type_arg,
-      &SkipBody);
+      OffsetOfState != OffsetOfStateKind::Outside,
+      OffsetOfState == OffsetOfStateKind::Macro, &SkipBody);
 
   if (SkipBody.ShouldSkip) {
     assert(TUK == Sema::TUK_Definition && "can only skip a definition");
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -3276,6 +3276,7 @@
                  bool &IsDependent, SourceLocation ScopedEnumKWLoc,
                  bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
                  bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+                 bool IsWithinOffsetOf, bool IsOffsetOfInMacro,
                  SkipBodyInfo *SkipBody = nullptr);
 
   Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
Index: clang/include/clang/Parse/RAIIObjectsForParser.h
===================================================================
--- clang/include/clang/Parse/RAIIObjectsForParser.h
+++ clang/include/clang/Parse/RAIIObjectsForParser.h
@@ -341,6 +341,19 @@
     }
   };
 
+  class OffsetOfStateRAIIObject {
+    Parser::OffsetOfStateKind &OffsetOfState;
+    Parser::OffsetOfStateKind OldValue;
+
+  public:
+    OffsetOfStateRAIIObject(Parser &P, Parser::OffsetOfStateKind Value)
+        : OffsetOfState(P.OffsetOfState), OldValue(P.OffsetOfState) {
+      OffsetOfState = Value;
+    }
+
+    ~OffsetOfStateRAIIObject() { OffsetOfState = 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 OffsetOfStateRAIIObject;
   friend class PoisonSEHIdentifiersRAIIObject;
   friend class ObjCDeclContextSwitch;
   friend class ParenBraceBracketBalancer;
@@ -247,6 +248,16 @@
   /// function call.
   bool CalledSignatureHelp = false;
 
+  enum OffsetOfStateKind {
+    // Not parsing a type within __builtin_offsetof
+    Outside,
+    // Parsing a type within __builtin_offsetof
+    Builtin,
+    // Parsing a type within macro "offsetof", defined in __buitin_offsetof
+    // To improve our diagnostic message
+    Macro,
+  } OffsetOfState = OffsetOfStateKind::Outside;
+
   /// 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 '%select{__builtin_offsetof|offsetof}1'">;
 
 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
@@ -284,6 +284,8 @@
   ``-Wunused-label`` warning.
 - Implemented `WG14 N2508 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2508.pdf>`_,
   so labels can placed everywhere inside a compound statement.
+- 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>`_.
 
 C++ Language Changes in Clang
 -----------------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to