]> granicus.if.org Git - clang/commitdiff
A clean-up pass, exploring the unification of traversals of class, variable and funct...
authorLarisse Voufo <lvoufo@google.com>
Fri, 23 Aug 2013 22:21:36 +0000 (22:21 +0000)
committerLarisse Voufo <lvoufo@google.com>
Fri, 23 Aug 2013 22:21:36 +0000 (22:21 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189152 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/RecursiveASTVisitor.h
lib/AST/DeclTemplate.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Serialization/ASTReaderDecl.cpp

index aaa26127d247ad1367961a2ab180ab40c98ae95d..b09b336511a0cad7c99cd810859bf45be0910cf5 100644 (file)
@@ -407,9 +407,12 @@ public:
 private:
   // These are helper methods used by more than one Traverse* method.
   bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
-  bool TraverseClassInstantiations(ClassTemplateDecl *D);
-  bool TraverseVariableInstantiations(VarTemplateDecl *D);
-  bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ;
+#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND)                                   \
+  bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D);
+  DEF_TRAVERSE_TMPL_INST(Class)
+  DEF_TRAVERSE_TMPL_INST(Var)
+  DEF_TRAVERSE_TMPL_INST(Function)
+#undef DEF_TRAVERSE_TMPL_INST
   bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
                                           unsigned Count);
   bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
@@ -1452,110 +1455,44 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
   return true;
 }
 
