]> granicus.if.org Git - clang/commitdiff
Add VarDecl::isThisDeclarationADefinition(), which properly encapsulates the logic...
authorSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 31 Jan 2010 22:27:38 +0000 (22:27 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 31 Jan 2010 22:27:38 +0000 (22:27 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94968 91177308-0d34-0410-b5e6-96231b3b80d8

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

index d7d7937773f1798c9de641b2eaccda2886194031..17ee3e54dadf3c863adf9bb5e453517443fedba2 100644 (file)
@@ -538,6 +538,7 @@ public:
   /// };
   /// \endcode
   bool isStaticDataMember() const {
+    // If it wasn't static, it would be a FieldDecl.
     return getDeclContext()->isRecord();
   }
 
@@ -546,6 +547,26 @@ public:
     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 @@ public:
     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 46f7117f2ce6684ef1fe1f61e4abf19db388a533..d75d355fdcf0da4e5069a5bcc70d2cd33267147b 100644 (file)
@@ -480,6 +480,82 @@ VarDecl *VarDecl::getCanonicalDecl() {
   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 @@ VarDecl *VarDecl::getOutOfLineDefinition() {
   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 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
 }
 
 TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
-  if (MemberSpecializationInfo *MSI
-        = getASTContext().getInstantiatedFromStaticDataMember(this))
+  if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
     return MSI->getTemplateSpecializationKind();
   
   return TSK_Undeclared;
index 259355145aa3099edcd988498418f843798ca812..bd93cf6b08ce9b1b009dbb5bcc3e6d7f46937430 100644 (file)
@@ -2464,11 +2464,10 @@ void PCHReader::InitializeSema(Sema &S) {
   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,
index 9909c95847eea04e5d1b90a52b544a766691cdd5..caf1ce47a18c685f5b92e1fddca530b738ac8c61 100644 (file)
@@ -1960,13 +1960,11 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
   }
 
   // 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
index 171101bb96de6e68ae873944756ba108f09eeab6..c0e7572cddea8db6eb040f515a48ba29851e0c9b 100644 (file)
@@ -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 @@ void Sema::ActOnEndOfTranslationUnit() {
   //   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
index 7f4806d3050d18566149043ea082a42c012c879a..54d36357be27f28ff25438f27489c9b71479b52e 100644 (file)
@@ -272,14 +272,8 @@ public:
   ///     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 };
index 398c156f9b57bffbcffb93126ed6a538d8a67b19..a493a29a5d2304582edf5ad6a58e8ad8701ac27d 100644 (file)
@@ -3570,14 +3570,6 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
   // 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 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
     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 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
     // 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(),