Skip to content

Commit f0fb6cc

Browse files
Merge branch 'main' into P2278R4_cbegin
2 parents 9e28bd8 + 1d7c460 commit f0fb6cc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+14440
-48769
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ Improvements to Clang's diagnostics
278278

279279
- Improve the diagnostics for shadows template parameter to report correct location (#GH129060).
280280

281+
- Improve the ``-Wundefined-func-template`` warning when a function template is not instantiated due to being unreachable in modules.
282+
281283
Improvements to Clang's time-trace
282284
----------------------------------
283285

clang/docs/analyzer/checkers.rst

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,42 @@ Do not attempt to create a std::string from a null pointer
543543
}
544544
}
545545
546+
.. _cplusplus-PureVirtualCall:
547+
548+
cplusplus.PureVirtualCall (C++)
549+
"""""""""""""""""""""""""""""""
550+
551+
When `virtual methods are called during construction and destruction
552+
<https://en.cppreference.com/w/cpp/language/virtual#During_construction_and_destruction>`__
553+
the polymorphism is restricted to the class that's being constructed or
554+
destructed because the more derived contexts are either not yet initialized or
555+
already destructed.
556+
557+
This checker reports situations where this restricted polymorphism causes a
558+
call to a pure virtual method, which is undefined behavior. (See also the
559+
related checker :ref:`optin-cplusplus-VirtualCall` which reports situations
560+
where the restricted polymorphism affects a call and the called method is not
561+
pure virtual – but may be still surprising for the programmer.)
562+
563+
.. code-block:: cpp
564+
565+
struct A {
566+
virtual int getKind() = 0;
567+
568+
A() {
569+
// warn: This calls the pure virtual method A::getKind().
570+
log << "Constructing " << getKind();
571+
}
572+
virtual ~A() {
573+
releaseResources();
574+
}
575+
void releaseResources() {
576+
// warn: This can call the pure virtual method A::getKind() when this is
577+
// called from the destructor.
578+
callSomeFunction(getKind())
579+
}
580+
};
581+
546582
.. _deadcode-checkers:
547583
548584
deadcode
@@ -833,24 +869,40 @@ This checker has several options which can be set from command line (e.g.
833869
834870
optin.cplusplus.VirtualCall (C++)
835871
"""""""""""""""""""""""""""""""""
836-
Check virtual function calls during construction or destruction.
872+
873+
When `virtual methods are called during construction and destruction
874+
<https://en.cppreference.com/w/cpp/language/virtual#During_construction_and_destruction>`__
875+
the polymorphism is restricted to the class that's being constructed or
876+
destructed because the more derived contexts are either not yet initialized or
877+
already destructed.
878+
879+
Although this behavior is well-defined, it can surprise the programmer and
880+
cause unintended behavior, so this checker reports calls that appear to be
881+
virtual calls but can be affected by this restricted polymorphism.
882+
883+
Note that situations where this restricted polymorphism causes a call to a pure
884+
virtual method (which is definitely invalid, triggers undefined behavior) are
885+
**reported by another checker:** :ref:`cplusplus-PureVirtualCall` and **this
886+
checker does not report them**.
837887
838888
.. code-block:: cpp
839889
840-
class A {
841-
public:
890+
struct A {
891+
virtual int getKind();
892+
842893
A() {
843-
f(); // warn
894+
// warn: This calls A::getKind() even if we are constructing an instance
895+
// of a different class that is derived from A.
896+
log << "Constructing " << getKind();
844897
}
845-
virtual void f();
846-
};
847-
848-
class A {
849-
public:
850-
~A() {
851-
this->f(); // warn
898+
virtual ~A() {
899+
releaseResources();
900+
}
901+
void releaseResources() {
902+
// warn: This can be called within ~A() and calls A::getKind() even if
903+
// we are destructing a class that is derived from A.
904+
callSomeFunction(getKind())
852905
}
853-
virtual void f();
854906
};
855907
856908
.. _optin-mpi-MPI-Checker:

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5700,6 +5700,8 @@ def warn_func_template_missing : Warning<"instantiation of function %q0 "
57005700
InGroup<UndefinedFuncTemplate>, DefaultIgnore;
57015701
def note_forward_template_decl : Note<
57025702
"forward declaration of template entity is here">;
5703+
def note_unreachable_template_decl
5704+
: Note<"unreachable declaration of template entity is here">;
57035705
def note_inst_declaration_hint : Note<"add an explicit instantiation "
57045706
"declaration to suppress this warning if %q0 is explicitly instantiated in "
57055707
"another translation unit">;

clang/include/clang/Sema/Sema.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11268,13 +11268,11 @@ class Sema final : public SemaBase {
1126811268

1126911269
/// Determine whether we would be unable to instantiate this template (because
1127011270
/// it either has no definition, or is in the process of being instantiated).
11271-
bool DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
11272-
NamedDecl *Instantiation,
11273-
bool InstantiatedFromMember,
11274-
const NamedDecl *Pattern,
11275-
const NamedDecl *PatternDef,
11276-
TemplateSpecializationKind TSK,
11277-
bool Complain = true);
11271+
bool DiagnoseUninstantiableTemplate(
11272+
SourceLocation PointOfInstantiation, NamedDecl *Instantiation,
11273+
bool InstantiatedFromMember, const NamedDecl *Pattern,
11274+
const NamedDecl *PatternDef, TemplateSpecializationKind TSK,
11275+
bool Complain = true, bool *Unreachable = nullptr);
1127811276

1127911277
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
1128011278
/// that the template parameter 'PrevDecl' is being shadowed by a new

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
765765
const NamedDecl *Pattern,
766766
const NamedDecl *PatternDef,
767767
TemplateSpecializationKind TSK,
768-
bool Complain /*= true*/) {
768+
bool Complain, bool *Unreachable) {
769769
assert(isa<TagDecl>(Instantiation) || isa<FunctionDecl>(Instantiation) ||
770770
isa<VarDecl>(Instantiation));
771771

@@ -778,6 +778,8 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
778778
if (!hasReachableDefinition(const_cast<NamedDecl *>(PatternDef),
779779
&SuggestedDef,
780780
/*OnlyNeedComplete*/ false)) {
781+
if (Unreachable)
782+
*Unreachable = true;
781783
// If we're allowed to diagnose this and recover, do so.
782784
bool Recover = Complain && !isSFINAEContext();
783785
if (Complain)

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5386,12 +5386,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
53865386
PatternDef = nullptr;
53875387
}
53885388

5389+
// True is the template definition is unreachable, otherwise false.
5390+
bool Unreachable = false;
53895391
// FIXME: We need to track the instantiation stack in order to know which
53905392
// definitions should be visible within this instantiation.
5391-
if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Function,
5392-
Function->getInstantiatedFromMemberFunction(),
5393-
PatternDecl, PatternDef, TSK,
5394-
/*Complain*/DefinitionRequired)) {
5393+
if (DiagnoseUninstantiableTemplate(
5394+
PointOfInstantiation, Function,
5395+
Function->getInstantiatedFromMemberFunction(), PatternDecl,
5396+
PatternDef, TSK,
5397+
/*Complain*/ DefinitionRequired, &Unreachable)) {
53955398
if (DefinitionRequired)
53965399
Function->setInvalidDecl();
53975400
else if (TSK == TSK_ExplicitInstantiationDefinition ||
@@ -5416,11 +5419,18 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
54165419
if (AtEndOfTU && !getDiagnostics().hasErrorOccurred() &&
54175420
!getSourceManager().isInSystemHeader(PatternDecl->getBeginLoc())) {
54185421
Diag(PointOfInstantiation, diag::warn_func_template_missing)
5419-
<< Function;
5420-
Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
5421-
if (getLangOpts().CPlusPlus11)
5422-
Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
5423-
<< Function;
5422+
<< Function;
5423+
if (Unreachable) {
5424+
// FIXME: would be nice to mention which module the function template
5425+
// comes from.
5426+
Diag(PatternDecl->getLocation(),
5427+
diag::note_unreachable_template_decl);
5428+
} else {
5429+
Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
5430+
if (getLangOpts().CPlusPlus11)
5431+
Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
5432+
<< Function;
5433+
}
54245434
}
54255435
}
54265436

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %clang_cc1 -std=c++20 -fmodules -fmodules-cache-path=%t -I%t \
4+
// RUN: -Wundefined-func-template \
5+
// RUN: -fimplicit-module-maps %t/main.cpp 2>&1 | grep "unreachable declaration of template entity is here"
6+
7+
// Note that the diagnostics are triggered when building the 'hoge' module, which is imported from the main file.
8+
// The "-verify" flag doesn't work in this case. Instead, we grep the expected text to verify the test.
9+
10+
//--- shared_ptr2.h
11+
#pragma once
12+
13+
template<class T>
14+
void x() { }
15+
16+
//--- hoge.h
17+
#pragma once
18+
19+
#include "shared_ptr2.h"
20+
21+
inline void f() {
22+
x<int>();
23+
}
24+
25+
//--- module.modulemap
26+
module hoge {
27+
header "hoge.h"
28+
}
29+
30+
module shared_ptr2 {
31+
header "shared_ptr2.h"
32+
}
33+
34+
//--- main.cpp
35+
#include "hoge.h"
36+
37+
int main() {
38+
f();
39+
}

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,8 @@ static void threadPrivatizeVars(lower::AbstractConverter &converter,
763763
commonSyms.insert(common);
764764
}
765765
symThreadprivateValue = lower::genCommonBlockMember(
766-
converter, currentLocation, *sym, commonThreadprivateValue);
766+
converter, currentLocation, sym->GetUltimate(),
767+
commonThreadprivateValue);
767768
} else {
768769
symThreadprivateValue = genThreadprivateOp(*sym);
769770
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
! Simple test for lowering of OpenMP Threadprivate Directive with a pointer var
2+
! from a common block.
3+
4+
!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
5+
!RUN: bbc -hlfir -emit-hlfir -fopenmp %s -o - | FileCheck %s
6+
7+
! Regression test for a compiler crash
8+
9+
module mmm
10+
integer,pointer::nam1
11+
common /com1/nam1,nam2
12+
!$omp threadprivate(/com1/)
13+
end
14+
use mmm
15+
!$omp parallel copyin(nam1)
16+
!$omp end parallel
17+
end
18+
19+
20+
! CHECK-LABEL: fir.global common @com1_(dense<0> : vector<28xi8>) {alignment = 8 : i64} : !fir.array<28xi8>
21+
22+
! CHECK-LABEL: func.func @_QQmain() {
23+
! CHECK: %[[VAL_0:.*]] = fir.address_of(@com1_) : !fir.ref<!fir.array<28xi8>>
24+
! CHECK: omp.parallel {
25+
! CHECK: %[[VAL_17:.*]] = omp.threadprivate %[[VAL_0]] : !fir.ref<!fir.array<28xi8>> -> !fir.ref<!fir.array<28xi8>>
26+
! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (!fir.ref<!fir.array<28xi8>>) -> !fir.ref<!fir.array<?xi8>>
27+
! CHECK: %[[VAL_19:.*]] = arith.constant 0 : index
28+
! CHECK: %[[VAL_20:.*]] = fir.coordinate_of %[[VAL_18]], %[[VAL_19]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
29+
! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
30+
! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_21]] {fortran_attrs = #{{.*}}<pointer>, uniq_name = "_QMmmmEnam1"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
31+

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ def ECALL : RVInstI<0b000, OPC_SYSTEM, (outs), (ins), "ecall", "">, Sched<[Write
752752
let imm12 = 0;
753753
}
754754

755+
let isTrap = 1 in
755756
def EBREAK : RVInstI<0b000, OPC_SYSTEM, (outs), (ins), "ebreak", "">,
756757
Sched<[]> {
757758
let rs1 = 0;
@@ -762,6 +763,7 @@ def EBREAK : RVInstI<0b000, OPC_SYSTEM, (outs), (ins), "ebreak", "">,
762763
// This is a de facto standard (as set by GNU binutils) 32-bit unimplemented
763764
// instruction (i.e., it should always trap, if your implementation has invalid
764765
// instruction traps).
766+
let isTrap = 1 in
765767
def UNIMP : RVInstI<0b001, OPC_SYSTEM, (outs), (ins), "unimp", "">,
766768
Sched<[]> {
767769
let rs1 = 0;

0 commit comments

Comments
 (0)