sepavloff updated this revision to Diff 89206.
sepavloff added a comment.

Implement `isDefined` through `isThisDeclarationADefinition`.


https://reviews.llvm.org/D30170

Files:
  include/clang/AST/Decl.h
  lib/AST/Decl.cpp
  lib/Sema/SemaDecl.cpp
  test/SemaCXX/cxx0x-cursory-default-delete.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===================================================================
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -101,6 +101,34 @@
   friend void func_12(int x = 0);  // expected-error{{friend declaration specifying a default argument must be the only declaration}}
 };
 
+// Friend function with uninstantiated body is still a definition.
+
+template<typename T> struct C20 {
+  friend void func_20() {} // expected-note{{previous definition is here}}
+};
+C20<int> c20i;
+void func_20() {} // expected-error{{redefinition of 'func_20'}}
+
+template<typename T> struct C21a {
+  friend void func_21() {} // expected-note{{previous definition is here}}
+};
+template<typename T> struct C21b {
+  friend void func_21() {} // expected-error{{redefinition of 'func_21'}}
+};
+C21a<int> c21ai;
+C21b<int> c21bi; // expected-note{{in instantiation of template class 'C21b<int>' requested here}}
+
+template<typename T> struct C22a {
+  friend void func_22() {} // expected-note{{previous definition is here}}
+};
+template<typename T> struct C22b {
+  friend void func_22();
+};
+C22a<int> c22ai;
+C22b<int> c22bi;
+void func_22() {} // expected-error{{redefinition of 'func_22'}}
+
+
 
 namespace pr22307 {
 
Index: test/SemaCXX/cxx0x-cursory-default-delete.cpp
===================================================================
--- test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -136,13 +136,13 @@
 };
 
 struct DefaultDelete {
-  DefaultDelete() = default; // expected-note {{previous declaration is here}}
+  DefaultDelete() = default; // expected-note {{previous definition is here}}
   DefaultDelete() = delete; // expected-error {{constructor cannot be redeclared}}
 
-  ~DefaultDelete() = default; // expected-note {{previous declaration is here}}
+  ~DefaultDelete() = default; // expected-note {{previous definition is here}}
   ~DefaultDelete() = delete; // expected-error {{destructor cannot be redeclared}}
 
-  DefaultDelete &operator=(const DefaultDelete &) = default; // expected-note {{previous declaration is here}}
+  DefaultDelete &operator=(const DefaultDelete &) = default; // expected-note {{previous definition is here}}
   DefaultDelete &operator=(const DefaultDelete &) = delete; // expected-error {{class member cannot be redeclared}}
 };
 
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11692,8 +11692,12 @@
                                    SkipBodyInfo *SkipBody) {
   const FunctionDecl *Definition = EffectiveDefinition;
   if (!Definition)
-    if (!FD->isDefined(Definition))
+    if (!FD->isOdrDefined(Definition))
       return;
+  assert(Definition);
+
+  if (FD == Definition)
+    return;
 
   if (canRedefineFunction(Definition, getLangOpts()))
     return;
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -2528,8 +2528,18 @@
 
 bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
   for (auto I : redecls()) {
-    if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed ||
-        I->hasDefiningAttr()) {
+    if (I->isThisDeclarationADefinition()) {
+      Definition = I->IsDeleted ? I->getCanonicalDecl() : I;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool FunctionDecl::isOdrDefined(const FunctionDecl *&Definition) const {
+  for (auto I : redecls()) {
+    if (I->isThisDeclarationAnOdrDefinition()) {
       Definition = I->IsDeleted ? I->getCanonicalDecl() : I;
       return true;
     }
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1781,32 +1781,104 @@
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
-  /// \brief Returns true if the function has a body (definition). The
-  /// function body might be in any of the (re-)declarations of this
-  /// function. The variant that accepts a FunctionDecl pointer will
-  /// set that function declaration to the actual declaration
-  /// containing the body (if there is one).
+  /// \name Definition and body checks
+  ///
+  /// A function declaration may be:
+  /// - a non defining declaration,
+  /// - a definition. A function may be defined because:
+  ///   - it has a body, or will have it in the case of late parsing.
+  ///   - it has an uninstantiated body. The body does not exist because the
+  ///     function is not used yet, but the declaration is considered a
+  ///     definition from viewpoint of ODR checks.
+  ///   - it does not have a user specified body, but it does not allow
+  ///     redefinition, because it is deleted/defaulted or is defined through
+  ///     some other mechanism (alias, ifunc).
+  ///
+  /// Depending on whether the redeclaration chain contains a definition and of
+  /// what kind, the same classification applies to the function represented by
+  /// a set of redeclarations.
+  ///
+  /// \{
+
+  /// Returns true if the function has a body.
+  ///
+  /// The function body might be in any of the (re-)declarations of this
+  /// function. The variant that accepts a FunctionDecl pointer will set that
+  /// function declaration to the actual declaration containing the body (if
+  /// there is one).
+  ///
   bool hasBody(const FunctionDecl *&Definition) const;
 
   bool hasBody() const override {
     const FunctionDecl* Definition;
     return hasBody(Definition);
   }
 
-  /// hasTrivialBody - Returns whether the function has a trivial body that does
-  /// not require any specific codegen.
-  bool hasTrivialBody() const;
-
-  /// isDefined - Returns true if the function is defined at all, including
-  /// a deleted definition. Except for the behavior when the function is
-  /// deleted, behaves like hasBody.
+  /// Returns true if the function has a definition that does not need to be
+  /// instantiated.
+  ///
+  /// The only difference to isOdrDefined is that this function does not take
+  /// into account functions where body is not instantiated because it is not
+  /// used.
+  ///
+  /// The variant that accepts a FunctionDecl pointer will set that function
+  /// declaration to the declaration that is a definition (if there is one).
+  ///
   bool isDefined(const FunctionDecl *&Definition) const;
 
   virtual bool isDefined() const {
     const FunctionDecl* Definition;
     return isDefined(Definition);
   }
 
+  /// Returns true if the function is defined in the sense of ODR checks.
+  ///
+  bool isOdrDefined(const FunctionDecl *&Definition) const;
+  bool isOdrDefined() const {
+    const FunctionDecl* Definition;
+    return isOdrDefined(Definition);
+  }
+
+  /// Returns whether this specific declaration of the function is also a
+  /// definition that does not contain uninstantiated body.
+  ///
+  /// This does not determine whether the function has been defined (e.g., in a
+  /// previous definition); for that information, use isDefined.
+  ///
+  bool isThisDeclarationADefinition() const {
+    return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||
+           hasDefiningAttr();
+  }
+
+  /// Returns whether this specific declaration of the function has a body.
+  ///
+  bool doesThisDeclarationHaveABody() const {
+    return Body || IsLateTemplateParsed;
+  }
+
+  /// Returns true if the function has a body that was instantiated from a
+  /// template definition or can be instantiated from such.
+  ///
+  bool doesThisDeclarationHaveATemplatedBody() const {
+    if (FunctionDecl *Original = getInstantiatedFromMemberFunction())
+      return Original->isOdrDefined();
+    return false;
+  }
+
+  /// Returns true if this declaration is a definition is the sense of ODR
+  /// checks.
+  ///
+  bool isThisDeclarationAnOdrDefinition() const {
+    return isThisDeclarationADefinition() ||
+           doesThisDeclarationHaveATemplatedBody();
+  }
+
+  /// \}
+
+  /// hasTrivialBody - Returns whether the function has a trivial body that does
+  /// not require any specific codegen.
+  bool hasTrivialBody() const;
+
   /// \brief Get the definition for this declaration.
   FunctionDecl *getDefinition() {
     const FunctionDecl *Definition;
@@ -1832,23 +1904,6 @@
     return getBody(Definition);
   }
 
-  /// isThisDeclarationADefinition - Returns whether this specific
-  /// declaration of the function is also a definition. This does not
-  /// determine whether the function has been defined (e.g., in a
-  /// previous definition); for that information, use isDefined. Note
-  /// that this returns false for a defaulted function unless that function
-  /// has been implicitly defined (possibly as deleted).
-  bool isThisDeclarationADefinition() const {
-    return IsDeleted || Body || IsLateTemplateParsed;
-  }
-
-  /// doesThisDeclarationHaveABody - Returns whether this specific
-  /// declaration of the function has a body - that is, if it is a non-
-  /// deleted definition.
-  bool doesThisDeclarationHaveABody() const {
-    return Body || IsLateTemplateParsed;
-  }
-
   void setBody(Stmt *B);
   void setLazyBody(uint64_t Offset) { Body = Offset; }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to