-// A helper method for traversing the implicit instantiations of a
-// class template.
-template<typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
-    ClassTemplateDecl *D) {
-  ClassTemplateDecl::spec_iterator end = D->spec_end();
-  for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
-    ClassTemplateSpecializationDecl* SD = *it;
-
-    switch (SD->getSpecializationKind()) {
-    // Visit the implicit instantiations with the requested pattern.
-    case TSK_Undeclared:
-    case TSK_ImplicitInstantiation:
-      TRY_TO(TraverseDecl(SD));
-      break;
-
-    // We don't need to do anything on an explicit instantiation
-    // or explicit specialization because there will be an explicit
-    // node for it elsewhere.
-    case TSK_ExplicitInstantiationDeclaration:
-    case TSK_ExplicitInstantiationDefinition:
-    case TSK_ExplicitSpecialization:
-      break;
-    }
-  }
-
-  return true;
-}
-
-DEF_TRAVERSE_DECL(ClassTemplateDecl, {
-    CXXRecordDecl* TempDecl = D->getTemplatedDecl();
-    TRY_TO(TraverseDecl(TempDecl));
-    TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-
-    // By default, we do not traverse the instantiations of
-    // class templates since they do not appear in the user code. The
-    // following code optionally traverses them.
-    //
-    // We only traverse the class instantiations when we see the canonical
-    // declaration of the template, to ensure we only visit them once.
-    if (getDerived().shouldVisitTemplateInstantiations() &&
-        D == D->getCanonicalDecl())
-      TRY_TO(TraverseClassInstantiations(D));
-
-    // Note that getInstantiatedFromMemberTemplate() is just a link
-    // from a template instantiation back to the template from which
-    // it was instantiated, and thus should not be traversed.
-  })
-
-// A helper method for traversing the implicit instantiations of a
-// variable template.
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseVariableInstantiations(
-    VarTemplateDecl *D) {
-  VarTemplateDecl::spec_iterator end = D->spec_end();
-  for (VarTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
-    VarTemplateSpecializationDecl *SD = *it;
-
-    switch (SD->getSpecializationKind()) {
-    // Visit the implicit instantiations with the requested pattern.
-    case TSK_Undeclared:
-    case TSK_ImplicitInstantiation:
-      TRY_TO(TraverseDecl(SD));
-      break;
-
-    // We don't need to do anything on an explicit instantiation
-    // or explicit specialization because there will be an explicit
-    // node for it elsewhere.
-    case TSK_ExplicitInstantiationDeclaration:
-    case TSK_ExplicitInstantiationDefinition:
-    case TSK_ExplicitSpecialization:
-      break;
-    }
-  }
-
-  return true;
+#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND)                                 \
+/* A helper method for traversing the implicit instantiations of a
+   class or variable template. */                                            \
+template<typename Derived>                                                   \
+bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(           \
+    TMPLDECLKIND##TemplateDecl *D) {                                         \
+  TMPLDECLKIND##TemplateDecl::spec_iterator end = D->spec_end();             \
+  for (TMPLDECLKIND##TemplateDecl::spec_iterator it = D->spec_begin();       \
+       it != end; ++it) {                                                    \
+    TMPLDECLKIND##TemplateSpecializationDecl* SD = *it;                      \
+                                                                             \
+    switch (SD->getSpecializationKind()) {                                   \
+    /* Visit the implicit instantiations with the requested pattern. */      \
+    case TSK_Undeclared:                                                     \
+    case TSK_ImplicitInstantiation:                                          \
+      TRY_TO(TraverseDecl(SD));                                              \
+      break;                                                                 \
+                                                                             \
+    /* We don't need to do anything on an explicit instantiation             
+       or explicit specialization because there will be an explicit
+       node for it elsewhere. */                                             \
+    case TSK_ExplicitInstantiationDeclaration:                               \
+    case TSK_ExplicitInstantiationDefinition:                                \
+    case TSK_ExplicitSpecialization:                                         \
+      break;                                                                 \
+    }                                                                        \
+  }                                                                          \
+                                                                             \
+  return true;                                                               \
 }
-
-  // FIXME: Unify traversal for variable templates, class templates and function
-  // templates.
-DEF_TRAVERSE_DECL(VarTemplateDecl, {
-  VarDecl *TempDecl = D->getTemplatedDecl();
-  TRY_TO(TraverseDecl(TempDecl));
-  TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-
-  // By default, we do not traverse the instantiations of
-  // class templates since they do not appear in the user code. The
-  // following code optionally traverses them.
-  //
-  // We only traverse the class instantiations when we see the canonical
-  // declaration of the template, to ensure we only visit them once.
-  if (getDerived().shouldVisitTemplateInstantiations() &&
-      D == D->getCanonicalDecl())
-    TRY_TO(TraverseVariableInstantiations(D));
-
-      // Note that getInstantiatedFromMemberTemplate() is just a link
-      // from a template instantiation back to the template from which
-      // it was instantiated, and thus should not be traversed.
-})
+   
+DEF_TRAVERSE_TMPL_INST(Class)
+DEF_TRAVERSE_TMPL_INST(Var)
 
 // A helper method for traversing the instantiations of a
 // function while skipping its specializations.
 template<typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
+bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
     FunctionTemplateDecl *D) {
   FunctionTemplateDecl::spec_iterator end = D->spec_end();
   for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
@@ -1583,20 +1520,31 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
   return true;
 }
 
-DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
-    TRY_TO(TraverseDecl(D->getTemplatedDecl()));
-    TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-
-    // By default, we do not traverse the instantiations of
-    // function templates since they do not appear in the user code. The
-    // following code optionally traverses them.
-    //
-    // We only traverse the function instantiations when we see the canonical
-    // declaration of the template, to ensure we only visit them once.
-    if (getDerived().shouldVisitTemplateInstantiations() &&
-        D == D->getCanonicalDecl())
-      TRY_TO(TraverseFunctionInstantiations(D));
-  })
+// This macro unifies the traversal of class, variable and function
+// template declarations.
+#define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND)                                 \
+DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, {                              \
+    TRY_TO(TraverseDecl(D->getTemplatedDecl()));                             \
+    TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \
+                                                                             \
+    /* By default, we do not traverse the instantiations of
+       class templates since they do not appear in the user code. The
+       following code optionally traverses them.
+       
+       We only traverse the class instantiations when we see the canonical
+       declaration of the template, to ensure we only visit them once. */    \
+    if (getDerived().shouldVisitTemplateInstantiations() &&                  \
+        D == D->getCanonicalDecl())                                          \
+      TRY_TO(TraverseTemplateInstantiations(D));                             \
+                                                                             \
+    /* Note that getInstantiatedFromMemberTemplate() is just a link
+       from a template instantiation back to the template from which
+       it was instantiated, and thus should not be traversed. */             \
+  })
+
+DEF_TRAVERSE_TMPL_DECL(Class)
+DEF_TRAVERSE_TMPL_DECL(Var)
+DEF_TRAVERSE_TMPL_DECL(Function)
 
 DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
     // D is the "T" in something like
