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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70419 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 99ed741..2de1ef3 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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;
}