Hi,

Attached patch reimplements the "is a variable declaration a definition"
code. This currently adds some stuff and replaces isTentativeDefinition.
Follow-ups will then move more code over and eventually fix the C++
redefinition issues. But I'd like this part of the code reviewed before
I commit it. All test cases pass.

Sebastian
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h	(revision 94752)
+++ include/clang/AST/Decl.h	(working copy)
@@ -537,6 +537,7 @@
   /// };
   /// \endcode
   bool isStaticDataMember() const {
+    // If it wasn't static, it would be a FieldDecl.
     return getDeclContext()->isRecord();
   }
 
@@ -545,6 +546,26 @@
     return const_cast<VarDecl*>(this)->getCanonicalDecl();
   }
 
+  enum DefinitionKind {
+    DeclarationOnly,      ///< This declaration is only a declaration.
+    TentativeDefinition,  ///< This declaration is a tentative definition.
+    Definition            ///< This declaration is definitely a definition.
+  };
+
+  /// \brief Check whether this declaration is a definition. If this could be
+  /// a tentative definition (in C), don't check whether there's an overriding
+  /// definition.
+  DefinitionKind isThisDeclarationADefinition() const;
+
+  /// \brief Determine whether this declaration acts as a definition. This is
+  /// the case if it either is a definition, or the last tentative definition
+  /// in the TU if there is no real definition.
+  bool actsAsDefinition() const;
+
+  /// \brief Determine whether this is a tentative definition of a
+  /// variable in C.
+  bool isTentativeDefinitionNow() const;
+
   /// \brief Retrieve the definition of this variable, which may come
   /// from a previous declaration. Def will be set to the VarDecl that
   /// contains the initializer, and the result will be that
@@ -578,10 +599,9 @@
     return false;
   }
 
-  /// \brief Determine whether this is a tentative definition of a
-  /// variable in C.
-  bool isTentativeDefinition(ASTContext &Context) const;
-
+  bool hasInit() const {
+    return !Init.isNull();
+  }
   const Expr *getInit() const {
     if (Init.isNull())
       return 0;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 94752)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -3570,14 +3570,6 @@
   // Attach the initializer to the decl.
   VDecl->setInit(Context, Init);
 
-  // If the previous declaration of VDecl was a tentative definition,
-  // remove it from the set of tentative definitions.
-  if (VDecl->getPreviousDeclaration() &&
-      VDecl->getPreviousDeclaration()->isTentativeDefinition(Context)) {
-    bool Deleted = TentativeDefinitions.erase(VDecl->getDeclName());
-    assert(Deleted && "Unrecorded tentative definition?"); Deleted=Deleted;
-  }
-
   if (getLangOptions().CPlusPlus) {
     // Make sure we mark the destructor as used if necessary.
     QualType InitType = VDecl->getType();
@@ -3602,7 +3594,7 @@
     QualType Type = Var->getType();
 
     // Record tentative definitions.
-    if (Var->isTentativeDefinition(Context)) {
+    if (Var->isTentativeDefinitionNow()) {
       std::pair<llvm::DenseMap<DeclarationName, VarDecl *>::iterator, bool>
         InsertPair =
            TentativeDefinitions.insert(std::make_pair(Var->getDeclName(), Var));
@@ -3794,7 +3786,8 @@
     // storage-class specifier or with the storage-class specifier "static",
     // constitutes a tentative definition. Note: A tentative definition with
     // external linkage is valid (C99 6.2.2p5).
-    if (IDecl->isTentativeDefinition(Context) && !IDecl->isInvalidDecl()) {
+    if (IDecl->isThisDeclarationADefinition() == VarDecl::TentativeDefinition &&
+        !IDecl->isInvalidDecl()) {
       if (const IncompleteArrayType *ArrayT
           = Context.getAsIncompleteArrayType(T)) {
         if (RequireCompleteType(IDecl->getLocation(),
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp	(revision 94752)
+++ lib/Sema/Sema.cpp	(working copy)
@@ -477,7 +477,7 @@
 
     // If the tentative definition was completed, it will be in the list, but
     // not the map.
-    if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
+    if (VD == 0 || VD->isInvalidDecl() || !VD->actsAsDefinition())
       continue;
 
     if (const IncompleteArrayType *ArrayT
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp	(revision 94752)
+++ lib/AST/Decl.cpp	(working copy)
@@ -480,6 +480,81 @@
   return getFirstDeclaration();
 }
 
+VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const {
+  // C++ [basic.def]p2:
+  //   A declaration is a definition unless [...] it contains the 'extern'
+  //   specifier or a linkage-specification and neither an initializer [...],
+  //   it declares a static data member in a class declaration [...].
+  // C++ [temp.expl.spec]p15:
+  //   An explicit specialization of a static data member of a template is a
+  //   definition if the declaration includes an initializer; otherwise, it is
+  //   a declaration.
+  if (isStaticDataMember()) {
+    if (isOutOfLine() && (hasInit() ||
+          getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
+      return Definition;
+    else
+      return DeclarationOnly;
+  }
+  // C99 6.7p5:
+  //   A definition of an identifier is a declaration for that identifier that
+  //   [...] causes storage to be reserved for that object.
+  // Note: that applies for all non-file-scope objects.
+  // C99 6.9.2p1:
+  //   If the declaration of an identifier for an object has file scope and an
+  //   initializer, the declaration is an external definition for the identifier
+  if (hasInit())
+    return Definition;
+  // AST for 'extern "C" int foo;' is annotated with 'extern'.
+  if (hasExternalStorage())
+    return DeclarationOnly;
+
+  // C99 6.9.2p2:
+  //   A declaration of an object that has file scope without an initializer,
+  //   and without a storage class specifier or the scs 'static', constitutes
+  //   a tentative definition.
+  // No such thing in C++.
+  if (!getASTContext().getLangOptions().CPlusPlus && isFileVarDecl())
+    return TentativeDefinition;
+
+  // What's left is (in C, block-scope) declarations without initializers or
+  // external storage. These are definitions.
+  return Definition;
+}
+
+bool VarDecl::actsAsDefinition() const {
+  DefinitionKind Kind = isThisDeclarationADefinition();
+  switch (Kind) {
+  case DeclarationOnly: return false;
+  case Definition: return true;
+  case TentativeDefinition: break;
+  }
+
+  bool LastIsThis = false;
+  const VarDecl *First = getFirstDeclaration();
+  for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
+       I != E; ++I) {
+    Kind = (*I)->isThisDeclarationADefinition();
+    if (Kind == Definition)
+      return false;
+    else if (Kind == TentativeDefinition)
+      LastIsThis = (*I == this);
+  }
+  return LastIsThis;
+}
+
+bool VarDecl::isTentativeDefinitionNow() const {
+  DefinitionKind Kind = isThisDeclarationADefinition();
+  if (Kind != TentativeDefinition)
+    return false;
+
+  for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+    if ((*I)->isThisDeclarationADefinition() == Definition)
+      return false;
+  }
+  return true;  
+}
+
 const Expr *VarDecl::getDefinition(const VarDecl *&Def) const {
   redecl_iterator I = redecls_begin(), E = redecls_end();
   while (I != E && !I->getInit())
@@ -521,15 +596,6 @@
   return 0;
 }
 
-bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
-  if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
-    return false;
-
-  const VarDecl *Def = 0;
-  return (!getDefinition(Def) &&
-          (getStorageClass() == None || getStorageClass() == Static));
-}
-
 void VarDecl::setInit(ASTContext &C, Expr *I) {
   if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
     Eval->~EvaluatedStmt();
@@ -547,8 +613,7 @@
 }
 
 TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
-  if (MemberSpecializationInfo *MSI
-        = getASTContext().getInstantiatedFromStaticDataMember(this))
+  if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
     return MSI->getTemplateSpecializationKind();
   
   return TSK_Undeclared;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to