> Patch fixes testcases like:
> static int *p = (int []){2, 4};
>
> and
>
> typedef struct Test {int a;int b;} Test;
> static Test* ll = &(Test) {0,0};
>
> so that they get through sema correctly.
>
> This patch fixes a few underlying issues:
>
> 1. It was previously not possible to determine (AFAIK) whether a
> CompoundLiteralExpr was file scope or not, so this patch propagates
> that information from the parser. This is the biggest change, but is
> mostly mechanical.
> 2. It makes Expr::hasStaticStorage use that information when necessary.
> 3. It makes Expr::isConstantExpr deal with arrays that aren't
> declarations (currently, that's just compound literals).
> 4. It changes the order of the checks in Sema::CheckSingleInitializer
> so that any necessary implicit casts get added before checking for
> whether an initializer is constant.
Here's a current version of this patch; there were some recent changes
that caused merge conflicts.
-Eli
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h (revision 45615)
+++ include/clang/AST/Expr.h (working copy)
@@ -728,12 +728,15 @@
/// synthesized compound expression.
SourceLocation LParenLoc;
Expr *Init;
+ bool FileScope;
public:
- CompoundLiteralExpr(SourceLocation lparenloc, QualType ty, Expr *init) :
- Expr(CompoundLiteralExprClass, ty), LParenLoc(lparenloc), Init(init) {}
+ CompoundLiteralExpr(SourceLocation lparenloc, QualType ty, Expr *init, bool
fileScope) :
+ Expr(CompoundLiteralExprClass, ty), LParenLoc(lparenloc), Init(init),
FileScope(fileScope) {}
const Expr *getInitializer() const { return Init; }
Expr *getInitializer() { return Init; }
+
+ bool isFileScope() const { return FileScope; }
SourceLocation getLParenLoc() const { return LParenLoc; }
Index: include/clang/Parse/Action.h
===================================================================
--- include/clang/Parse/Action.h (revision 45615)
+++ include/clang/Parse/Action.h (working copy)
@@ -401,7 +401,7 @@
return 0;
}
- virtual ExprResult ActOnCompoundLiteral(SourceLocation LParen, TypeTy *Ty,
+ virtual ExprResult ActOnCompoundLiteral(Scope* S, SourceLocation LParen,
TypeTy *Ty,
SourceLocation RParen, ExprTy *Op) {
return 0;
}
Index: Sema/SemaExpr.cpp
===================================================================
--- Sema/SemaExpr.cpp (revision 45615)
+++ Sema/SemaExpr.cpp (working copy)
@@ -15,7 +15,8 @@
#include "SemaUtil.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
-#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Basic/SourceManager.h"
@@ -655,7 +656,7 @@
}
Action::ExprResult Sema::
-ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
+ActOnCompoundLiteral(Scope* S, SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprTy *InitExpr) {
assert((Ty != 0) && "ActOnCompoundLiteral(): missing type");
QualType literalType = QualType::getFromOpaquePtr(Ty);
@@ -667,7 +668,7 @@
if (CheckInitializer(literalExpr, literalType, false))
return 0;
- return new CompoundLiteralExpr(LParenLoc, literalType, literalExpr);
+ return new CompoundLiteralExpr(LParenLoc, literalType, literalExpr,
S->getParent() == 0);
}
Action::ExprResult Sema::
@@ -1940,7 +1941,7 @@
// Otherwise, create a compound literal expression as the base, and
// iteratively process the offsetof designators.
- Expr *Res = new CompoundLiteralExpr(SourceLocation(), ArgTy, 0);
+ Expr *Res = new CompoundLiteralExpr(SourceLocation(), ArgTy, 0, false);
// offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are
a
// GCC extension, diagnose them.
Index: Sema/Sema.h
===================================================================
--- Sema/Sema.h (revision 45615)
+++ Sema/Sema.h (working copy)
@@ -422,8 +422,9 @@
virtual ExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprTy *Op);
- virtual ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
- SourceLocation RParenLoc, ExprTy
*Op);
+ virtual ExprResult ActOnCompoundLiteral(Scope* S, SourceLocation LParenLoc,
+ TypeTy *Ty, SourceLocation RParenLoc,
+ ExprTy *Op);
virtual ExprResult ActOnInitList(SourceLocation LParenLoc,
ExprTy **InitList, unsigned NumInit,
Index: Sema/SemaDecl.cpp
===================================================================
--- Sema/SemaDecl.cpp (revision 45615)
+++ Sema/SemaDecl.cpp (working copy)
@@ -354,6 +354,19 @@
bool Sema::CheckSingleInitializer(Expr *&Init, bool isStatic,
QualType DeclType) {
+ // Get the type before calling CheckSingleAssignmentConstraints(), since
+ // it can promote the expression.
+ QualType InitType = Init->getType();
+
+ AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init);
+ if (DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
+ InitType, Init, "initializing"))
+ return true;
+
+ // This has to be done after checking for assignment
+ // compatibility because those checks might introduce a necessary
+ // implicit conversion (e.g. a static array isn't constant, but a
+ // pointer to a static array is constant).
// FIXME: Remove the isReferenceType check and handle assignment
// to a reference.
SourceLocation loc;
@@ -363,14 +376,7 @@
Diag(loc, diag::err_init_element_not_constant, Init->getSourceRange());
return true;
}
-
- // Get the type before calling CheckSingleAssignmentConstraints(), since
- // it can promote the expression.
- QualType InitType = Init->getType();
-
- AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init);
- return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
- InitType, Init, "initializing");
+ return false;
}
bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot,
Index: AST/Expr.cpp
===================================================================
--- AST/Expr.cpp (revision 45615)
+++ AST/Expr.cpp (working copy)
@@ -418,6 +418,8 @@
return cast<ParenExpr>(this)->getSubExpr()->hasStaticStorage();
case ImplicitCastExprClass:
return cast<ImplicitCastExpr>(this)->getSubExpr()->hasStaticStorage();
+ case CompoundLiteralExprClass:
+ return cast<CompoundLiteralExpr>(this)->isFileScope();
case DeclRefExprClass: {
const Decl *D = cast<DeclRefExpr>(this)->getDecl();
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
@@ -461,12 +463,9 @@
}
case DeclRefExprClass: {
const Decl *D = cast<DeclRefExpr>(this)->getDecl();
- // Accept address of function.
- if (isa<EnumConstantDecl>(D) || isa<FunctionDecl>(D))
+ if (isa<EnumConstantDecl>(D))
return true;
if (Loc) *Loc = getLocStart();
- if (isa<VarDecl>(D))
- return TR->isArrayType();
return false;
}
case UnaryOperatorClass: {
@@ -474,6 +473,8 @@
// C99 6.6p9
if (Exp->getOpcode() == UnaryOperator::AddrOf) {
+ if (Exp->getSubExpr()->getType()->isFunctionType())
+ return true;
if (!Exp->getSubExpr()->hasStaticStorage()) {
if (Loc) *Loc = getLocStart();
return false;
@@ -541,6 +542,19 @@
SubExpr = cast<ImplicitCastExpr>(this)->getSubExpr();
CastLoc = getLocStart();
}
+ if (SubExpr->getType()->isArrayType()) {
+ // FIXME: This check isn't strict enough: the fact that an array has
static scope
+ // doesn't mean the address is computable at compile-time.
+ // FIXME: This code should be shared with the code for
UnaryOperator::AddrOf.
+ if (!SubExpr->hasStaticStorage()) {
+ if (Loc) *Loc = getLocStart();
+ return false;
+ }
+ return true;
+ }
+ // FIXME: Only correct for C, AFAIK. (consider "static Func* f = obj->f;"
in C++)
+ if (SubExpr->getType()->isFunctionType())
+ return true;
if (!SubExpr->isConstantExpr(Ctx, Loc)) {
if (Loc) *Loc = SubExpr->getLocStart();
return false;
Index: AST/StmtSerialization.cpp
===================================================================
--- AST/StmtSerialization.cpp (revision 45615)
+++ AST/StmtSerialization.cpp (working copy)
@@ -392,13 +392,15 @@
S.Emit(getType());
S.Emit(getLParenLoc());
S.EmitOwnedPtr(Init);
+ S.EmitBool(isFileScope());
}
CompoundLiteralExpr* CompoundLiteralExpr::CreateImpl(Deserializer& D) {
QualType Q = QualType::ReadVal(D);
SourceLocation L = SourceLocation::ReadVal(D);
Expr* Init = D.ReadOwnedPtr<Expr>();
- return new CompoundLiteralExpr(L, Q, Init);
+ bool fileScope = D.ReadBool();
+ return new CompoundLiteralExpr(L, Q, Init, fileScope);
}
void CompoundStmt::EmitImpl(Serializer& S) const {
Index: Driver/RewriteTest.cpp
===================================================================
--- Driver/RewriteTest.cpp (revision 45615)
+++ Driver/RewriteTest.cpp (working copy)
@@ -1322,7 +1322,7 @@
InitListExpr *ILE = new InitListExpr(SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation());
- CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType,
ILE);
+ CompoundLiteralExpr *StrRep = new CompoundLiteralExpr(CFConstantStrType,
ILE, false);
// struct NSConstantString *
expType = Context->getPointerType(StrRep->getType());
Unop = new UnaryOperator(StrRep, UnaryOperator::AddrOf, expType,
@@ -1455,7 +1455,7 @@
&InitExprs[0], InitExprs.size(),
SourceLocation());
CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(SourceLocation(),
- superType, ILE);
+ superType, ILE,
false);
// struct objc_super *
Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
@@ -1508,7 +1508,7 @@
&InitExprs[0], InitExprs.size(),
SourceLocation());
CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(SourceLocation(),
- superType, ILE);
+ superType, ILE,
false);
// struct objc_super *
Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
Index: Parse/ParseExpr.cpp
===================================================================
--- Parse/ParseExpr.cpp (revision 45615)
+++ Parse/ParseExpr.cpp (working copy)
@@ -976,7 +976,7 @@
Result = ParseInitializer();
ExprType = CompoundLiteral;
if (!Result.isInvalid)
- return Actions.ActOnCompoundLiteral(OpenLoc, Ty, RParenLoc,
Result.Val);
+ return Actions.ActOnCompoundLiteral(CurScope, OpenLoc, Ty, RParenLoc,
Result.Val);
} else if (ExprType == CastExpr) {
// Note that this doesn't parse the subsequence cast-expression, it just
// returns the parsed type to the callee.
_______________________________________________
cfe-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev