[cfe-commits] r67715 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaTemplate/fibonacci.cpp test/SemaTemplate/instantiate-static-var.cpp

Douglas Gregor dgregor at apple.com
Wed Mar 25 16:32:15 PDT 2009


Author: dgregor
Date: Wed Mar 25 18:32:15 2009
New Revision: 67715

URL: http://llvm.org/viewvc/llvm-project?rev=67715&view=rev
Log:
Implement template instantiation for static data members of class
templates, including in-class initializers. For example:

  template<typename T, T Divisor>
  class X {
  public:
    static const T value = 10 / Divisor;
  };

instantiated with, e.g.,

  X<int, 5>::value

to get the value '2'.


Added:
    cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp
Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaTemplate/fibonacci.cpp

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Mar 25 18:32:15 2009
@@ -345,6 +345,8 @@
                                      QualType R, Decl* LastDeclarator,
                                      NamedDecl* PrevDecl, bool& InvalidDecl,
                                      bool &Redeclaration);
+  bool CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
+                                bool &Redeclaration);
   NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                                      QualType R, Decl *LastDeclarator,
                                      NamedDecl* PrevDecl, 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Mar 25 18:32:15 2009
@@ -1587,11 +1587,6 @@
   if (getLangOptions().CPlusPlus)
     CheckExtraCXXDefaultArguments(D);
 
-  if (R.getTypePtr()->isObjCInterfaceType()) {
-    Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object);
-    InvalidDecl = true;
-  }
-
   VarDecl *NewVD;
   VarDecl::StorageClass SC;
   switch (D.getDeclSpec().getStorageClassSpec()) {
@@ -1641,12 +1636,6 @@
     } else if (SC == VarDecl::None)
       SC = VarDecl::Static;
   }
-
-  // The variable can not have an abstract class type.
-  if (RequireNonAbstractType(D.getIdentifierLoc(), R, 
-                             diag::err_abstract_type_in_decl, 
-                             AbstractVariableType))
-    InvalidDecl = true;
     
   // The variable can not 
   NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), 
@@ -1671,32 +1660,94 @@
                                                         SE->getByteLength())));
   }
 
+  // If name lookup finds a previous declaration that is not in the
+  // same scope as the new declaration, this may still be an
+  // acceptable redeclaration.
+  if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) &&
+      !(NewVD->hasLinkage() &&
+        isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
+    PrevDecl = 0;     
+
+  // Merge the decl with the existing one if appropriate.
+  if (PrevDecl) {
+    if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) {
+      // The user tried to define a non-static data member
+      // out-of-line (C++ [dcl.meaning]p1).
+      Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line)
+        << D.getCXXScopeSpec().getRange();
+      PrevDecl = 0;
+      InvalidDecl = true;
+    }
+  } else if (D.getCXXScopeSpec().isSet()) {
+    // No previous declaration in the qualifying scope.
+    Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member)
+      << Name << D.getCXXScopeSpec().getRange();
+    InvalidDecl = true;
+  }
+
+  if (CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration))
+    InvalidDecl = true;
+
+  // If this is a locally-scoped extern C variable, update the map of
+  // such variables.
+  if (CurContext->isFunctionOrMethod() && NewVD->isExternC(Context) &&
+      !InvalidDecl)
+    RegisterLocallyScopedExternCDecl(NewVD, PrevDecl, S);
+
+  return NewVD;
+}
+
+/// \brief Perform semantic checking on a newly-created variable
+/// declaration.
+///
+/// This routine performs all of the type-checking required for a
+/// variable declaration once it has been build. It is used both to
+/// check variables after they have been parsed and their declarators
+/// have been translated into a declaration, and to check 
+///
+/// \returns true if an error was encountered, false otherwise.
+bool Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
+                                    bool &Redeclaration) {
+  bool Invalid = false;
+
+  QualType T = NewVD->getType();
+
+  if (T->isObjCInterfaceType()) {
+    Diag(NewVD->getLocation(), diag::err_statically_allocated_object);
+    Invalid = true;
+  }
+  
+  // The variable can not have an abstract class type.
+  if (RequireNonAbstractType(NewVD->getLocation(), T,
+                             diag::err_abstract_type_in_decl, 
+                             AbstractVariableType))
+    Invalid = true;
+
   // Emit an error if an address space was applied to decl with local storage.
   // This includes arrays of objects with address space qualifiers, but not
   // automatic variables that point to other address spaces.
   // ISO/IEC TR 18037 S5.1.2
-  if (NewVD->hasLocalStorage() && (NewVD->getType().getAddressSpace() != 0)) {
-    Diag(D.getIdentifierLoc(), diag::err_as_qualified_auto_decl);
-    InvalidDecl = true;
+  if (NewVD->hasLocalStorage() && (T.getAddressSpace() != 0)) {
+    Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl);
+    Invalid = true;
   }
 
-  if (NewVD->hasLocalStorage() && NewVD->getType().isObjCGCWeak()) {
-    Diag(D.getIdentifierLoc(), diag::warn_attribute_weak_on_local);
-  }
+  if (NewVD->hasLocalStorage() && T.isObjCGCWeak())
+    Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
 
-  bool isIllegalVLA = R->isVariableArrayType() && NewVD->hasGlobalStorage();
-  bool isIllegalVM = R->isVariablyModifiedType() && NewVD->hasLinkage();
+  bool isIllegalVLA = T->isVariableArrayType() && NewVD->hasGlobalStorage();
+  bool isIllegalVM = T->isVariablyModifiedType() && NewVD->hasLinkage();
   if (isIllegalVLA || isIllegalVM) {
     bool SizeIsNegative;
     QualType FixedTy =
-        TryToFixInvalidVariablyModifiedType(R, Context, SizeIsNegative);
+        TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative);
     if (!FixedTy.isNull()) {
       Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size);
       NewVD->setType(FixedTy);
-    } else if (R->isVariableArrayType()) {
-      NewVD->setInvalidDecl();
+    } else if (T->isVariableArrayType()) {
+      Invalid = true;
 
-      const VariableArrayType *VAT = Context.getAsVariableArrayType(R);
+      const VariableArrayType *VAT = Context.getAsVariableArrayType(T);
       // FIXME: This won't give the correct result for 
       // int a[10][n];      
       SourceRange SizeRange = VAT->getSizeExpr()->getSourceRange();
@@ -1711,7 +1762,7 @@
         Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage)
             << SizeRange;
     } else {
-      InvalidDecl = true;
+      Invalid = true;
       
       if (NewVD->isFileVarDecl())
         Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope);
@@ -1720,59 +1771,29 @@
     }
   }
 
-  // If name lookup finds a previous declaration that is not in the
-  // same scope as the new declaration, this may still be an
-  // acceptable redeclaration.
-  if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) &&
-      !(NewVD->hasLinkage() &&
-        isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
-    PrevDecl = 0;     
-
   if (!PrevDecl && NewVD->isExternC(Context)) {
     // Since we did not find anything by this name and we're declaring
     // an extern "C" variable, look for a non-visible extern "C"
     // declaration with the same name.
     llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
-      = LocallyScopedExternalDecls.find(Name);
+      = LocallyScopedExternalDecls.find(NewVD->getDeclName());
     if (Pos != LocallyScopedExternalDecls.end())
       PrevDecl = Pos->second;
   }
 
-  // Merge the decl with the existing one if appropriate.
-  if (PrevDecl) {
-    if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) {
-      // The user tried to define a non-static data member
-      // out-of-line (C++ [dcl.meaning]p1).
-      Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line)
-        << D.getCXXScopeSpec().getRange();
-      NewVD->Destroy(Context);
-      return 0;
-    }
+  if (!Invalid && T->isVoidType() && !NewVD->hasExternalStorage()) {
+    Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
+      << T;
+    Invalid = true;
+  }
 
+  if (PrevDecl) {
     Redeclaration = true;
     if (MergeVarDecl(NewVD, PrevDecl))
-      InvalidDecl = true;
-  } else if (D.getCXXScopeSpec().isSet()) {
-    // No previous declaration in the qualifying scope.
-    Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member)
-      << Name << D.getCXXScopeSpec().getRange();
-    InvalidDecl = true;
-  }
-
-  if (!InvalidDecl && R->isVoidType() && !NewVD->hasExternalStorage()) {
-    Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
-      << R;
-    InvalidDecl = true;
+      Invalid = true;
   }
 
-
-  // If this is a locally-scoped extern C variable, update the map of
-  // such variables.
-  if (CurContext->isFunctionOrMethod() && NewVD->isExternC(Context) &&
-      !InvalidDecl)
-    RegisterLocallyScopedExternCDecl(NewVD, PrevDecl, S);
-
-  return NewVD;
+  return NewVD->isInvalidDecl() || Invalid;
 }
 
 NamedDecl* 
