[cfe-commits] r94968 - in /cfe/trunk: include/clang/AST/Decl.h lib/AST/Decl.cpp lib/Frontend/PCHReader.cpp lib/Frontend/PCHWriter.cpp lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Sun Jan 31 14:27:38 PST 2010


Author: cornedbee
Date: Sun Jan 31 16:27:38 2010
New Revision: 94968

URL: http://llvm.org/viewvc/llvm-project?rev=94968&view=rev
Log:
Add VarDecl::isThisDeclarationADefinition(), which properly encapsulates the logic for when a variable declaration is a (possibly tentativ) definition. Add a few functions building on this, and shift C tentative definition handling over to this new functionality. This shift also kills the Sema::TentativeDefinitions map and instead simply stores all declarations in the renamed list. The correct handling for multiple tentative definitions is instead shifted to the final walk of the list.

Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Frontend/PCHReader.cpp
    cfe/trunk/lib/Frontend/PCHWriter.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Sun Jan 31 16:27:38 2010
@@ -538,6 +538,7 @@
   /// };
   /// \endcode
   bool isStaticDataMember() const {
+    // If it wasn't static, it would be a FieldDecl.
     return getDeclContext()->isRecord();
   }
 
@@ -546,6 +547,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 Get the tentative definition that acts as the real definition in
+  /// a TU. Returns null if there is a proper definition available.
+  const VarDecl *getActingDefinition() const;
+  VarDecl *getActingDefinition();
+
+  /// \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
@@ -579,10 +600,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;

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=94968&r1=94967&r2=94968&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Sun Jan 31 16:27:38 2010
@@ -480,6 +480,82 @@
   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;
+}
+
+const VarDecl *VarDecl::getActingDefinition() const {
+  return const_cast<VarDecl*>(this)->getActingDefinition();
+}
+
+VarDecl *VarDecl::getActingDefinition() {
+  DefinitionKind Kind = isThisDeclarationADefinition();
+  if (Kind != TentativeDefinition)
+    return 0;
+
+  VarDecl *LastTentative = false;
+  VarDecl *First = getFirstDeclaration();
+  for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
+       I != E; ++I) {
+    Kind = (*I)->isThisDeclarationADefinition();
+    if (Kind == Definition)
+      return 0;
+    else if (Kind == TentativeDefinition)
+      LastTentative = *I;
+  }
+  return LastTentative;
+}
+
+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 +597,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 +614,7 @@
 }
 
 TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
-  if (MemberSpecializationInfo *MSI
-        = getASTContext().getInstantiatedFromStaticDataMember(this))
+  if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
     return MSI->getTemplateSpecializationKind();
   
   return TSK_Undeclared;

Modified: cfe/trunk/lib/Frontend/PCHReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=94968&r1=94967&r2=94968&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHReader.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReader.cpp Sun Jan 31 16:27:38 2010
@@ -2464,11 +2464,10 @@
   PreloadedDecls.clear();
 
   // If there were any tentative definitions, deserialize them and add
-  // them to Sema's table of tentative definitions.
+  // them to Sema's list of tentative definitions.
   for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
     VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I]));
-    SemaObj->TentativeDefinitions[Var->getDeclName()] = Var;
-    SemaObj->TentativeDefinitionList.push_back(Var->getDeclName());
+    SemaObj->TentativeDefinitions.push_back(Var);
   }
 
   // If there were any locally-scoped external declarations,

Modified: cfe/trunk/lib/Frontend/PCHWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=94968&r1=94967&r2=94968&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriter.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriter.cpp Sun Jan 31 16:27:38 2010
@@ -1960,13 +1960,11 @@
   }
 
   // Build a record containing all of the tentative definitions in this file, in
-  // TentativeDefinitionList order.  Generally, this record will be empty for
+  // TentativeDefinitions order.  Generally, this record will be empty for
   // headers.
   RecordData TentativeDefinitions;
-  for (unsigned i = 0, e = SemaRef.TentativeDefinitionList.size(); i != e; ++i){
-    VarDecl *VD =
-      SemaRef.TentativeDefinitions.lookup(SemaRef.TentativeDefinitionList[i]);
-    if (VD) AddDeclRef(VD, TentativeDefinitions);
+  for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) {
+    AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions);
   }
 
   // Build a record containing all of the locally-scoped external

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Sun Jan 31 16:27:38 2010
@@ -15,6 +15,7 @@
 #include "Sema.h"
 #include "TargetAttributesSema.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/APFloat.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
@@ -472,12 +473,14 @@
   //   translation unit contains a file scope declaration of that
   //   identifier, with the composite type as of the end of the
   //   translation unit, with an initializer equal to 0.
-  for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) {
-    VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]);
-
-    // If the tentative definition was completed, it will be in the list, but
-    // not the map.
-    if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
+  llvm::SmallSet<VarDecl *, 32> Seen;
+  for (unsigned i = 0, e = TentativeDefinitions.size(); i != e; ++i) {
+    VarDecl *VD = TentativeDefinitions[i]->getActingDefinition();
+
+    // If the tentative definition was completed, getActingDefinition() returns
+    // null. If we've already seen this variable before, insert()'s second
+    // return value is false.
+    if (VD == 0 || VD->isInvalidDecl() || !Seen.insert(VD))
       continue;
 
     if (const IncompleteArrayType *ArrayT

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sun Jan 31 16:27:38 2010
@@ -272,14 +272,8 @@
   ///     not visible.
   llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls;
 
-  /// \brief The set of tentative declarations seen so far in this
-  /// translation unit for which no definition has been seen.
-  ///
-  /// The tentative declarations are indexed by the name of the
-  /// declaration, and only the most recent tentative declaration for
-  /// a given variable will be recorded here.
-  llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions;
-  std::vector<DeclarationName> TentativeDefinitionList;
+  /// \brief All the tentative definitions encountered in the TU.
+  std::vector<VarDecl *> TentativeDefinitions;
 
   struct DelayedDiagnostic {
     enum DDKind { Deprecation, Access };

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Jan 31 16:27:38 2010
@@ -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,20 +3594,8 @@
     QualType Type = Var->getType();
 
     // Record tentative definitions.
-    if (Var->isTentativeDefinition(Context)) {
-      std::pair<llvm::DenseMap<DeclarationName, VarDecl *>::iterator, bool>
-        InsertPair =
-           TentativeDefinitions.insert(std::make_pair(Var->getDeclName(), Var));
-
-      // Keep the latest definition in the map.  If we see 'int i; int i;' we
-      // want the second one in the map.
-      InsertPair.first->second = Var;
-
-      // However, for the list, we don't care about the order, just make sure
-      // that there are no dupes for a given declaration name.
-      if (InsertPair.second)
-        TentativeDefinitionList.push_back(Var->getDeclName());
-    }
+    if (Var->isTentativeDefinitionNow())
+      TentativeDefinitions.push_back(Var);
 
     // C++ [dcl.init.ref]p3:
     //   The initializer can be omitted for a reference only in a
@@ -3794,7 +3774,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(),





More information about the cfe-commits mailing list