[cfe-commits] r57178 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h lib/Parse/ParseDecl.cpp lib/Parse/Parser.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp test/SemaCXX/direct-initializer.cpp

Argiris Kirtzidis akyrtzi at gmail.com
Mon Oct 6 10:10:35 PDT 2008


Author: akirtzidis
Date: Mon Oct  6 12:10:33 2008
New Revision: 57178

URL: http://llvm.org/viewvc/llvm-project?rev=57178&view=rev
Log:
Implement support for C++ direct initializers in declarations, e.g. "int x(1);".

This is how this kind of initializers appear in the AST:
-The Init expression of the VarDecl is a functional type construction (of the VarDecl's type).
-The new VarDecl::hasCXXDirectInitializer() returns true.

e.g, for "int x(1);":
-VarDecl 'x' has Init with expression "int(1)" (CXXFunctionalCastExpr).
-hasCXXDirectInitializer() of VarDecl 'x' returns true.

A major benefit is that clients that don't particularly care about which exactly form was the initializer can handle both cases without special case code.
Note that codegening works now for "int x(1);" without any changes to CodeGen.

Added:
    cfe/trunk/test/SemaCXX/direct-initializer.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=57178&r1=57177&r2=57178&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Mon Oct  6 12:10:33 2008
@@ -229,6 +229,7 @@
   // 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;
@@ -238,7 +239,8 @@
           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,
@@ -257,6 +259,24 @@
   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.

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=57178&r1=57177&r2=57178&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Mon Oct  6 12:10:33 2008
@@ -571,6 +571,17 @@
                                          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 --------------------------===//
   

Modified: cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=57178&r1=57177&r2=57178&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Mon Oct  6 12:10:33 2008
@@ -595,7 +595,10 @@
   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;
@@ -605,8 +608,8 @@
   
 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() {
@@ -666,6 +669,15 @@
   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
@@ -725,6 +737,9 @@
 
   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

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=57178&r1=57177&r2=57178&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Oct  6 12:10:33 2008
@@ -245,6 +245,11 @@
 ///         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) {
@@ -284,6 +289,27 @@
         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
@@ -1200,6 +1226,12 @@
   
   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);
@@ -1247,6 +1279,8 @@
   // direct-declarator: '(' declarator ')'
   // direct-declarator: '(' attributes declarator ')'
   if (isGrouping) {
+    D.setGroupingParens(true);
+
     if (Tok.is(tok::kw___attribute))
       D.AddAttributes(ParseAttributes());
     

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=57178&r1=57177&r2=57178&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Mon Oct  6 12:10:33 2008
@@ -449,7 +449,9 @@
       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() {}

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=57178&r1=57177&r2=57178&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Oct  6 12:10:33 2008
@@ -593,6 +593,15 @@
                                         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,

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=57178&r1=57177&r2=57178&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Oct  6 12:10:33 2008
@@ -548,3 +548,83 @@
   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);
+}

Added: cfe/trunk/test/SemaCXX/direct-initializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/direct-initializer.cpp?rev=57178&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/direct-initializer.cpp (added)
+++ cfe/trunk/test/SemaCXX/direct-initializer.cpp Mon Oct  6 12:10:33 2008
@@ -0,0 +1,8 @@
+// RUN: clang -fsyntax-only %s 
+
+int x(1);
+
+void f() {
+  int x(1);
+  for (int x(1);;) {}
+}





More information about the cfe-commits mailing list