Skip to content

Commit 96a0469

Browse files
authored
Merge branch 'llvm:main' into main
2 parents 3af6ae6 + 13d8188 commit 96a0469

File tree

122 files changed

+2062
-364
lines changed

Some content is hidden

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

122 files changed

+2062
-364
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,11 @@ Improvements to Clang's diagnostics
705705
- Improve the diagnostics for placement new expression when const-qualified
706706
object was passed as the storage argument. (#GH143708)
707707

708+
- Clang now does not issue a warning about returning from a function declared with
709+
the ``[[noreturn]]`` attribute when the function body is ended with a call via
710+
pointer, provided it can be proven that the pointer only points to
711+
``[[noreturn]]`` functions.
712+
708713
Improvements to Clang's time-trace
709714
----------------------------------
710715

clang/include/clang/Sema/Overload.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,11 @@ class Sema;
350350
LLVM_PREFERRED_TYPE(bool)
351351
unsigned BindsToRvalue : 1;
352352

353+
/// Whether this was an identity conversion with qualification
354+
/// conversion for the implicit object argument.
355+
LLVM_PREFERRED_TYPE(bool)
356+
unsigned IsImplicitObjectArgumentQualificationConversion : 1;
357+
353358
/// Whether this binds an implicit object argument to a
354359
/// non-static member function without a ref-qualifier.
355360
LLVM_PREFERRED_TYPE(bool)
@@ -448,11 +453,11 @@ class Sema;
448453
#endif
449454
return true;
450455
}
451-
if (!C.hasSameType(getFromType(), getToType(2)))
452-
return false;
453456
if (BindsToRvalue && IsLvalueReference)
454457
return false;
455-
return true;
458+
if (IsImplicitObjectArgumentQualificationConversion)
459+
return C.hasSameUnqualifiedType(getFromType(), getToType(2));
460+
return C.hasSameType(getFromType(), getToType(2));
456461
}
457462

458463
ImplicitConversionRank getRank() const;

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "clang/Analysis/AnalysisDeclContext.h"
3838
#include "clang/Analysis/CFG.h"
3939
#include "clang/Analysis/CFGStmtMap.h"
40+
#include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
4041
#include "clang/Basic/Diagnostic.h"
4142
#include "clang/Basic/DiagnosticSema.h"
4243
#include "clang/Basic/SourceLocation.h"
@@ -46,6 +47,7 @@
4647
#include "clang/Sema/SemaInternal.h"
4748
#include "llvm/ADT/ArrayRef.h"
4849
#include "llvm/ADT/BitVector.h"
50+
#include "llvm/ADT/DenseMap.h"
4951
#include "llvm/ADT/MapVector.h"
5052
#include "llvm/ADT/STLFunctionalExtras.h"
5153
#include "llvm/ADT/SmallVector.h"
@@ -401,6 +403,143 @@ static bool isNoexcept(const FunctionDecl *FD) {
401403
return false;
402404
}
403405

