]> granicus.if.org Git - clang/commitdiff
PR34163: Don't cache an incorrect key function for a class if queried between
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 12 Aug 2017 01:46:03 +0000 (01:46 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 12 Aug 2017 01:46:03 +0000 (01:46 +0000)
the class becoming complete and its inline methods being parsed.

This replaces the hack of using the "late parsed template" flag to track member
functions with bodies we've not parsed yet; instead we now use the "will have
body" flag, which carries the desired implication that the function declaration
*is* a definition, and that we've just not parsed its body yet.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@310776 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
lib/AST/DeclCXX.cpp
lib/Parse/ParseCXXInlineMethods.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CodeGenCXX/pr34163.cpp [new file with mode: 0644]
test/SemaCUDA/function-overload.cu
test/SemaCUDA/no-destructor-overload.cu

index 08b34a75aa600f35ef42fa6317f7c5ec2ed37bb7..54e6ebcd8af2a25100372081982eea9a7f324fc5 100644 (file)
@@ -1666,8 +1666,7 @@ private:
   unsigned HasSkippedBody : 1;
 
   /// Indicates if the function declaration will have a body, once we're done
-  /// parsing it.  (We don't set it to false when we're done parsing, in the
-  /// hopes this is simpler.)
+  /// parsing it.
   unsigned WillHaveBody : 1;
 
   /// \brief End part of this FunctionDecl's source range.
index 5cab48882251552d144074c097285151b70afe84..1caceab85eea6e830725247b043a82475aa2b418 100644 (file)
@@ -1837,9 +1837,10 @@ bool CXXMethodDecl::hasInlineBody() const {
   const FunctionDecl *CheckFn = getTemplateInstantiationPattern();
   if (!CheckFn)
     CheckFn = this;
-  
+
   const FunctionDecl *fn;
-  return CheckFn->hasBody(fn) && !fn->isOutOfLine();
+  return CheckFn->isDefined(fn) && !fn->isOutOfLine() &&
+         (fn->doesThisDeclarationHaveABody() || fn->willHaveBody());
 }
 
 bool CXXMethodDecl::isLambdaStaticInvoker() const {
index c9a895d7d549a0b66f4da28f8c185ea2ea78c1ec..2b3d4ba85bd8d091d46d11a6d77cf90f0e6b939b 100644 (file)
@@ -166,20 +166,11 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
   }
 
   if (FnD) {
-    // If this is a friend function, mark that it's late-parsed so that
-    // it's still known to be a definition even before we attach the
-    // parsed body.  Sema needs to treat friend function definitions
-    // differently during template instantiation, and it's possible for
-    // the containing class to be instantiated before all its member
-    // function definitions are parsed.
-    //
-    // If you remove this, you can remove the code that clears the flag
-    // after parsing the member.
-    if (D.getDeclSpec().isFriendSpecified()) {
-      FunctionDecl *FD = FnD->getAsFunction();
-      Actions.CheckForFunctionRedefinition(FD);
-      FD->setLateTemplateParsed(true);
-    }
+    FunctionDecl *FD = FnD->getAsFunction();
+    // Track that this function will eventually have a body; Sema needs
+    // to know this.
+    Actions.CheckForFunctionRedefinition(FD);
+    FD->setWillHaveBody(true);
   } else {
     // If semantic analysis could not build a function declaration,
     // just throw away the late-parsed declaration.
@@ -559,10 +550,6 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
 
   ParseFunctionStatementBody(LM.D, FnScope);
 
-  // Clear the late-template-parsed bit if we set it before.
-  if (LM.D)
-    LM.D->getAsFunction()->setLateTemplateParsed(false);
-
   while (Tok.isNot(tok::eof))
     ConsumeAnyToken();
 
index 86c367097f7ab6c4bcc85c1e7685383dda99677a..0879e78a9a1bbe7e6c8e9f9b3860f657b7dcc020 100644 (file)
@@ -12090,8 +12090,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
     FD->setInvalidDecl();
   }
 
-  // See if this is a redefinition.
-  if (!FD->isLateTemplateParsed()) {
+  // See if this is a redefinition. If 'will have body' is already set, then
+  // these checks were already performed when it was set.
+  if (!FD->willHaveBody() && !FD->isLateTemplateParsed()) {
     CheckForFunctionRedefinition(FD, nullptr, SkipBody);
 
     // If we're skipping the body, we're done. Don't enter the scope.
index abe912fb548ba7c63a989ea18d462f6992d47217..6fee23aa8bc10401e0f86be85c00ad012d93abdd 100644 (file)
@@ -3771,6 +3771,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
   if (PatternDef) {
     Pattern = PatternDef->getBody(PatternDef);
     PatternDecl = PatternDef;
+    if (PatternDef->willHaveBody())
+      PatternDef = nullptr;
   }
 
   // FIXME: We need to track the instantiation stack in order to know which
diff --git a/test/CodeGenCXX/pr34163.cpp b/test/CodeGenCXX/pr34163.cpp
new file mode 100644 (file)
index 0000000..a200a0f
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=standalone -triple x86_64-linux-gnu -o - -x c++ %s | FileCheck %s
+
+void f(struct X *) {}
+
+// CHECK: @_ZTV1X =
+struct X {
+  void a() { delete this; }
+  virtual ~X() {}
+  virtual void key_function();
+};
+
+// CHECK: define {{.*}} @_ZN1X12key_functionEv(
+void X::key_function() {}
index 3d4c29c42cee1abf12619dbe2d66d65fa6ebf34d..adf488b5eea3736e6c0c151fb4a93d88b7a3bd18 100644 (file)
@@ -222,7 +222,7 @@ GlobalFnPtr fp_g = g;
 // Test overloading of destructors
 // Can't mix H and unattributed destructors
 struct d_h {
-  ~d_h() {} // expected-note {{previous declaration is here}}
+  ~d_h() {} // expected-note {{previous definition is here}}
   __host__ ~d_h() {} // expected-error {{destructor cannot be redeclared}}
 };
 
index aa6971ee8ca82d074ca62397c1f8553f286f9b8f..32dbb8db76ecb1131e89510616e61b9eed65da18 100644 (file)
@@ -7,27 +7,27 @@
 // giant change to clang, and the use cases seem quite limited.
 
 struct A {
-  ~A() {} // expected-note {{previous declaration is here}}
+  ~A() {} // expected-note {{previous definition is here}}
   __device__ ~A() {} // expected-error {{destructor cannot be redeclared}}
 };
 
 struct B {
-  __host__ ~B() {} // expected-note {{previous declaration is here}}
+  __host__ ~B() {} // expected-note {{previous definition is here}}
   __host__ __device__ ~B() {} // expected-error {{destructor cannot be redeclared}}
 };
 
 struct C {
-  __host__ __device__ ~C() {} // expected-note {{previous declaration is here}}
+  __host__ __device__ ~C() {} // expected-note {{previous definition is here}}
   __host__ ~C() {} // expected-error {{destructor cannot be redeclared}}
 };
 
 struct D {
-  __device__ ~D() {} // expected-note {{previous declaration is here}}
+  __device__ ~D() {} // expected-note {{previous definition is here}}
   __host__ __device__ ~D() {} // expected-error {{destructor cannot be redeclared}}
 };
 
 struct E {
-  __host__ __device__ ~E() {} // expected-note {{previous declaration is here}}
+  __host__ __device__ ~E() {} // expected-note {{previous definition is here}}
   __device__ ~E() {} // expected-error {{destructor cannot be redeclared}}
 };