@@ -1690,26 +1638,30 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, {
     TRY_TO(TraverseCXXRecordHelper(D));
   })
 
-DEF_TRAVERSE_DECL(ClassTemplateSpecializationDecl, {
-    // For implicit instantiations ("set<int> x;"), we don't want to
-    // recurse at all, since the instatiated class isn't written in
-    // the source code anywhere.  (Note the instatiated *type* --
-    // set<int> -- is written, and will still get a callback of
-    // TemplateSpecializationType).  For explicit instantiations
-    // ("template set<int>;"), we do need a callback, since this
-    // is the only callback that's made for this instantiation.
-    // We use getTypeAsWritten() to distinguish.
-    if (TypeSourceInfo *TSI = D->getTypeAsWritten())
-      TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
-
-    if (!getDerived().shouldVisitTemplateInstantiations() &&
-        D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
-      // Returning from here skips traversing the
-      // declaration context of the ClassTemplateSpecializationDecl
-      // (embedded in the DEF_TRAVERSE_DECL() macro)
-      // which contains the instantiated members of the class.
-      return true;
-  })
+#define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND) \
+DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, {                \
+    /* For implicit instantiations ("set<int> x;"), we don't want to
+       recurse at all, since the instatiated template isn't written in
+       the source code anywhere.  (Note the instatiated *type* --
+       set<int> -- is written, and will still get a callback of
+       TemplateSpecializationType).  For explicit instantiations
+       ("template set<int>;"), we do need a callback, since this
+       is the only callback that's made for this instantiation.
+       We use getTypeAsWritten() to distinguish. */                          \
+    if (TypeSourceInfo *TSI = D->getTypeAsWritten())                         \
+      TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));                            \
+                                                                             \
+    if (!getDerived().shouldVisitTemplateInstantiations() &&                 \
+        D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)    \
+      /* Returning from here skips traversing the
+         declaration context of the *TemplateSpecializationDecl
+         (embedded in the DEF_TRAVERSE_DECL() macro)
+         which contains the instantiated members of the template. */         \
+      return true;                                                           \
+  })
+
+DEF_TRAVERSE_TMPL_SPEC_DECL(Class)
+DEF_TRAVERSE_TMPL_SPEC_DECL(Var)
 
 template <typename Derived>
 bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
@@ -1720,26 +1672,30 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
   return true;
 }
 
-DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, {
-    // The partial specialization.
-    if (TemplateParameterList *TPL = D->getTemplateParameters()) {
-      for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
-           I != E; ++I) {
-        TRY_TO(TraverseDecl(*I));
-      }
-    }
-    // The args that remains unspecialized.
-    TRY_TO(TraverseTemplateArgumentLocsHelper(
-                      D->getTemplateArgsAsWritten()->getTemplateArgs(),
-                      D->getTemplateArgsAsWritten()->NumTemplateArgs));
-
-    // Don't need the ClassTemplatePartialSpecializationHelper, even
-    // though that's our parent class -- we already visit all the
-    // template args here.
-    TRY_TO(TraverseCXXRecordHelper(D));
-
-    // Instantiations will have been visited with the primary template.
-  })
+#define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
+DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, {         \
+    /* The partial specialization. */                                        \
+    if (TemplateParameterList *TPL = D->getTemplateParameters()) {           \
+      for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); \
+           I != E; ++I) {                                                    \
+        TRY_TO(TraverseDecl(*I));                                            \
+      }                                                                      \
+    }                                                                        \
+    /* The args that remains unspecialized. */                               \
+    TRY_TO(TraverseTemplateArgumentLocsHelper(                               \
+                      D->getTemplateArgsAsWritten()->getTemplateArgs(),      \
+                      D->getTemplateArgsAsWritten()->NumTemplateArgs));      \
+                                                                             \
+    /* Don't need the *TemplatePartialSpecializationHelper, even
+       though that's our parent class -- we already visit all the
+       template args here. */                                                \
+    TRY_TO(Traverse##DECLKIND##Helper(D));                                   \
+                                                                             \
+    /* Instantiations will have been visited with the primary template. */   \
+  })
+
+DEF_TRAVERSE_TMPL_PART_SPEC_DECL(Class, CXXRecord)
+DEF_TRAVERSE_TMPL_PART_SPEC_DECL(Var, Var)
 
 DEF_TRAVERSE_DECL(EnumConstantDecl, {
     TRY_TO(TraverseStmt(D->getInitExpr()));
@@ -1883,43 +1839,6 @@ DEF_TRAVERSE_DECL(VarDecl, {
     TRY_TO(TraverseVarHelper(D));
   })
 
-DEF_TRAVERSE_DECL(VarTemplateSpecializationDecl, {
-  // For implicit instantiations, we don't want to
-  // recurse at all, since the instatiated class isn't written in
-  // the source code anywhere.
-  if (TypeSourceInfo *TSI = D->getTypeAsWritten())
-    TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
-
-  if (!getDerived().shouldVisitTemplateInstantiations() &&
-      D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
-    // Returning from here skips traversing the
-    // declaration context of the VarTemplateSpecializationDecl
-    // (embedded in the DEF_TRAVERSE_DECL() macro).
-    return true;
-})
-
-DEF_TRAVERSE_DECL(VarTemplatePartialSpecializationDecl, {
-  // The partial specialization.
-  if (TemplateParameterList *TPL = D->getTemplateParameters()) {
-    for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
-         I != E; ++I) {
-      TRY_TO(TraverseDecl(*I));
-    }
-  }
-  // The args that remain unspecialized.
-  TRY_TO(TraverseTemplateArgumentLocsHelper(
-                      D->getTemplateArgsAsWritten()->getTemplateArgs(),
-                      D->getTemplateArgsAsWritten()->NumTemplateArgs));
-
-  // Don't need the VarTemplatePartialSpecializationHelper, even
-  // though that's our parent class -- we already visit all the
-  // template args here.
-  TRY_TO(TraverseVarHelper(D));
-
-                    // Instantiations will have been visited with the primary
-                    // template.
-})
-
 DEF_TRAVERSE_DECL(ImplicitParamDecl, {
     TRY_TO(TraverseVarHelper(D));
   })
index 52e35c6752d6979938c2539d359bc302f941e5bf..94f05e9c2f7172eaff28c4fd4e4ad39297e2b550 100644 (file)
@@ -984,8 +984,8 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
   return new (Mem) VarTemplateDecl(EmptyShell());
 }
 
-// FIXME: Should this be unified accross class, function and variable
-// templates? Perhaps also moved to RedeclarableTemplateDecl?
+// TODO: Unify accross class, function and variable templates?
+//       May require moving this and Common to RedeclarableTemplateDecl.
 void VarTemplateDecl::LoadLazySpecializations() const {
   Common *CommonPtr = getCommonPtr();
   if (CommonPtr->LazySpecializations) {
index 096d938ea072b2db19959a4a46b7747f80178e18..8170fb9a50319134344d3d6f992709cdc4ed1c7a 100644 (file)
@@ -2541,7 +2541,9 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
   // a placeholder for an incomplete declarative context; which must be
   // complete by instantiation time. Thus, do not search through the partial
   // specializations yet.
-  // FIXME: Unify with InstantiateClassTemplateSpecialization()?
+  // TODO: Unify with InstantiateClassTemplateSpecialization()?
+  //       Perhaps better after unification of DeduceTemplateArguments() and
+  //       getMoreSpecializedPartialSpecialization().
   bool InstantiationDependent = false;
   if (!TemplateSpecializationType::anyDependentTemplateArguments(
           TemplateArgs, InstantiationDependent)) {
@@ -2556,6 +2558,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
       if (TemplateDeductionResult Result =
               DeduceTemplateArguments(Partial, TemplateArgList, Info)) {
         // Store the failed-deduction information for use in diagnostics, later.
+        // TODO: Actually use the failed-deduction info?
         FailedCandidates.addCandidate()
             .set(Partial, MakeDeductionFailureInfo(Context, Result, Info));
         (void)Result;
@@ -2618,8 +2621,6 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
     }
   }
 
-  // FIXME: Actually use FailedCandidates.
-
   // 2. Create the canonical declaration.
   // Note that we do not instantiate the variable just yet, since
   // instantiation is handled in DoMarkVarDeclReferenced().
index a5878bcb36405f92e59f528b83f4b0a410cee437..47d8e162c8ad4d8fefa39615c25dd43bd2c0f795 100644 (file)
@@ -2288,7 +2288,11 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
 
 /// Complete template argument deduction for a variable template partial
 /// specialization.
-/// TODO: Unify with ClassTemplatePartialSpecializationDecl version.
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version?
+///       May require unifying ClassTemplate(Partial)SpecializationDecl and
+///        VarTemplate(Partial)SpecializationDecl with a new data
+///        structure Template(Partial)SpecializationDecl, and
+///        using Template(Partial)SpecializationDecl as input type.
 static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
     Sema &S, VarTemplatePartialSpecializationDecl *Partial,
     const TemplateArgumentList &TemplateArgs,
@@ -2404,7 +2408,11 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
 /// \brief Perform template argument deduction to determine whether
 /// the given template arguments match the given variable template
 /// partial specialization per C++ [temp.class.spec.match].
-/// TODO: Unify with ClassTemplatePartialSpecializationDecl version.
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version?
+///       May require unifying ClassTemplate(Partial)SpecializationDecl and
+///        VarTemplate(Partial)SpecializationDecl with a new data
+///        structure Template(Partial)SpecializationDecl, and
+///        using Template(Partial)SpecializationDecl as input type.
 Sema::TemplateDeductionResult
 Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
                               const TemplateArgumentList &TemplateArgs,
@@ -4458,7 +4466,11 @@ Sema::getMoreSpecializedPartialSpecialization(
   return Better1 ? PS1 : PS2;
 }
 
-/// TODO: Unify with ClassTemplatePartialSpecializationDecl version.
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version?
+///       May require unifying ClassTemplate(Partial)SpecializationDecl and
+///        VarTemplate(Partial)SpecializationDecl with a new data
+///        structure Template(Partial)SpecializationDecl, and
+///        using Template(Partial)SpecializationDecl as input type.
 VarTemplatePartialSpecializationDecl *
 Sema::getMoreSpecializedPartialSpecialization(
     VarTemplatePartialSpecializationDecl *PS1,
index b1fe8c60cdc8f19eb03d6cda8b9a0ebae3326fe5..3c93340f5ef099a04cb1245a4830d792667f9f5e 100644 (file)
@@ -1440,6 +1440,9 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
   }
 }
 
+/// TODO: Unify with ClassTemplateDecl version?
+///       May require unifying ClassTemplateDecl and
+///        VarTemplateDecl beyond TemplateDecl...
 void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
   RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
 
@@ -1574,6 +1577,11 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
   }
 }
 
+/// TODO: Unify with ClassTemplateSpecializationDecl version?
+///       May require unifying ClassTemplate(Partial)SpecializationDecl and
+///        VarTemplate(Partial)SpecializationDecl with a new data
+///        structure Template(Partial)SpecializationDecl, and
+///        using Template(Partial)SpecializationDecl as input type.
 ASTDeclReader::RedeclarableResult
 ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
     VarTemplateSpecializationDecl *D) {
@@ -1632,6 +1640,11 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
   return Redecl;
 }
 
+/// TODO: Unify with ClassTemplatePartialSpecializationDecl version?
+///       May require unifying ClassTemplate(Partial)SpecializationDecl and
+///        VarTemplate(Partial)SpecializationDecl with a new data
+///        structure Template(Partial)SpecializationDecl, and
+///        using Template(Partial)SpecializationDecl as input type.
 void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
     VarTemplatePartialSpecializationDecl *D) {
   RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);