diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -56,6 +56,7 @@ C++ Language Changes -------------------- +- Improved ``__builtin_offsetof`` support, allowing qualified name in member designator. This fixes [Issue 64154](https://github.com/llvm/llvm-project/issues/64154). C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ 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 @@ -6035,11 +6035,15 @@ // __builtin_offsetof(type, identifier(.identifier|[expr])*) struct OffsetOfComponent { SourceLocation LocStart, LocEnd; - bool isBrackets; // true if [expr], false if .ident union { IdentifierInfo *IdentInfo; Expr *E; } U; + enum { + Brackets, // U.E is valid + Identifier, // U.IdentInfo is valid + Qualifier, // Nothing in U is valid + } Kind; }; /// __builtin_offsetof(type, a.b[123][456].c) 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 @@ -2635,16 +2635,23 @@ SmallVector Comps; Comps.push_back(Sema::OffsetOfComponent()); - Comps.back().isBrackets = false; + Comps.back().Kind = Sema::OffsetOfComponent::Identifier; Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken(); // FIXME: This loop leaks the index expressions on error. while (true) { - if (Tok.is(tok::period)) { + if (Tok.is(tok::period) || Tok.is(tok::coloncolon)) { // offsetof-member-designator: offsetof-member-designator '.' identifier + if (Tok.is(tok::coloncolon) && getLangOpts().CPlusPlus) { + Comps.back().Kind = Sema::OffsetOfComponent::Qualifier; + } else if (Tok.is(tok::coloncolon) && !getLangOpts().CPlusPlus) { + Res = ExprError(); + break; + } + Comps.push_back(Sema::OffsetOfComponent()); - Comps.back().isBrackets = false; + Comps.back().Kind = Sema::OffsetOfComponent::Identifier; Comps.back().LocStart = ConsumeToken(); if (Tok.isNot(tok::identifier)) { @@ -2660,7 +2667,7 @@ // offsetof-member-designator: offsetof-member-design '[' expression ']' Comps.push_back(Sema::OffsetOfComponent()); - Comps.back().isBrackets = true; + Comps.back().Kind = Sema::OffsetOfComponent::Brackets; BalancedDelimiterTracker ST(*this, tok::l_square); ST.consumeOpen(); Comps.back().LocStart = ST.getOpenLocation(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -16612,7 +16612,7 @@ SmallVector Comps; SmallVector Exprs; for (const OffsetOfComponent &OC : Components) { - if (OC.isBrackets) { + if (OC.Kind == OffsetOfComponent::Brackets) { // Offset of an array sub-field. TODO: Should we allow vector elements? if (!CurrentType->isDependentType()) { const ArrayType *AT = Context.getAsArrayType(CurrentType); @@ -16682,6 +16682,10 @@ << SourceRange(Components[0].LocStart, OC.LocEnd) << CurrentType)) DidWarnAboutNonPOD = true; + + if (OC.Kind == OffsetOfComponent::Qualifier && + RD->getIdentifier() == OC.U.IdentInfo) + continue; } // Look for the field. diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -11028,7 +11028,7 @@ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { const OffsetOfNode &ON = E->getComponent(I); Component Comp; - Comp.isBrackets = true; + Comp.Kind = Sema::OffsetOfComponent::Brackets; Comp.LocStart = ON.getSourceRange().getBegin(); Comp.LocEnd = ON.getSourceRange().getEnd(); switch (ON.getKind()) { @@ -11039,14 +11039,14 @@ return ExprError(); ExprChanged = ExprChanged || Index.get() != FromIndex; - Comp.isBrackets = true; + Comp.Kind = Sema::OffsetOfComponent::Brackets; Comp.U.E = Index.get(); break; } case OffsetOfNode::Field: case OffsetOfNode::Identifier: - Comp.isBrackets = false; + Comp.Kind = Sema::OffsetOfComponent::Identifier; Comp.U.IdentInfo = ON.getFieldName(); if (!Comp.U.IdentInfo) continue; diff --git a/clang/test/SemaCXX/offsetof.cpp b/clang/test/SemaCXX/offsetof.cpp --- a/clang/test/SemaCXX/offsetof.cpp +++ b/clang/test/SemaCXX/offsetof.cpp @@ -98,3 +98,10 @@ B x; }, a); } + +// https://github.com/llvm/llvm-project/issues/64154 +struct X2 { int a; static int static_a; }; +int x2[__builtin_offsetof(struct X2, X2::a) == 0 ? 1 : -1]; +int x3[__builtin_offsetof(struct X2, X2::static_a) == 0 ? 1 : -1]; // expected-error{{no member named 'static_a'}} +int x4[__builtin_offsetof(struct X2, X2::X2) == 0 ? 1 : -1]; // expected-error{{no member named 'X2'}} +