406+
/// Checks if the given expression is a reference to a function with
407+
/// 'noreturn' attribute.
408+
static bool isReferenceToNoReturn(const Expr *E) {
409+
if (auto *DRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
410+
if (auto *FD = dyn_cast<FunctionDecl>(DRef->getDecl()))
411+
return FD->isNoReturn();
412+
return false;
413+
}
414+
415+
/// Checks if the given variable, which is assumed to be a function pointer, is
416+
/// initialized with a function having 'noreturn' attribute.
417+
static bool isInitializedWithNoReturn(const VarDecl *VD) {
418+
if (const Expr *Init = VD->getInit()) {
419+
if (auto *ListInit = dyn_cast<InitListExpr>(Init);
420+
ListInit && ListInit->getNumInits() > 0)
421+
Init = ListInit->getInit(0);
422+
return isReferenceToNoReturn(Init);
423+
}
424+
return false;
425+
}
426+
427+
namespace {
428+
429+
/// Looks for statements, that can define value of the given variable.
430+
struct TransferFunctions : public StmtVisitor<TransferFunctions> {
431+
const VarDecl *Var;
432+
std::optional<bool> AllValuesAreNoReturn;
433+
434+
TransferFunctions(const VarDecl *VD) : Var(VD) {}
435+
436+
void reset() { AllValuesAreNoReturn = std::nullopt; }
437+
438+
void VisitDeclStmt(DeclStmt *DS) {
439+
for (auto *DI : DS->decls())
440+
if (auto *VD = dyn_cast<VarDecl>(DI))
441+
if (VarDecl *Def = VD->getDefinition())
442+
if (Def == Var)
443+
AllValuesAreNoReturn = isInitializedWithNoReturn(Def);
444+
}
445+
446+
void VisitUnaryOperator(UnaryOperator *UO) {
447+
if (UO->getOpcode() == UO_AddrOf) {
448+
if (auto *DRef =
449+
dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParenCasts()))
450+
if (DRef->getDecl() == Var)
451+
AllValuesAreNoReturn = false;
452+
}
453+
}
454+
455+
void VisitBinaryOperator(BinaryOperator *BO) {
456+
if (BO->getOpcode() == BO_Assign)
457+
if (auto *DRef = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParenCasts()))
458+
if (DRef->getDecl() == Var)
459+
AllValuesAreNoReturn = isReferenceToNoReturn(BO->getRHS());
460+
}
461+
462+
void VisitCallExpr(CallExpr *CE) {
463+
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E;
464+
++I) {
465+
const Expr *Arg = *I;
466+
if (Arg->isGLValue() && !Arg->getType().isConstQualified())
467+
if (auto *DRef = dyn_cast<DeclRefExpr>(Arg->IgnoreParenCasts()))
468+
if (auto VD = dyn_cast<VarDecl>(DRef->getDecl()))
469+
if (VD->getDefinition() == Var)
470+
AllValuesAreNoReturn = false;
471+
}
472+
}
473+
};
474+
} // namespace
475+
476+
// Checks if all possible values of the given variable are functions with
477+
// 'noreturn' attribute.
478+
static bool areAllValuesNoReturn(const VarDecl *VD, const CFGBlock &VarBlk,
479+
AnalysisDeclContext &AC) {
480+
// The set of possible values of a constant variable is determined by
481+
// its initializer, unless it is a function parameter.
482+
if (!isa<ParmVarDecl>(VD) && VD->getType().isConstant(AC.getASTContext())) {
483+
if (const VarDecl *Def = VD->getDefinition())
484+
return isInitializedWithNoReturn(Def);
485+
return false;
486+
}
487+
488+
// In multithreaded environment the value of a global variable may be changed
489+
// asynchronously.
490+
if (!VD->getDeclContext()->isFunctionOrMethod())
491+
return false;
492+
493+
// Check the condition "all values are noreturn". It is satisfied if the
494+
// variable is set to "noreturn" value in the current block or all its
495+
// predecessors satisfies the condition.
496+
using MapTy = llvm::DenseMap<const CFGBlock *, std::optional<bool>>;
497+
using ValueTy = MapTy::value_type;
498+
MapTy BlocksToCheck;
499+
BlocksToCheck[&VarBlk] = std::nullopt;
500+
const auto BlockSatisfiesCondition = [](ValueTy Item) {
501+
return Item.getSecond().value_or(false);
502+
};
503+
504+
TransferFunctions TF(VD);
505+
BackwardDataflowWorklist Worklist(*AC.getCFG(), AC);
506+
Worklist.enqueueBlock(&VarBlk);
507+
while (const CFGBlock *B = Worklist.dequeue()) {
508+
// First check the current block.
509+
for (CFGBlock::const_reverse_iterator ri = B->rbegin(), re = B->rend();
510+
ri != re; ++ri) {
511+
if (std::optional<CFGStmt> cs = ri->getAs<CFGStmt>()) {
512+
const Stmt *S = cs->getStmt();
513+
TF.reset();
514+
TF.Visit(const_cast<Stmt *>(S));
515+
if (TF.AllValuesAreNoReturn) {
516+
if (!TF.AllValuesAreNoReturn.value())
517+
return false;
518+
BlocksToCheck[B] = true;
519+
break;
520+
}
521+
}
522+
}
523+
524+
// If all checked blocks satisfy the condition, the check is finished.
525+
if (std::all_of(BlocksToCheck.begin(), BlocksToCheck.end(),
526+
BlockSatisfiesCondition))
527+
return true;
528+
529+
// If this block does not contain the variable definition, check
530+
// its predecessors.
531+
if (!BlocksToCheck[B]) {
532+
Worklist.enqueuePredecessors(B);
533+
BlocksToCheck.erase(B);
534+
for (const auto &PredBlk : B->preds())
535+
if (!BlocksToCheck.contains(PredBlk))
536+
BlocksToCheck[PredBlk] = std::nullopt;
537+
}
538+
}
539+
540+
return false;
541+
}
542+
404543
//===----------------------------------------------------------------------===//
405544
// Check for missing return value.
406545
//===----------------------------------------------------------------------===//
@@ -527,6 +666,17 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
527666
HasAbnormalEdge = true;
528667
continue;
529668
}
669+
if (auto *Call = dyn_cast<CallExpr>(S)) {
670+
const Expr *Callee = Call->getCallee();
671+
if (Callee->getType()->isPointerType())
672+
if (auto *DeclRef =
673+
dyn_cast<DeclRefExpr>(Callee->IgnoreParenImpCasts()))
674+
if (auto *VD = dyn_cast<VarDecl>(DeclRef->getDecl()))
675+
if (areAllValuesNoReturn(VD, B, AC)) {
676+
HasAbnormalEdge = true;
677+
continue;
678+
}
679+
}
530680

531681
HasPlainEdge = true;
532682
}

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8059,7 +8059,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
80598059
NewVD->setInvalidDecl();
80608060

80618061
// Handle GNU asm-label extension (encoded as an attribute).
8062-
if (Expr *E = (Expr*)D.getAsmLabel()) {
8062+
if (Expr *E = D.getAsmLabel()) {
80638063
// The parser guarantees this is a string.
80648064
StringLiteral *SE = cast<StringLiteral>(E);
80658065
StringRef Label = SE->getString();
@@ -10333,7 +10333,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
1033310333
isFunctionTemplateSpecialization);
1033410334

1033510335
// Handle GNU asm-label extension (encoded as an attribute).
10336-
if (Expr *E = (Expr*) D.getAsmLabel()) {
10336+
if (Expr *E = D.getAsmLabel()) {
1033710337
// The parser guarantees this is a string.
1033810338
StringLiteral *SE = cast<StringLiteral>(E);
1033910339
NewFD->addAttr(AsmLabelAttr::Create(Context, SE->getString(),

clang/lib/Sema/SemaOverload.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ void StandardConversionSequence::setAsIdentityConversion() {
245245
IsLvalueReference = true;
246246
BindsToFunctionLvalue = false;
247247
BindsToRvalue = false;
248+
IsImplicitObjectArgumentQualificationConversion = false;
248249
BindsImplicitObjectArgumentWithoutRefQualifier = false;
249250
ObjCLifetimeConversionBinding = false;
250251
FromBracedInitList = false;
@@ -5317,6 +5318,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
53175318
ICS.Standard.DirectBinding = BindsDirectly;
53185319
ICS.Standard.IsLvalueReference = !isRValRef;
53195320
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
5321+
ICS.Standard.IsImplicitObjectArgumentQualificationConversion = false;
53205322
ICS.Standard.BindsToRvalue = InitCategory.isRValue();
53215323
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
53225324
ICS.Standard.ObjCLifetimeConversionBinding =
@@ -5496,6 +5498,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
54965498
ICS.Standard.IsLvalueReference = !isRValRef;
54975499
ICS.Standard.BindsToFunctionLvalue = false;
54985500
ICS.Standard.BindsToRvalue = true;
5501+
ICS.Standard.IsImplicitObjectArgumentQualificationConversion = false;
54995502
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
55005503
ICS.Standard.ObjCLifetimeConversionBinding = false;
55015504
} else if (ICS.isUserDefined()) {
@@ -5518,6 +5521,8 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
55185521
ICS.UserDefined.After.IsLvalueReference = !isRValRef;
55195522
ICS.UserDefined.After.BindsToFunctionLvalue = false;
55205523
ICS.UserDefined.After.BindsToRvalue = !LValRefType;
5524+
ICS.UserDefined.After.IsImplicitObjectArgumentQualificationConversion =
5525+
false;
55215526
ICS.UserDefined.After.BindsImplicitObjectArgumentWithoutRefQualifier = false;
55225527
ICS.UserDefined.After.ObjCLifetimeConversionBinding = false;
55235528
ICS.UserDefined.After.FromBracedInitList = false;
@@ -5802,6 +5807,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
58025807
StandardConversionSequence &SCS = Result.isStandard() ? Result.Standard :
58035808
Result.UserDefined.After;
58045809
SCS.ReferenceBinding = true;
5810+
SCS.IsImplicitObjectArgumentQualificationConversion = false;
58055811
SCS.IsLvalueReference = ToType->isLValueReferenceType();
58065812
SCS.BindsToRvalue = true;
58075813
SCS.BindsToFunctionLvalue = false;
@@ -5999,8 +6005,12 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
59996005
// affects the conversion rank.
60006006
QualType ClassTypeCanon = S.Context.getCanonicalType(ClassType);
60016007
ImplicitConversionKind SecondKind;
6002-
if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) {
6008+
bool IsQualificationConversion = false;
6009+
if (ImplicitParamType.getCanonicalType() == FromTypeCanon) {
60036010
SecondKind = ICK_Identity;
6011+
} else if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) {
6012+
SecondKind = ICK_Identity;
6013+
IsQualificationConversion = true;
60046014
} else if (S.IsDerivedFrom(Loc, FromType, ClassType)) {
60056015
SecondKind = ICK_Derived_To_Base;
60066016
} else if (!Method->isExplicitObjectMemberFunction()) {
@@ -6041,6 +6051,8 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
60416051
ICS.Standard.setFromType(FromType);
60426052
ICS.Standard.setAllToTypes(ImplicitParamType);
60436053
ICS.Standard.ReferenceBinding = true;
6054+
ICS.Standard.IsImplicitObjectArgumentQualificationConversion =
6055+
IsQualificationConversion;
60446056
ICS.Standard.DirectBinding = true;
60456057
ICS.Standard.IsLvalueReference = Method->getRefQualifier() != RQ_RValue;
60466058
ICS.Standard.BindsToFunctionLvalue = false;

clang/test/Format/multiple-inputs-error.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: cp %s %t-1.cpp
22
// RUN: cp %s %t-2.cpp
3-
// RUN: not clang-format 2>&1 >/dev/null -offset=1 -length=1 %t-1.cpp %t-2.cpp |FileCheck %s
3+
// RUN: not clang-format 2>&1 >/dev/null -offset=1 -length=0 %t-1.cpp %t-2.cpp |FileCheck %s
44
// RUN: not clang-format 2>&1 >/dev/null -lines=1:1 %t-1.cpp %t-2.cpp |FileCheck %s -check-prefix=CHECK-LINE
55
// CHECK: error: -offset, -length and -lines can only be used for single file.
66
// CHECK-LINE: error: -offset, -length and -lines can only be used for single file.

clang/test/Format/ranges.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: grep -Ev "// *[A-Z-]+:" %s \
2-
// RUN: | clang-format -style=LLVM -offset=2 -length=1 -offset=28 -length=1 -offset=35 -length=8 \
2+
// RUN: | clang-format -style=LLVM -offset=2 -length=0 -offset=28 -length=0 \
33
// RUN: | FileCheck -strict-whitespace %s
44
// CHECK: {{^int\ \*i;$}}
55
int*i;
@@ -9,12 +9,3 @@ int * i;
99

1010
// CHECK: {{^int\ \*i;$}}
1111
int * i;
12-
13-
// CHECK: int I;
14-
// CHECK-NEXT: int J ;
15-
int I ;
16-
int J ;
17-
18-
// RUN: not clang-format -length=0 %s 2>&1 \
19-
// RUN: | FileCheck -strict-whitespace -check-prefix=CHECK0 %s
20-
// CHECK0: error: length should be at least 1

0 commit comments

Comments
 (0)