@@ -2376,7 +2397,8 @@
           Diag(Loc, diag::err_in_class_initializer_non_constant)
             << Init->getSourceRange();
           VDecl->setInvalidDecl();
-        }
+        } else if (!VDecl->getType()->isDependentType())
+          ImpCastExprToType(Init, VDecl->getType());
       }
     }
   } else if (VDecl->isFileVarDecl()) {

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Mar 25 18:32:15 2009
@@ -42,6 +42,7 @@
     Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
     Decl *VisitNamespaceDecl(NamespaceDecl *D);
     Decl *VisitTypedefDecl(TypedefDecl *D);
+    Decl *VisitVarDecl(VarDecl *D);
     Decl *VisitFieldDecl(FieldDecl *D);
     Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
     Decl *VisitEnumDecl(EnumDecl *D);
@@ -56,6 +57,7 @@
 
     // Base case. FIXME: Remove once we can instantiate everything.
     Decl *VisitDecl(Decl *) { 
+      assert(false && "Template instantiation of unknown declaration kind!");
       return 0;
     }
 
@@ -102,6 +104,45 @@
   return Typedef;
 }
 
+Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
+  // Instantiate the type of the declaration
+  QualType T = SemaRef.InstantiateType(D->getType(), TemplateArgs,
+                                       NumTemplateArgs, 
+                                       D->getTypeSpecStartLoc(),
+                                       D->getDeclName());
+  if (T.isNull())
+    return 0;
+
+  // Build the instantiataed declaration
+  VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
+                                 D->getLocation(), D->getIdentifier(),
+                                 T, D->getStorageClass(),
+                                 D->getTypeSpecStartLoc());
+  Var->setThreadSpecified(D->isThreadSpecified());
+  Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
+  Var->setDeclaredInCondition(D->isDeclaredInCondition());
+ 
+  // FIXME: In theory, we could have a previous declaration for
+  // variables that are not static data members.
+  bool Redeclaration = false;
+  if (SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration))
+    Var->setInvalidDecl();
+
+  Owner->addDecl(Var);
+
+  if (D->getInit()) {
+    OwningExprResult Init 
+      = SemaRef.InstantiateExpr(D->getInit(), TemplateArgs, NumTemplateArgs);
+    if (Init.isInvalid())
+      Var->setInvalidDecl();
+    else
+      SemaRef.AddInitializerToDecl(Var, move(Init),
+                                   D->hasCXXDirectInitializer());
+  }
+
+  return Var;
+}
+
 Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
   bool Invalid = false;
   QualType T = D->getType();

Modified: cfe/trunk/test/SemaTemplate/fibonacci.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/fibonacci.cpp?rev=67715&r1=67714&r2=67715&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/fibonacci.cpp (original)
+++ cfe/trunk/test/SemaTemplate/fibonacci.cpp Wed Mar 25 18:32:15 2009
@@ -25,3 +25,28 @@
 
 int array5[Fibonacci<5>::value == 5? 1 : -1];
 int array10[Fibonacci<10>::value == 55? 1 : -1];
+
+template<unsigned I>
+struct FibonacciEval2;
+
+template<unsigned I>
+struct Fibonacci2 {
+  static const unsigned value 
+    = FibonacciEval2<I-1>::value + FibonacciEval2<I-2>::value;
+};
+
+template<unsigned I>
+struct FibonacciEval2 {
+  static const unsigned value = Fibonacci2<I>::value;
+};
+
+template<> struct Fibonacci2<0> {
+  static const unsigned value = 0;
+};
+
+template<> struct Fibonacci2<1> {
+  static const unsigned value = 1;
+};
+
+int array5_2[Fibonacci2<5>::value == 5? 1 : -1];
+int array10_2[Fibonacci2<10>::value == 55? 1 : -1];

Added: cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp?rev=67715&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp (added)
+++ cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp Wed Mar 25 18:32:15 2009
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, T Divisor>
+class X {
+public:
+  static const T value = 10 / Divisor; // expected-error{{in-class initializer is not an integral constant expression}}
+};
+
+int array1[X<int, 2>::value == 5? 1 : -1];
+X<int, 0> xi0; // expected-note{{in instantiation of template class 'class X<int, 0>' requested here}}
+
+
+template<typename T>
+class Y {
+  static const T value = 0; // expected-error{{'value' can only be initialized if it is a static const integral data member}}
+};
+
+Y<float> fy; // expected-note{{in instantiation of template class 'class Y<float>' requested here}}





More information about the cfe-commits mailing list