rogfer01 created this revision.
rogfer01 added reviewers: aaron.ballman, rsmith.
rogfer01 added subscribers: cfe-commits, rsmith.
This is a WIP for PR28571.
As suggested by @rsmith it introduces a new ObjectKind for PackedField's
modeled similarly in spirit to BitField's. If the reference is const, the
binding is done using a temporary otherwise an error is diagnosed.
https://reviews.llvm.org/D23325
Files:
include/clang/AST/Decl.h
include/clang/AST/Expr.h
include/clang/AST/Stmt.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/Specifiers.h
lib/AST/ASTDumper.cpp
lib/AST/Decl.cpp
lib/CodeGen/CGCall.cpp
lib/Sema/SemaCast.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprMember.cpp
lib/Sema/SemaFixItUtils.cpp
lib/Sema/SemaInit.cpp
test/SemaCXX/bind-packed-member.cpp
Index: test/SemaCXX/bind-packed-member.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/bind-packed-member.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -verify %s
+
+struct __attribute__((packed)) A {
+ char x;
+ float y;
+ char z;
+} a;
+
+char &rax = a.x; // no-error
+float &ray = a.y; // expected-error {{reference cannot bind to packed field}}
+char &raz = a.z; // no-error
+
+struct __attribute__((packed, aligned(2))) B {
+ // Regardless of aligned(2) the fields are aligned(1) because of packed.
+ // The whole struct is aligned(2), though.
+ short x;
+ float y;
+ short z;
+ char w;
+} b;
+
+const short &crbx = b.x; // no-error
+short &rbx = b.x; // expected-error {{reference cannot bind to packed field}}
+float &rby = b.y; // expected-error {{reference cannot bind to packed field}}
+short &rbz = b.z; // expected-error {{reference cannot bind to packed field}}
+char &rbw = b.w; // no-error
+
+struct __attribute__((packed)) B2 {
+ short x __attribute__((aligned(2)));
+ float y;
+ short z __attribute__((aligned(4)));
+ char w;
+} b2;
+
+short &rb2x = b2.x; // no-error
+short &rb2z = b2.z; // no-error
+
+struct C {
+ int c;
+};
+
+struct __attribute__((packed)) D {
+ char x;
+ int y;
+ C z;
+} d;
+
+C &rcz = d.z; // expected-error {{reference cannot bind to packed field}}
+int &rczc = d.z.c; // expected-error {{reference cannot bind to packed field}}
+
+struct E {
+ int x __attribute__((packed));
+ C y __attribute__((packed));
+ C z;
+} e;
+
+int& rex = e.x; // expected-error {{reference cannot bind to packed field}}
+C& rey = e.y; // expected-error {{reference cannot bind to packed field}}
+C& rez = e.z; // no-error
+
+struct NonTrivialCopy
+{
+ int w;
+ NonTrivialCopy();
+ NonTrivialCopy(const NonTrivialCopy&);
+};
+
+struct F
+{
+ char c;
+ NonTrivialCopy x __attribute__((packed));
+ int w __attribute__((packed));
+} f;
+
+
+void fun1(int &);
+void fun2(const int &);
+
+void bar()
+{
+ const NonTrivialCopy& rx = f.x; // expected-error {{reference cannot bind to packed field}}
+ const int &w = f.w; // no-error
+
+ fun1(f.w); // expected-error {{reference cannot bind to packed field}}
+ // expected-note@76 {{passing argument to parameter here}}
+ fun2(f.w); // no-error
+}
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -4168,6 +4168,7 @@
Qualifiers T2Quals,
bool IsLValueRef) {
bool IsNonAddressableType = Initializer->refersToBitField() ||
+ Initializer->refersToPackedField() ||
Initializer->refersToVectorElement();
if (IsNonAddressableType) {
@@ -4182,6 +4183,30 @@
return Initializer->getValueKind();
}
+ if (IsLValueRef && Initializer->refersToPackedField() &&
+ Initializer->getType()->getAsCXXRecordDecl()) {
+ auto Record = Initializer->getType()->getAsCXXRecordDecl();
+ /*
+ Consider the case below:
+ struct A
+ {
+ char c;
+ std::vector<int> x __attribute__((packed));
+ } a;
+
+ void f()
+ {
+ const std::vector<int>& w = a.x;
+ }
+
+ It is not possible to bind w to a temporary of a.x because this
+ would require (recursively) invoking the copy constructor of
+ std::vector to obtain first a (properly aligned) temporary of a.x.
+ */
+ if (!Record->hasTrivialCopyConstructor())
+ return Initializer->getValueKind();
+ }
+
// Force a load so we can materialize a temporary.
Sequence.AddLValueToRValueStep(cv1T1.getUnqualifiedType());
return VK_RValue;
@@ -6431,6 +6456,13 @@
return ExprError();
}
+ if (CurInit.get()->refersToPackedField()) {
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_to_packed_field)
+ << CurInit.get()->getSourceRange();
+ PrintInitLocationNote(S, Entity);
+ return ExprError();
+ }
+
if (CurInit.get()->refersToVectorElement()) {
// References cannot bind to vector elements.
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element)
Index: lib/Sema/SemaFixItUtils.cpp
===================================================================
--- lib/Sema/SemaFixItUtils.cpp
+++ lib/Sema/SemaFixItUtils.cpp
@@ -130,7 +130,8 @@
OverloadFixItKind FixKind = OFIK_TakeAddress;
// Only suggest taking address of L-values.
- if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary)
+ if (!Expr->isLValue() || (Expr->getObjectKind() != OK_Ordinary &&
+ Expr->getObjectKind() != OK_PackedField))
return false;
CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy,
Index: lib/Sema/SemaExprMember.cpp
===================================================================
--- lib/Sema/SemaExprMember.cpp
+++ lib/Sema/SemaExprMember.cpp
@@ -1769,14 +1769,20 @@
ExprValueKind VK = VK_LValue;
ExprObjectKind OK = OK_Ordinary;
if (!IsArrow) {
- if (BaseExpr->getObjectKind() == OK_Ordinary)
+ if (BaseExpr->getObjectKind() == OK_Ordinary ||
+ BaseExpr->getObjectKind() == OK_PackedField)
VK = BaseExpr->getValueKind();
else
VK = VK_RValue;
}
- if (VK != VK_RValue && Field->isBitField())
- OK = OK_BitField;
-
+ if (VK != VK_RValue)
+ {
+ if (Field->isBitField())
+ OK = OK_BitField;
+ else if (Field->isPackedField(S.Context) || BaseExpr->refersToPackedField())
+ OK = OK_PackedField;
+ }
+
// Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
QualType MemberType = Field->getType();
if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) {
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -1786,6 +1786,8 @@
// Just in case we're building an illegal pointer-to-member.
if (FD->isBitField())
E->setObjectKind(OK_BitField);
+ else if (FD->isPackedField(Context))
+ E->setObjectKind(OK_PackedField);
}
return E;
Index: lib/Sema/SemaCast.cpp
===================================================================
--- lib/Sema/SemaCast.cpp
+++ lib/Sema/SemaCast.cpp
@@ -1909,6 +1909,7 @@
const char *inappropriate = nullptr;
switch (SrcExpr.get()->getObjectKind()) {
case OK_Ordinary:
+ case OK_PackedField:
break;
case OK_BitField: inappropriate = "bit-field"; break;
case OK_VectorComponent: inappropriate = "vector element"; break;
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -3275,7 +3275,7 @@
"reference binding to unmaterialized r-value!");
if (E->isGLValue()) {
- assert(E->getObjectKind() == OK_Ordinary);
+ assert(E->getObjectKind() == OK_Ordinary || E->getObjectKind() == OK_PackedField);
return args.add(EmitReferenceBindingToExpr(E), type);
}
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -34,6 +34,8 @@
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
+#include <iostream>
+
using namespace clang;
Decl *clang::getPrimaryMergedDecl(Decl *D) {
@@ -3516,6 +3518,13 @@
ISK_CapturedVLAType);
}
+bool FieldDecl::isPackedField(const ASTContext &Context) const {
+ return !isBitField() &&
+ (this->hasAttr<PackedAttr>() || getParent()->hasAttr<PackedAttr>()) &&
+ Context.getDeclAlign(this) <
+ Context.getTypeAlignInChars(this->getType());
+}
+
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -1874,6 +1874,9 @@
switch (Node->getObjectKind()) {
case OK_Ordinary:
break;
+ case OK_PackedField:
+ OS << " packfield";
+ break;
case OK_BitField:
OS << " bitfield";
break;
Index: include/clang/Basic/Specifiers.h
===================================================================
--- include/clang/Basic/Specifiers.h
+++ include/clang/Basic/Specifiers.h
@@ -123,6 +123,9 @@
/// A bitfield object is a bitfield on a C or C++ record.
OK_BitField,
+ /// A packed-field is a field on a C or C++ packed record.
+ OK_PackedField,
+
/// A vector component is an element or range of elements on a vector.
OK_VectorComponent,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1649,6 +1649,8 @@
def err_reference_bind_to_bitfield : Error<
"%select{non-const|volatile}0 reference cannot bind to "
"bit-field%select{| %1}2">;
+def err_reference_bind_to_packed_field : Error<
+ "reference cannot bind to packed field">;
def err_reference_bind_to_vector_element : Error<
"%select{non-const|volatile}0 reference cannot bind to vector element">;
def err_reference_var_requires_init : Error<
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -126,13 +126,13 @@
unsigned : NumStmtBits;
unsigned ValueKind : 2;
- unsigned ObjectKind : 2;
+ unsigned ObjectKind : 3;
unsigned TypeDependent : 1;
unsigned ValueDependent : 1;
unsigned InstantiationDependent : 1;
unsigned ContainsUnexpandedParameterPack : 1;
};
- enum { NumExprBits = 16 };
+ enum { NumExprBits = 17 };
class CharacterLiteralBitfields {
friend class CharacterLiteral;
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -409,9 +409,10 @@
return static_cast<ExprObjectKind>(ExprBits.ObjectKind);
}
+ /// States that this object is ordinary, packed field or bitfield
bool isOrdinaryOrBitFieldObject() const {
ExprObjectKind OK = getObjectKind();
- return (OK == OK_Ordinary || OK == OK_BitField);
+ return (OK == OK_Ordinary || OK == OK_PackedField || OK == OK_BitField);
}
/// setValueKind - Set the value kind produced by this expression.
@@ -432,6 +433,14 @@
/// an aspect of the value-kind type system.
bool refersToBitField() const { return getObjectKind() == OK_BitField; }
+ /// \brief Returns true if this expression is a gl-value that
+ /// potentially refers to a packed-field. Here packed-field means
+ /// that the field has got its alignment effectively reduced.
+ ///
+ /// Likewise bitfields, we model gl-values referring to packed-fields as
+ /// an aspect of the value-kind type system.
+ bool refersToPackedField() const { return getObjectKind() == OK_PackedField; }
+
/// \brief If this expression refers to a bit-field, retrieve the
/// declaration of that bit-field.
///
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -2363,6 +2363,10 @@
InitStorage.getPointer() != nullptr;
}
+ /// \brief Determines whether this field is actually packed, i.e.
+ /// its alignment is smaller than the alignment of its field type.
+ bool isPackedField(const ASTContext& context) const;
+
/// @brief Determines whether this is an unnamed bitfield.
bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits