[cfe-commits] r70419 - in /cfe/trunk: include/clang/AST/Attr.h include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/Sema/transparent-union.c
Douglas Gregor
dgregor at apple.com
Wed Apr 29 15:16:17 PDT 2009
Author: dgregor
Date: Wed Apr 29 17:16:16 2009
New Revision: 70419
URL: http://llvm.org/viewvc/llvm-project?rev=70419&view=rev
Log:
Implement semantic analysis for transparent unions. This is largely
based on a patch from Anders Johnsen. CodeGen support is incomplete,
in that we do not properly coerce to the first field's type.
Added:
cfe/trunk/test/Sema/transparent-union.c
Modified:
cfe/trunk/include/clang/AST/Attr.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
Modified: cfe/trunk/include/clang/AST/Attr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=70419&r1=70418&r2=70419&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Attr.h (original)
+++ cfe/trunk/include/clang/AST/Attr.h Wed Apr 29 17:16:16 2009
@@ -400,7 +400,9 @@
virtual bool isMerged() const { return false; }
- virtual Attr *clone(ASTContext &C) const { return ::new (C) OverloadableAttr; }
+ virtual Attr *clone(ASTContext &C) const {
+ return ::new (C) OverloadableAttr;
+ }
static bool classof(const Attr *A) { return A->getKind() == Overloadable; }
static bool classof(const OverloadableAttr *) { return true; }
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=70419&r1=70418&r2=70419&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Apr 29 17:16:16 2009
@@ -415,18 +415,21 @@
def warn_attribute_ignored_for_field_of_type : Warning<
"%0 attribute ignored for field of type %1">;
-def warn_transparent_union_attribute_field_size : Warning<
- "transparent_union attribute ignored, size of type %0 must match "
- "type of first field">;
-def warn_transparent_union_attribute_not_difinition : Warning<
- "transparent_union attribute ignored, union type must be defined">;
+def warn_transparent_union_attribute_field_size_align : Warning<
+ "%select{alignment|size}0 of field %1 (%2 bits) does not match the "
+ "%select{alignment|size}0 of the first field in transparent union; "
+ "transparent_union attribute ignored">;
+def note_transparent_union_first_field_size_align : Note<
+ "%select{alignment|size}0 of first field is %1 bits">;
+def warn_transparent_union_attribute_not_definition : Warning<
+ "transparent_union attribute can only be applied to a union definition; "
+ "attribute ignored">;
def warn_transparent_union_attribute_floating : Warning<
- "transparent_union attribute ignored, first field cannot be a floating-point "
- "or vector type">;
+ "first field of a transparent union cannot have floating point or vector "
+ "type; transparent_union attribute ignored">;
def warn_transparent_union_attribute_zero_fields : Warning<
- "transparent_union attribute ignored, the union does not contain any fields">;
-def warn_transparent_union_attribute_not_c : Warning<
- "transparent_union attribute ignored, attribute is c only">;
+ "transparent union definition must contain at least one field; "
+ "transparent_union attribute ignored">;
def warn_attribute_type_not_supported : Warning<
"'%0' attribute argument not supported: %1">;
def warn_attribute_unknown_visibility : Warning<"unknown visibility '%1'">;
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=70419&r1=70418&r2=70419&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Apr 29 17:16:16 2009
@@ -2355,11 +2355,17 @@
/// This routine is only used by the following two methods. C99 6.5.16.
AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs);
- // CheckSingleAssignmentConstraints - Currently used by ActOnCallExpr,
+ // CheckSingleAssignmentConstraints - Currently used by
// CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking,
// this routine performs the default function/array converions.
AssignConvertType CheckSingleAssignmentConstraints(QualType lhs,
Expr *&rExpr);
+
+ // \brief If the lhs type is a transparent union, check whether we
+ // can initialize the transparent union with the given expression.
+ AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs,
+ Expr *&rExpr);
+
// CheckCompoundAssignmentConstraints - Type check without performing any
// conversions. For compound assignments, the "Check...Operands" methods
// perform the necessary conversions.
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=70419&r1=70418&r2=70419&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed Apr 29 17:16:16 2009
@@ -1178,36 +1178,63 @@
return;
}
- // FIXME: This shouldn't be restricted to typedefs
+ // Try to find the underlying union declaration.
+ RecordDecl *RD = 0;
TypedefDecl *TD = dyn_cast<TypedefDecl>(d);
- if (!TD || !TD->getUnderlyingType()->isUnionType()) {
+ if (TD && TD->getUnderlyingType()->isUnionType())
+ RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
+ else
+ RD = dyn_cast<RecordDecl>(d);
+
+ if (!RD || !RD->isUnion()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< "transparent_union" << 1 /*union*/;
return;
}
- RecordDecl* RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
+ if (!RD->isDefinition()) {
+ S.Diag(Attr.getLoc(),
+ diag::warn_transparent_union_attribute_not_definition);
+ return;
+ }
- // FIXME: Should we do a check for RD->isDefinition()?
+ RecordDecl::field_iterator Field = RD->field_begin(S.Context),
+ FieldEnd = RD->field_end(S.Context);
+ if (Field == FieldEnd) {
+ S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_zero_fields);
+ return;
+ }
+
+ FieldDecl *FirstField = *Field;
+ QualType FirstType = FirstField->getType();
+ if (FirstType->isFloatingType() || FirstType->isVectorType()) {
+ S.Diag(FirstField->getLocation(),
+ diag::warn_transparent_union_attribute_floating);
+ return;
+ }
- // FIXME: This isn't supposed to be restricted to pointers, but otherwise
- // we might silently generate incorrect code; see following code
- for (RecordDecl::field_iterator Field = RD->field_begin(S.Context),
- FieldEnd = RD->field_end(S.Context);
- Field != FieldEnd; ++Field) {
- if (!Field->getType()->isPointerType()) {
- S.Diag(Attr.getLoc(), diag::warn_transparent_union_nonpointer);
+ uint64_t FirstSize = S.Context.getTypeSize(FirstType);
+ uint64_t FirstAlign = S.Context.getTypeAlign(FirstType);
+ for (; Field != FieldEnd; ++Field) {
+ QualType FieldType = Field->getType();
+ if (S.Context.getTypeSize(FieldType) != FirstSize ||
+ S.Context.getTypeAlign(FieldType) != FirstAlign) {
+ // Warn if we drop the attribute.
+ bool isSize = S.Context.getTypeSize(FieldType) != FirstSize;
+ unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
+ : S.Context.getTypeAlign(FieldType);
+ S.Diag(Field->getLocation(),
+ diag::warn_transparent_union_attribute_field_size_align)
+ << isSize << Field->getDeclName() << FieldBits;
+ unsigned FirstBits = isSize? FirstSize : FirstAlign;
+ S.Diag(FirstField->getLocation(),
+ diag::note_transparent_union_first_field_size_align)
+ << isSize << FirstBits;
return;
}
}
- // FIXME: This is a complete hack; we should be properly propagating
- // transparent_union through Sema. That said, this is close enough to
- // correctly compile all the common cases of transparent_union without
- // errors or warnings
- QualType NewTy = S.Context.VoidPtrTy;
- NewTy.addConst();
- TD->setUnderlyingType(NewTy);
+ RD->addAttr(::new (S.Context) TransparentUnionAttr());
}
static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=70419&r1=70418&r2=70419&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Apr 29 17:16:16 2009
@@ -3124,6 +3124,73 @@
return Incompatible;
}
+/// \brief Constructs a transparent union from an expression that is
+/// used to initialize the transparent union.
+static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
+ QualType UnionType, FieldDecl *Field) {
+ // Build an initializer list that designates the appropriate member
+ // of the transparent union.
+ InitListExpr *Initializer = new (C) InitListExpr(SourceLocation(),
+ &E, 1,
+ SourceLocation());
+ Initializer->setType(UnionType);
+ Initializer->setInitializedFieldInUnion(Field);
+
+ // Build a compound literal constructing a value of the transparent
+ // union type from this initializer list.
+ E = new (C) CompoundLiteralExpr(SourceLocation(), UnionType, Initializer,
+ false);
+}
+
+Sema::AssignConvertType
+Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
+ QualType FromType = rExpr->getType();
+
+ // If the ArgType is a Union type, we want to handle a potential
+ // transparent_union GCC extension.
+ const RecordType *UT = ArgType->getAsUnionType();
+ if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ return Incompatible;
+
+ // The field to initialize within the transparent union.
+ RecordDecl *UD = UT->getDecl();
+ FieldDecl *InitField = 0;
+ // It's compatible if the expression matches any of the fields.
+ for (RecordDecl::field_iterator it = UD->field_begin(Context),
+ itend = UD->field_end(Context);
+ it != itend; ++it) {
+ if (it->getType()->isPointerType()) {
+ // If the transparent union contains a pointer type, we allow:
+ // 1) void pointer
+ // 2) null pointer constant
+ if (FromType->isPointerType())
+ if (FromType->getAsPointerType()->getPointeeType()->isVoidType()) {
+ ImpCastExprToType(rExpr, it->getType());
+ InitField = *it;
+ break;
+ }
+
+ if (rExpr->isNullPointerConstant(Context)) {
+ ImpCastExprToType(rExpr, it->getType());
+ InitField = *it;
+ break;
+ }
+ }
+
+ if (CheckAssignmentConstraints(it->getType(), rExpr->getType())
+ == Compatible) {
+ InitField = *it;
+ break;
+ }
+ }
+
+ if (!InitField)
+ return Incompatible;
+
+ ConstructTransparentUnion(Context, rExpr, ArgType, InitField);
+ return Compatible;
+}
+
Sema::AssignConvertType
Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
if (getLangOptions().CPlusPlus) {
@@ -3169,7 +3236,7 @@
// so that we can use references in built-in functions even in C.
// The getNonReferenceType() call makes sure that the resulting expression
// does not have reference type.
- if (rExpr->getType() != lhsType)
+ if (result != Incompatible && rExpr->getType() != lhsType)
ImpCastExprToType(rExpr, lhsType.getNonReferenceType());
return result;
}
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=70419&r1=70418&r2=70419&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Apr 29 17:16:16 2009
@@ -1888,9 +1888,13 @@
if (!getLangOptions().CPlusPlus) {
// In C, argument passing is the same as performing an assignment.
QualType FromType = From->getType();
+
AssignConvertType ConvTy =
CheckSingleAssignmentConstraints(ToType, From);
-
+ if (ConvTy != Compatible &&
+ CheckTransparentUnionArgumentConstraints(ToType, From) == Compatible)
+ ConvTy = Compatible;
+
return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType,
FromType, From, Flavor);
}
Added: cfe/trunk/test/Sema/transparent-union.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/transparent-union.c?rev=70419&view=auto
==============================================================================
--- cfe/trunk/test/Sema/transparent-union.c (added)
+++ cfe/trunk/test/Sema/transparent-union.c Wed Apr 29 17:16:16 2009
@@ -0,0 +1,40 @@
+// RUN: clang -fsyntax-only -Xclang -verify %s
+typedef union {
+ int *ip;
+ float *fp;
+} TU __attribute__((transparent_union));
+
+void f(TU);
+
+void g(int *ip, float *fp, char *cp) {
+ f(ip);
+ f(fp);
+ f(cp); // expected-error{{incompatible type}}
+ f(0);
+
+ TU tu_ip = ip; // expected-error{{incompatible type}}
+ TU tu;
+ tu.ip = ip;
+}
+
+/* FIXME: we'd like to just use an "int" here and align it differently
+ from the normal "int", but if we do so we lose the alignment
+ information from the typedef within the compiler. */
+typedef struct { int x, y; } __attribute__((aligned(8))) aligned_struct8;
+
+typedef struct { int x, y; } __attribute__((aligned(4))) aligned_struct4;
+typedef union {
+ aligned_struct4 s4; // expected-note{{alignment of first field}}
+ aligned_struct8 s8; // expected-warning{{alignment of field}}
+} TU1 __attribute__((transparent_union));
+
+typedef union {
+ char c; // expected-note{{size of first field is 8 bits}}
+ int i; // expected-warning{{size of field}}
+} TU2 __attribute__((transparent_union));
+
+typedef union {
+ float f; // expected-warning{{floating}}
+} TU3 __attribute__((transparent_union));
+
+typedef union { } TU4 __attribute__((transparent_union)); // expected-warning{{field}}
More information about the cfe-commits
mailing list