// FIXME: This can be packed into the bitfields in Decl.
unsigned SClass : 3;
bool ThreadSpecified : 1;
+ bool HasCXXDirectInit : 1;
// Move to DeclGroup when it is implemented.
SourceLocation TypeSpecStartLoc;
QualType T, StorageClass SC, ScopedDecl *PrevDecl,
SourceLocation TSSL = SourceLocation())
: ValueDecl(DK, DC, L, Id, T, PrevDecl), Init(0),
- ThreadSpecified(false), TypeSpecStartLoc(TSSL) { SClass = SC; }
+ ThreadSpecified(false), HasCXXDirectInit(false),
+ TypeSpecStartLoc(TSSL) { SClass = SC; }
public:
static VarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
bool isThreadSpecified() const {
return ThreadSpecified;
}
+
+ void setCXXDirectInitializer(bool T) { HasCXXDirectInit = T; }
+
+ /// hasCXXDirectInitializer - If true, the initializer was a direct
+ /// initializer, e.g: "int x(1);". The Init expression will be an expression
+ /// that constructs the type with functional notation, e.g. for:
+ ///
+ /// int x(1);
+ ///
+ /// hasCXXDirectInitializer will be true,
+ /// Init expression will be a "int(1)" functional-cast expression.
+ ///
+ /// Clients can distinguish between "int x(1);" and "int x = int(1);" by
+ /// checking hasCXXDirectInitializer.
+ ///
+ bool hasCXXDirectInitializer() const {
+ return HasCXXDirectInit;
+ }
/// hasLocalStorage - Returns true if a variable with function scope
/// is a non-static local variable.
SourceLocation EqualLoc,
ExprTy *defarg) {
}
+
+ /// AddCXXDirectInitializerToDecl - This action is called immediately after
+ /// ActOnDeclarator, when a C++ direct initializer is present.
+ /// e.g: "int x(1);"
+ virtual void AddCXXDirectInitializerToDecl(DeclTy *Dcl,
+ SourceLocation LParenLoc,
+ ExprTy **Exprs, unsigned NumExprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ return;
+ }
//===------------------------- C++ Expressions --------------------------===//
llvm::SmallVector<DeclaratorChunk, 8> DeclTypeInfo;
// InvalidType - Set by Sema::GetTypeForDeclarator().
- bool InvalidType;
+ bool InvalidType : 1;
+
+ /// GroupingParens - Set by Parser::ParseParenDeclarator().
+ bool GroupingParens : 1;
/// AttrList - Attributes.
AttributeList *AttrList;
public:
Declarator(const DeclSpec &ds, TheContext C)
- : DS(ds), Identifier(0), Context(C), InvalidType(false), AttrList(0),
- AsmLabel(0) {
+ : DS(ds), Identifier(0), Context(C), InvalidType(false),
+ GroupingParens(false), AttrList(0), AsmLabel(0) {
}
~Declarator() {
bool mayHaveIdentifier() const {
return Context != TypeNameContext;
}
+
+ /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be
+ /// followed by a C++ direct initializer, e.g. "int x(1);".
+ bool mayBeFollowedByCXXDirectInit() const {
+ return !hasGroupingParens() &&
+ (Context == FileContext ||
+ Context == BlockContext ||
+ Context == ForContext );
+ }
/// isPastIdentifier - Return true if we have parsed beyond the point where
/// the
void setInvalidType(bool flag) { InvalidType = flag; }
bool getInvalidType() const { return InvalidType; }
+
+ void setGroupingParens(bool flag) { GroupingParens = flag; }
+ bool hasGroupingParens() const { return GroupingParens; }
};
/// FieldDeclarator - This little struct is used to capture information about
/// declarator '=' initializer
/// [GNU] declarator simple-asm-expr[opt] attributes[opt]
/// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer
+/// [C++] declarator initializer[opt]
+///
+/// [C++] initializer:
+/// [C++] '=' initializer-clause
+/// [C++] '(' expression-list ')'
///
Parser::DeclTy *Parser::
ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
return 0;
}
Actions.AddInitializerToDecl(LastDeclInGroup, Init.Val);
+ } else if (Tok.is(tok::l_paren)) {
+ // Parse C++ direct initializer: '(' expression-list ')'
+ SourceLocation LParenLoc = ConsumeParen();
+ ExprListTy Exprs;
+ CommaLocsTy CommaLocs;
+
+ bool InvalidExpr = false;
+ if (ParseExpressionList(Exprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ InvalidExpr = true;
+ }
+ // Match the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (!InvalidExpr) {
+ assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
+ "Unexpected number of commas!");
+ Actions.AddCXXDirectInitializerToDecl(LastDeclInGroup, LParenLoc,
+ &Exprs[0], Exprs.size(),
+ &CommaLocs[0], RParenLoc);
+ }
}
// If we don't have a comma, it is either the end of the list (a ';') or an
while (1) {
if (Tok.is(tok::l_paren)) {
+ // The paren may be part of a C++ direct initializer, eg. "int x(1);".
+ // In such a case, check if we actually have a function declarator; if it
+ // is not, the declarator has been fully parsed.
+ if (getLang().CPlusPlus && D.mayBeFollowedByCXXDirectInit() &&
+ !isCXXFunctionDeclarator())
+ break;
ParseFunctionDeclarator(ConsumeParen(), D);
} else if (Tok.is(tok::l_square)) {
ParseBracketDeclarator(D);
// direct-declarator: '(' declarator ')'
// direct-declarator: '(' attributes declarator ')'
if (isGrouping) {
+ D.setGroupingParens(true);
+
if (Tok.is(tok::kw___attribute))
D.AddAttributes(ParseAttributes());
Tok.is(tok::comma) || // int X(), -> not a function def
Tok.is(tok::semi) || // int X(); -> not a function def
Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def
- Tok.is(tok::kw___attribute)) { // int X() __attr__ -> not a function def
+ Tok.is(tok::kw___attribute) || // int X() __attr__ -> not a function def
+ (getLang().CPlusPlus &&
+ Tok.is(tok::l_paren)) ) { // int X(0) -> not a function def [C++]
// FALL THROUGH.
} else if (DeclaratorInfo.isFunctionDeclarator() &&
(Tok.is(tok::l_brace) || // int X() {}
SourceLocation LBrace);
virtual void ActOnFinishNamespaceDef(DeclTy *Dcl, SourceLocation RBrace);
+ /// AddCXXDirectInitializerToDecl - This action is called immediately after
+ /// ActOnDeclarator, when a C++ direct initializer is present.
+ /// e.g: "int x(1);"
+ virtual void AddCXXDirectInitializerToDecl(DeclTy *Dcl,
+ SourceLocation LParenLoc,
+ ExprTy **Exprs, unsigned NumExprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc);
+
/// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
virtual ExprResult ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
SourceLocation LAngleBracketLoc, TypeTy *Ty,
Namespc->setRBracLoc(RBrace);
PopDeclContext();
}
+
+
+/// AddCXXDirectInitializerToDecl - This action is called immediately after
+/// ActOnDeclarator, when a C++ direct initializer is present.
+/// e.g: "int x(1);"
+void Sema::AddCXXDirectInitializerToDecl(DeclTy *Dcl, SourceLocation LParenLoc,
+ ExprTy **ExprTys, unsigned NumExprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ Decl *RealDecl = static_cast<Decl *>(Dcl);
+ assert(NumExprs != 0 && ExprTys && "missing expressions");
+
+ // If there is no declaration, there was an error parsing it. Just ignore
+ // the initializer.
+ if (RealDecl == 0) {
+ for (int i=0; i != NumExprs; ++i)
+ delete static_cast<Expr *>(ExprTys[i]);
+ return;
+ }
+
+ VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
+ if (!VDecl) {
+ Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
+ RealDecl->setInvalidDecl();
+ return;
+ }
+
+ // We will treat direct-initialization as a copy-initialization with a
+ // type-construction expression of the variable's type. In plain english:
+ // We will treat:
+ // int x(1); -as-> int x = int(1);
+ // and for class types:
+ // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c);
+ //
+ // Clients that want to distinguish between the two forms, can check for
+ // direct initializer using VarDecl::hasCXXDirectInitializer().
+ // A major benefit is that clients that don't particularly care about which
+ // exactly form was it (like the CodeGen) can handle both cases without
+ // special case code.
+ //
+ // According to the C++ standard, there shouldn't be semantic differences
+ // between a direct-initialization and a copy-initialization where the
+ // destination type is the same as the source type:
+ //
+ // C++ 8.5p11:
+ // The form of initialization (using parentheses or '=') is generally
+ // insignificant, but does matter when the entity being initialized has a
+ // class type; see below.
+ // C++ 8.5p15:
+ // [...]
+ // If the initialization is direct-initialization, or if it is
+ // copy-initialization where the cv-unqualified version of the source type is
+ // the same class as, or a derived class of, the class of the destination,
+ // constructors are considered. The applicable constructors are enumerated
+ // (13.3.1.3), and the best one is chosen through overload resolution (13.3).
+ // The constructor so selected is called to initialize the object, with the
+ // initializer expression(s) as its argument(s). If no constructor applies, or
+ // the overload resolution is ambiguous, the initialization is ill-formed.
+ // [...]
+ //
+ // Note that according to C++ 8.5p15, the same semantic process is applied
+ // to both the direct-initialization and copy-initialization,
+ // if destination type == source type.
+
+ // Get an expression for constructing the type of the variable, using the
+ // expression list of the initializer.
+ ExprResult Res = ActOnCXXTypeConstructExpr(VDecl->getLocation(),
+ VDecl->getType().getAsOpaquePtr(),
+ LParenLoc, ExprTys, NumExprs,
+ CommaLocs, RParenLoc);
+ if (Res.isInvalid) {
+ RealDecl->setInvalidDecl();
+ return;
+ }
+
+ // Performs additional semantic checks.
+ AddInitializerToDecl(Dcl, Res.Val);
+ // Let clients know that initialization was done with a direct initializer.
+ VDecl->setCXXDirectInitializer(true);
+}
--- /dev/null
+// RUN: clang -fsyntax-only %s
+
+int x(1);
+
+void f() {
+ int x(1);
+ for (int x(1);;) {}
+}