82 changes: 31 additions & 51 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10818,6 +10818,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
break;
}

// Similar to no_builtin logic above, at this point of the code
// FunctionDecl::isThisDeclarationADefinition() always returns `false`
// because Sema::ActOnStartOfFunctionDef has not been called yet.
if (Context.getTargetInfo().allowDebugInfoForExternalRef() &&
!NewFD->isInvalidDecl() &&
D.getFunctionDefinitionKind() == FunctionDefinitionKind::Declaration)
ExternalDeclarations.push_back(NewFD);

return NewFD;
}

Expand Down Expand Up @@ -11201,6 +11209,10 @@ static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) {
// otherwise it is treated as a normal function.
if (TA && !TA->isDefaultVersion())
return false;
// The target_version attribute only causes Multiversioning if this
// declaration is NOT the default version.
if (TVA && TVA->isDefaultVersion())
return false;

if ((TA || TVA) && CheckMultiVersionValue(S, FD)) {
FD->setInvalidDecl();
Expand Down Expand Up @@ -11234,18 +11246,16 @@ static void patchDefaultTargetVersion(FunctionDecl *From, FunctionDecl *To) {

if (MVKindTo == MultiVersionKind::None &&
(MVKindFrom == MultiVersionKind::TargetVersion ||
MVKindFrom == MultiVersionKind::TargetClones)) {
To->setIsMultiVersion();
MVKindFrom == MultiVersionKind::TargetClones))
To->addAttr(TargetVersionAttr::CreateImplicit(
To->getASTContext(), "default", To->getSourceRange()));
}
}

static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
FunctionDecl *NewFD,
bool &Redeclaration,
NamedDecl *&OldDecl,
LookupResult &Previous) {
static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
FunctionDecl *NewFD,
bool &Redeclaration,
NamedDecl *&OldDecl,
LookupResult &Previous) {
assert(!OldFD->isMultiVersion() && "Unexpected MultiVersion");

// The definitions should be allowed in any order. If we have discovered
Expand All @@ -11256,13 +11266,16 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
const auto *NewTA = NewFD->getAttr<TargetAttr>();
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
const auto *OldTA = OldFD->getAttr<TargetAttr>();
const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>();

// If the old decl is NOT MultiVersioned yet, and we don't cause that
// to change, this is a simple redeclaration.
if ((NewTA && !NewTA->isDefaultVersion() &&
(!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) ||
(NewTVA && !NewTVA->isDefaultVersion() &&
(!OldTVA || OldTVA->getName() == NewTVA->getName())))
if (NewTA && !NewTA->isDefaultVersion() &&
(!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()))
return false;

// The target_version attribute only causes Multiversioning if this
// declaration is NOT the default version.
if (NewTVA && NewTVA->isDefaultVersion())
return false;

// Otherwise, this decl causes MultiVersioning.
Expand All @@ -11279,8 +11292,7 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
}

// If this is 'default', permit the forward declaration.
if ((NewTA && NewTA->isDefaultVersion() && !OldTA) ||
(NewTVA && NewTVA->isDefaultVersion() && !OldTVA)) {
if (NewTA && NewTA->isDefaultVersion() && !OldTA) {
Redeclaration = true;
OldDecl = OldFD;
OldFD->setIsMultiVersion();
Expand Down Expand Up @@ -11312,22 +11324,6 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
}
}

if (NewTVA) {
llvm::SmallVector<StringRef, 8> Feats;
OldTVA->getFeatures(Feats);
llvm::sort(Feats);
llvm::SmallVector<StringRef, 8> NewFeats;
NewTVA->getFeatures(NewFeats);
llvm::sort(NewFeats);

if (Feats == NewFeats) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
NewFD->setInvalidDecl();
return true;
}
}

for (const auto *FD : OldFD->redecls()) {
const auto *CurTA = FD->getAttr<TargetAttr>();
const auto *CurTVA = FD->getAttr<TargetVersionAttr>();
Expand Down Expand Up @@ -11683,24 +11679,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,

FunctionDecl *OldFD = OldDecl->getAsFunction();

if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) {
if (NewTVA || !OldFD->getAttr<TargetVersionAttr>())
return false;
if (!NewFD->getType()->getAs<FunctionProtoType>()) {
// Multiversion declaration doesn't have prototype.
S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto);
NewFD->setInvalidDecl();
} else {
// No "target_version" attribute is equivalent to "default" attribute.
NewFD->addAttr(TargetVersionAttr::CreateImplicit(
S.Context, "default", NewFD->getSourceRange()));
NewFD->setIsMultiVersion();
OldFD->setIsMultiVersion();
OldDecl = OldFD;
Redeclaration = true;
}
return true;
}
if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None)
return false;

// Multiversioned redeclarations aren't allowed to omit the attribute, except
// for target_clones and target_version.
Expand All @@ -11717,8 +11697,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
switch (MVKind) {
case MultiVersionKind::Target:
case MultiVersionKind::TargetVersion:
return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, Redeclaration,
OldDecl, Previous);
return CheckDeclarationCausesMultiVersioning(
S, OldFD, NewFD, Redeclaration, OldDecl, Previous);
case MultiVersionKind::TargetClones:
if (OldFD->isUsed(false)) {
NewFD->setInvalidDecl();
Expand Down
16 changes: 5 additions & 11 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3010,12 +3010,10 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
}

bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
StringRef &AttrStr, bool &isDefault) {
StringRef AttrStr) {
enum FirstParam { Unsupported };
enum SecondParam { None };
enum ThirdParam { Target, TargetClones, TargetVersion };
if (AttrStr.trim() == "default")
isDefault = true;
llvm::SmallVector<StringRef, 8> Features;
AttrStr.split(Features, "+");
for (auto &CurFeature : Features) {
Expand All @@ -3035,16 +3033,12 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation LiteralLoc;
bool isDefault = false;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) ||
S.checkTargetVersionAttr(LiteralLoc, D, Str, isDefault))
S.checkTargetVersionAttr(LiteralLoc, D, Str))
return;
// Do not create default only target_version attribute
if (!isDefault) {
TargetVersionAttr *NewAttr =
::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
D->addAttr(NewAttr);
}
TargetVersionAttr *NewAttr =
::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
D->addAttr(NewAttr);
}

static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3719,8 +3719,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// The C++ standard bans deleting a pointer to a non-object type, which
// effectively bans deletion of "void*". However, most compilers support
// this, so we treat it as a warning unless we're in a SFINAE context.
Diag(StartLoc, diag::ext_delete_void_ptr_operand)
<< Type << Ex.get()->getSourceRange();
// But we still prohibit this since C++26.
Diag(StartLoc, LangOpts.CPlusPlus26 ? diag::err_delete_incomplete
: diag::ext_delete_void_ptr_operand)
<< (LangOpts.CPlusPlus26 ? Pointee : Type)
<< Ex.get()->getSourceRange();
} else if (Pointee->isFunctionType() || Pointee->isVoidType() ||
Pointee->isSizelessType()) {
return ExprError(Diag(StartLoc, diag::err_delete_operand)
Expand All @@ -3729,7 +3732,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// FIXME: This can result in errors if the definition was imported from a
// module but is hidden.
if (!RequireCompleteType(StartLoc, Pointee,
diag::warn_delete_incomplete, Ex.get())) {
LangOpts.CPlusPlus26
? diag::err_delete_incomplete
: diag::warn_delete_incomplete,
Ex.get())) {
if (const RecordType *RT = PointeeElem->getAs<RecordType>())
PointeeRD = cast<CXXRecordDecl>(RT->getDecl());
}
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9811,9 +9811,6 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// C++ [over.best.ics]p4:
// When [...] the constructor [...] is a candidate by
// - [over.match.copy] (in all cases)
// FIXME: The "second phase of [over.match.list] case can also
// theoretically happen here, but it's not clear whether we can
// ever have a parameter of the right type.
if (TD) {
SmallVector<Expr *, 8> TmpInits;
for (Expr *E : Inits)
Expand Down
36 changes: 29 additions & 7 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2743,7 +2743,7 @@ Expr *
buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
TypeAliasTemplateDecl *AliasTemplate,
ArrayRef<DeducedTemplateArgument> DeduceResults,
Expr *IsDeducible) {
unsigned FirstUndeducedParamIdx, Expr *IsDeducible) {
Expr *RC = F->getTemplateParameters()->getRequiresClause();
if (!RC)
return IsDeducible;
Expand Down Expand Up @@ -2803,8 +2803,22 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,

for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
const auto &D = DeduceResults[Index];
if (D.isNull())
if (D.isNull()) { // non-deduced template parameters of f
NamedDecl *TP = F->getTemplateParameters()->getParam(Index);
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
// Rebuild the template parameter with updated depth and index.
NamedDecl *NewParam = transformTemplateParameter(
SemaRef, F->getDeclContext(), TP, Args,
/*NewIndex=*/FirstUndeducedParamIdx,
getTemplateParameterDepth(TP) + AdjustDepth);
FirstUndeducedParamIdx += 1;
assert(TemplateArgsForBuildingRC[Index].isNull());
TemplateArgsForBuildingRC[Index] = Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
continue;
}
TemplateArgumentLoc Input =
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
TemplateArgumentLoc Output;
Expand All @@ -2820,8 +2834,8 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
MultiLevelTemplateArgumentList ArgsForBuildingRC;
ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
// For 2), if the underlying F is instantiated from a member template, we need
// the entire template argument list, as the constraint AST in the
// For 2), if the underlying deduction guide F is nested in a class template,
// we need the entire template argument list, as the constraint AST in the
// require-clause of F remains completely uninstantiated.
//
// For example:
Expand All @@ -2845,7 +2859,13 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
// We add the outer template arguments which is [int] to the multi-level arg
// list to ensure that the occurrence U in `C<U>` will be replaced with int
// during the substitution.
if (F->getInstantiatedFromMemberTemplate()) {
//
// NOTE: The underlying deduction guide F is instantiated -- either from an
// explicitly-written deduction guide member, or from a constructor.
// getInstantiatedFromMemberTemplate() can only handle the former case, so we
// check the DeclContext kind.
if (F->getLexicalDeclContext()->getDeclKind() ==
clang::Decl::ClassTemplateSpecialization) {
auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
F, F->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
Expand Down Expand Up @@ -3063,6 +3083,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
Context.getInjectedTemplateArg(NewParam));
TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
}
unsigned FirstUndeducedParamIdx = FPrimeTemplateParams.size();
// ...followed by the template parameters of f that were not deduced
// (including their default template arguments)
for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
Expand Down Expand Up @@ -3131,8 +3152,9 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,

Expr *IsDeducible = buildIsDeducibleConstraint(
SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams);
Expr *RequiresClause = buildAssociatedConstraints(
SemaRef, F, AliasTemplate, DeduceResults, IsDeducible);
Expr *RequiresClause =
buildAssociatedConstraints(SemaRef, F, AliasTemplate, DeduceResults,
FirstUndeducedParamIdx, IsDeducible);

auto *FPrimeTemplateParamList = TemplateParameterList::Create(
Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4704,6 +4704,12 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
return;
}

// The noexcept specification could reference any lambda captures. Ensure
// those are added to the LocalInstantiationScope.
LambdaScopeForCallOperatorInstantiationRAII PushLambdaCaptures(
*this, Decl, TemplateArgs, Scope,
/*ShouldAddDeclsFromParentScope=*/false);

SubstExceptionSpec(Decl, Template->getType()->castAs<FunctionProtoType>(),
TemplateArgs);
}
Expand Down
211 changes: 168 additions & 43 deletions clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//

#include "InterCheckerAPI.h"
#include "clang/AST/OperationKinds.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/CharInfo.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
Expand All @@ -22,10 +23,13 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
#include <optional>
Expand Down Expand Up @@ -304,6 +308,10 @@ class CStringChecker : public Checker< eval::Call,
// Re-usable checks
ProgramStateRef checkNonNull(CheckerContext &C, ProgramStateRef State,
AnyArgExpr Arg, SVal l) const;
// Check whether the origin region behind \p Element (like the actual array
// region \p Element is from) is initialized.
ProgramStateRef checkInit(CheckerContext &C, ProgramStateRef state,
AnyArgExpr Buffer, SVal Element, SVal Size) const;
ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state,
AnyArgExpr Buffer, SVal Element,
AccessKind Access,
Expand All @@ -329,7 +337,7 @@ class CStringChecker : public Checker< eval::Call,
const Stmt *S, StringRef WarningMsg) const;
void emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const;
void emitUninitializedReadBug(CheckerContext &C, ProgramStateRef State,
const Expr *E) const;
const Expr *E, StringRef Msg) const;
ProgramStateRef checkAdditionOverflow(CheckerContext &C,
ProgramStateRef state,
NonLoc left,
Expand All @@ -351,16 +359,16 @@ REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
// Individual checks and utility methods.
//===----------------------------------------------------------------------===//

std::pair<ProgramStateRef , ProgramStateRef >
CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V,
std::pair<ProgramStateRef, ProgramStateRef>
CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef State, SVal V,
QualType Ty) {
std::optional<DefinedSVal> val = V.getAs<DefinedSVal>();
if (!val)
return std::pair<ProgramStateRef , ProgramStateRef >(state, state);
return std::pair<ProgramStateRef, ProgramStateRef>(State, State);

SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
return state->assume(svalBuilder.evalEQ(state, *val, zero));
return State->assume(svalBuilder.evalEQ(State, *val, zero));
}

ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
Expand Down Expand Up @@ -393,6 +401,149 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
return stateNonNull;
}

static std::optional<NonLoc> getIndex(ProgramStateRef State,
const ElementRegion *ER, CharKind CK) {
SValBuilder &SVB = State->getStateManager().getSValBuilder();
ASTContext &Ctx = SVB.getContext();

if (CK == CharKind::Regular) {
if (ER->getValueType() != Ctx.CharTy)
return {};
return ER->getIndex();
}

if (ER->getValueType() != Ctx.WideCharTy)
return {};

QualType SizeTy = Ctx.getSizeType();
NonLoc WideSize =
SVB.makeIntVal(Ctx.getTypeSizeInChars(Ctx.WideCharTy).getQuantity(),
SizeTy)
.castAs<NonLoc>();
SVal Offset =
SVB.evalBinOpNN(State, BO_Mul, ER->getIndex(), WideSize, SizeTy);
if (Offset.isUnknown())
return {};
return Offset.castAs<NonLoc>();
}

// Basically 1 -> 1st, 12 -> 12th, etc.
static void printIdxWithOrdinalSuffix(llvm::raw_ostream &Os, unsigned Idx) {
Os << Idx << llvm::getOrdinalSuffix(Idx);
}

ProgramStateRef CStringChecker::checkInit(CheckerContext &C,
ProgramStateRef State,
AnyArgExpr Buffer, SVal Element,
SVal Size) const {

// If a previous check has failed, propagate the failure.
if (!State)
return nullptr;

const MemRegion *R = Element.getAsRegion();
const auto *ER = dyn_cast_or_null<ElementRegion>(R);
if (!ER)
return State;

const auto *SuperR = ER->getSuperRegion()->getAs<TypedValueRegion>();
if (!SuperR)
return State;

// FIXME: We ought to able to check objects as well. Maybe
// UninitializedObjectChecker could help?
if (!SuperR->getValueType()->isArrayType())
return State;

SValBuilder &SVB = C.getSValBuilder();
ASTContext &Ctx = SVB.getContext();

const QualType ElemTy = Ctx.getBaseElementType(SuperR->getValueType());
const NonLoc Zero = SVB.makeZeroArrayIndex();

std::optional<Loc> FirstElementVal =
State->getLValue(ElemTy, Zero, loc::MemRegionVal(SuperR)).getAs<Loc>();
if (!FirstElementVal)
return State;

// Ensure that we wouldn't read uninitialized value.
if (Filter.CheckCStringUninitializedRead &&
State->getSVal(*FirstElementVal).isUndef()) {
llvm::SmallString<258> Buf;
llvm::raw_svector_ostream OS(Buf);
OS << "The first element of the ";
printIdxWithOrdinalSuffix(OS, Buffer.ArgumentIndex + 1);
OS << " argument is undefined";
emitUninitializedReadBug(C, State, Buffer.Expression, OS.str());
return nullptr;
}

// We won't check whether the entire region is fully initialized -- lets just
// check that the first and the last element is. So, onto checking the last
// element:
const QualType IdxTy = SVB.getArrayIndexType();

NonLoc ElemSize =
SVB.makeIntVal(Ctx.getTypeSizeInChars(ElemTy).getQuantity(), IdxTy)
.castAs<NonLoc>();

// FIXME: Check that the size arg to the cstring function is divisible by
// size of the actual element type?

// The type of the argument to the cstring function is either char or wchar,
// but thats not the type of the original array (or memory region).
// Suppose the following:
// int t[5];
// memcpy(dst, t, sizeof(t) / sizeof(t[0]));
// When checking whether t is fully initialized, we see it as char array of
// size sizeof(int)*5. If we check the last element as a character, we read
// the last byte of an integer, which will be undefined. But just because
// that value is undefined, it doesn't mean that the element is uninitialized!
// For this reason, we need to retrieve the actual last element with the
// correct type.

// Divide the size argument to the cstring function by the actual element
// type. This value will be size of the array, or the index to the
// past-the-end element.
std::optional<NonLoc> Offset =
SVB.evalBinOpNN(State, clang::BO_Div, Size.castAs<NonLoc>(), ElemSize,
IdxTy)
.getAs<NonLoc>();

// Retrieve the index of the last element.
const NonLoc One = SVB.makeIntVal(1, IdxTy).castAs<NonLoc>();
SVal LastIdx = SVB.evalBinOpNN(State, BO_Sub, *Offset, One, IdxTy);

if (!Offset)
return State;

SVal LastElementVal =
State->getLValue(ElemTy, LastIdx, loc::MemRegionVal(SuperR));
if (!isa<Loc>(LastElementVal))
return State;

if (Filter.CheckCStringUninitializedRead &&
State->getSVal(LastElementVal.castAs<Loc>()).isUndef()) {
const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
// If we can't get emit a sensible last element index, just bail out --
// prefer to emit nothing in favour of emitting garbage quality reports.
if (!IdxInt) {
C.addSink();
return nullptr;
}
llvm::SmallString<258> Buf;
llvm::raw_svector_ostream OS(Buf);
OS << "The last accessed element (at index ";
OS << IdxInt->getExtValue();
OS << ") in the ";
printIdxWithOrdinalSuffix(OS, Buffer.ArgumentIndex + 1);
OS << " argument is undefined";
emitUninitializedReadBug(C, State, Buffer.Expression, OS.str());
return nullptr;
}
return State;
}

// FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor?
ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
ProgramStateRef state,
Expand All @@ -413,38 +564,17 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
if (!ER)
return state;

SValBuilder &svalBuilder = C.getSValBuilder();
ASTContext &Ctx = svalBuilder.getContext();

// Get the index of the accessed element.
NonLoc Idx = ER->getIndex();

if (CK == CharKind::Regular) {
if (ER->getValueType() != Ctx.CharTy)
return state;
} else {
if (ER->getValueType() != Ctx.WideCharTy)
return state;

QualType SizeTy = Ctx.getSizeType();
NonLoc WideSize =
svalBuilder
.makeIntVal(Ctx.getTypeSizeInChars(Ctx.WideCharTy).getQuantity(),
SizeTy)
.castAs<NonLoc>();
SVal Offset = svalBuilder.evalBinOpNN(state, BO_Mul, Idx, WideSize, SizeTy);
if (Offset.isUnknown())
return state;
Idx = Offset.castAs<NonLoc>();
}
std::optional<NonLoc> Idx = getIndex(state, ER, CK);
if (!Idx)
return state;

// Get the size of the array.
const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
DefinedOrUnknownSVal Size =
getDynamicExtent(state, superReg, C.getSValBuilder());

ProgramStateRef StInBound, StOutBound;
std::tie(StInBound, StOutBound) = state->assumeInBoundDual(Idx, Size);
auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
if (StOutBound && !StInBound) {
// These checks are either enabled by the CString out-of-bounds checker
// explicitly or implicitly by the Malloc checker.
Expand All @@ -459,15 +589,6 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
return nullptr;
}

// Ensure that we wouldn't read uninitialized value.
if (Access == AccessKind::read) {
if (Filter.CheckCStringUninitializedRead &&
StInBound->getSVal(ER).isUndef()) {
emitUninitializedReadBug(C, StInBound, Buffer.Expression);
return nullptr;
}
}

// Array bound check succeeded. From this point forward the array bound
// should always succeed.
return StInBound;
Expand Down Expand Up @@ -502,6 +623,7 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,

// Check if the first byte of the buffer is accessible.
State = CheckLocation(C, State, Buffer, BufStart, Access, CK);

if (!State)
return nullptr;

Expand All @@ -526,6 +648,8 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
SVal BufEnd =
svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
State = CheckLocation(C, State, Buffer, BufEnd, Access, CK);
if (Access == AccessKind::read)
State = checkInit(C, State, Buffer, BufEnd, *Length);

// If the buffer isn't large enough, abort.
if (!State)
Expand Down Expand Up @@ -694,16 +818,17 @@ void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State,

void CStringChecker::emitUninitializedReadBug(CheckerContext &C,
ProgramStateRef State,
const Expr *E) const {
const Expr *E,
StringRef Msg) const {
if (ExplodedNode *N = C.generateErrorNode(State)) {
const char *Msg =
"Bytes string function accesses uninitialized/garbage values";
if (!BT_UninitRead)
BT_UninitRead.reset(new BugType(Filter.CheckNameCStringUninitializedRead,
"Accessing unitialized/garbage values"));

auto Report =
std::make_unique<PathSensitiveBugReport>(*BT_UninitRead, Msg, N);
Report->addNote("Other elements might also be undefined",
Report->getLocation());
Report->addRange(E->getSourceRange());
bugreporter::trackExpressionValue(N, E, *Report);
C.emitReport(std::move(Report));
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/StaticAnalyzer/Core/MemRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,17 @@ bool MemRegion::canPrintPrettyAsExpr() const {
return false;
}

StringRef MemRegion::getKindStr() const {
switch (getKind()) {
#define REGION(Id, Parent) \
case Id##Kind: \
return #Id;
#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
#undef REGION
}
llvm_unreachable("Unkown kind!");
}

void MemRegion::printPretty(raw_ostream &os) const {
assert(canPrintPretty() && "This region cannot be printed pretty.");
os << "'";
Expand Down
18 changes: 18 additions & 0 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,12 @@ namespace DeclRefs {
constexpr B b;
static_assert(b.a.m == 100, "");
static_assert(b.a.f == 100, "");

constexpr B b2;
static_assert(b2.a.m == 100, "");
static_assert(b2.a.f == 100, "");
static_assert(b2.a.f == 101, ""); // both-error {{failed}} \
// both-note {{evaluates to '100 == 101'}}
}

namespace PointerArith {
Expand Down Expand Up @@ -1482,3 +1488,15 @@ namespace FloatAPValue {
ClassTemplateArgRefTemplate<ClassTemplateArgObj.Arg> ClassTemplateArgRefObj;
}
#endif

namespace LocalWithThisPtrInit {
struct S {
int i;
int *p = &i;
};
constexpr int foo() {
S s{2};
return *s.p;
}
static_assert(foo() == 2, "");
}
27 changes: 27 additions & 0 deletions clang/test/AST/ast-dump-ctad-alias.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,33 @@ Out2<double>::AInner t(1.0);
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'double'
// CHECK-NEXT: | `-ParmVarDecl {{.*}} 'double'

// GH92596
template <typename T0>
struct Out3 {
template<class T1, typename T2>
struct Foo {
// Deduction guide:
// template <typename T1, typename T2, typename V>
// Foo(V, T1) -> Foo<T1, T2>;
template<class V> requires Concept<T0, V> // V in require clause of Foo deduction guide: depth 1, index: 2
Foo(V, T1);
};
};
template<class T3>
using AFoo3 = Out3<int>::Foo<T3, T3>;
AFoo3 afoo3{0, 1};
// Verify occurrence V in the require-clause is transformed (depth: 1 => 0, index: 2 => 1) correctly.

// CHECK: FunctionTemplateDecl {{.*}} implicit <deduction guide for AFoo3>
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} class depth 0 index 0 T3
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} class depth 0 index 1 V
// CHECK-NEXT: |-BinaryOperator {{.*}} '<dependent type>' '&&'
// CHECK-NEXT: | |-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue (no ADL) = 'Concept'
// CHECK-NEXT: | | |-TemplateArgument type 'int'
// CHECK-NEXT: | | | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-0-1'
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent depth 0 index 1

template <typename... T1>
struct Foo {
Foo(T1...);
Expand Down
119 changes: 96 additions & 23 deletions clang/test/Analysis/bstring_UninitRead.c
Original file line number Diff line number Diff line change
@@ -1,59 +1,132 @@
// RUN: %clang_analyze_cc1 -verify %s \
// RUN: -analyzer-checker=core,alpha.unix.cstring


// This file is generally for the alpha.unix.cstring.UninitializedRead Checker, the reason for putting it into
// the separate file because the checker is break the some existing test cases in bstring.c file , so we don't
// wanna mess up with some existing test case so it's better to create separate file for it, this file also include
// the broken test for the reference in future about the broken tests.

//===----------------------------------------------------------------------===//
// mempcpy() using character array. This is the easiest case, as memcpy
// intepretrs the dst and src buffers as character arrays (regardless of their
// actual type).
//===----------------------------------------------------------------------===//

typedef typeof(sizeof(int)) size_t;

void clang_analyzer_eval(int);

void *memcpy(void *restrict s1, const void *restrict s2, size_t n);

void top(char *dst) {
void memcpy_array_fully_uninit(char *dst) {
char buf[10];
memcpy(dst, buf, 10); // expected-warning{{The first element of the 2nd argument is undefined}}
// expected-note@-1{{Other elements might also be undefined}}
(void)buf;
}

void memcpy_array_partially_uninit(char *dst) {
char buf[10];
memcpy(dst, buf, 10); // expected-warning{{Bytes string function accesses uninitialized/garbage values}}
buf[0] = 'i';
memcpy(dst, buf, 10); // expected-warning{{The last accessed element (at index 9) in the 2nd argument is undefined}}
// expected-note@-1{{Other elements might also be undefined}}
(void)buf;
}

void memcpy_array_only_init_portion(char *dst) {
char buf[10];
buf[0] = 'i';
memcpy(dst, buf, 1);
(void)buf;
}

void memcpy_array_partially_init_error(char *dst) {
char buf[10];
buf[0] = 'i';
memcpy(dst, buf, 2); // expected-warning{{The last accessed element (at index 1) in the 2nd argument is undefined}}
// expected-note@-1{{Other elements might also be undefined}}
(void)buf;
}

// The interesting case here is that the portion we're copying is initialized,
// but not the whole matrix. We need to be careful to extract buf[1], and not
// buf when trying to peel region layers off from the source argument.
void memcpy_array_from_matrix(char *dst) {
char buf[2][2];
buf[1][0] = 'i';
buf[1][1] = 'j';
// FIXME: This is a FP -- we mistakenly retrieve the first element of buf,
// instead of the first element of buf[1]. getLValueElement simply peels off
// another ElementRegion layer, when in this case it really shouldn't.
memcpy(dst, buf[1], 2); // expected-warning{{The first element of the 2nd argument is undefined}}
// expected-note@-1{{Other elements might also be undefined}}
(void)buf;
}

//===----------------------------------------------------------------------===
// mempcpy()
//===----------------------------------------------------------------------===
//===----------------------------------------------------------------------===//
// mempcpy() using non-character arrays.
//===----------------------------------------------------------------------===//

void *mempcpy(void *restrict s1, const void *restrict s2, size_t n);

void mempcpy14() {
void memcpy_int_array_fully_init() {
int src[] = {1, 2, 3, 4};
int dst[5] = {0};
int *p;

p = mempcpy(dst, src, 4 * sizeof(int)); // expected-warning{{Bytes string function accesses uninitialized/garbage values}}
// FIXME: This behaviour is actually surprising and needs to be fixed,
// mempcpy seems to consider the very last byte of the src buffer uninitialized
// and returning undef unfortunately. It should have returned unknown or a conjured value instead.
p = mempcpy(dst, src, 4 * sizeof(int));
clang_analyzer_eval(p == &dst[4]);
}

clang_analyzer_eval(p == &dst[4]); // no-warning (above is fatal)
void memcpy_int_array_fully_init2(int *dest) {
int t[] = {1, 2, 3};
memcpy(dest, t, sizeof(t));
}

//===----------------------------------------------------------------------===//
// mempcpy() using nonarrays.
//===----------------------------------------------------------------------===//

struct st {
int i;
int j;
};


void mempcpy15() {
void mempcpy_struct_partially_uninit() {
struct st s1 = {0};
struct st s2;
struct st *p1;
struct st *p2;

p1 = (&s2) + 1;
p2 = mempcpy(&s2, &s1, sizeof(struct st)); // expected-warning{{Bytes string function accesses uninitialized/garbage values}}
// FIXME: It seems same as mempcpy14() case.

clang_analyzer_eval(p1 == p2); // no-warning (above is fatal)

// FIXME: Maybe ask UninitializedObjectChecker whether s1 is fully
// initialized?
p2 = mempcpy(&s2, &s1, sizeof(struct st));

clang_analyzer_eval(p1 == p2);
}

void mempcpy_struct_fully_uninit() {
struct st s1;
struct st s2;

// FIXME: Maybe ask UninitializedObjectChecker whether s1 is fully
// initialized?
mempcpy(&s2, &s1, sizeof(struct st));
}

// Creduced crash. In this case, an symbolicregion is wrapped in an
// elementregion for the src argument.
void *ga_copy_strings_from_0;
void *memmove();
void alloc();
void ga_copy_strings() {
int i = 0;
for (;; ++i)
memmove(alloc, ((char **)ga_copy_strings_from_0)[i], 1);
}

// Creduced crash. In this case, retrieving the Loc for the first element failed.
char mov_mdhd_language_map[][4] = {};
int ff_mov_lang_to_iso639_code;
char *ff_mov_lang_to_iso639_to;
void ff_mov_lang_to_iso639() {
memcpy(ff_mov_lang_to_iso639_to,
mov_mdhd_language_map[ff_mov_lang_to_iso639_code], 4);
}
22 changes: 13 additions & 9 deletions clang/test/CXX/drs/cwg5xx.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// RUN: %clang_cc1 -std=c++98 %s -verify=expected,cxx98-11,cxx98-14,cxx98-17,cxx98 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx98-11,cxx98-14,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++14 %s -verify=expected,cxx98-14,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++17 %s -verify=expected,since-cxx17,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++20 %s -verify=expected,since-cxx20,since-cxx17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx23,since-cxx20,since-cxx17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++98 %s -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,cxx98 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++14 %s -verify=expected,cxx98-23,cxx98-14,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++17 %s -verify=expected,cxx98-23,since-cxx17,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx98-23,since-cxx20,since-cxx17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,cxx98-23,since-cxx23,since-cxx20,since-cxx17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx26,since-cxx23,since-cxx20,since-cxx17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors

#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
Expand Down Expand Up @@ -901,7 +902,8 @@ namespace cwg573 { // cwg573: no
void *d = reinterpret_cast<void*>(c);
// cxx98-error@-1 {{cast between pointer-to-function and pointer-to-object is an extension}}
void f() { delete a; }
// expected-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
int n = d - a;
// expected-error@-1 {{arithmetic on pointers to void}}
// FIXME: This is ill-formed.
Expand Down Expand Up @@ -1238,11 +1240,13 @@ namespace cwg599 { // cwg599: partial
struct V { operator int*(); operator Fn*(); };
void f(void *p, void (*q)(), S s, T t, U u, V v) {
delete p;
// expected-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
delete q;
// expected-error@-1 {{cannot delete expression of type 'void (*)()'}}
delete s;
// expected-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
delete t;
// expected-error@-1 {{cannot delete expression of type 'T'}}
// FIXME: This is valid, but is rejected due to a non-conforming GNU
Expand Down
12 changes: 12 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-forward-declaration-inline.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify

inline int func2(int i);
int external_call2(int i) {
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
[[clang::musttail]] return func2(i);
}

inline int func2(int i) {
return 0;
}
12 changes: 12 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-forward-declaration-weak.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify

int func2(int i);
int external_call2(int i) {
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
[[clang::musttail]] return func2(i);
}

__attribute__((weak)) int func2(int i) {
return 0;
}
11 changes: 11 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-forward-declaration.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good

int func2(int i);
int external_call2(int i) {
// good-no-diagnostics
[[clang::musttail]] return func2(i);
}
int func2(int i) {
return 0;
}
8 changes: 8 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-indirect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
// RUN: %clang_cc1 %s -triple powerpc-unknown-linux-gnu -o /dev/null -emit-llvm -verify

void name(int *params) {
auto fn = (void (*)(int *))1;
// expected-error@+1 {{'musttail' attribute for this call is impossible because indirect calls can not be tail called on PPC}}
[[clang::musttail]] return fn(params);
}
12 changes: 12 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-inline.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify

inline int foo(int x) {
return x;
}

int bar(int x)
{
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
[[clang::musttail]] return foo(1);
}
10 changes: 10 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-undefined.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify

int foo(int x);

int bar(int x)
{
// expected-error@+1 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
[[clang::musttail]] return foo(x);
}
13 changes: 13 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail-weak.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify=linux
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify=linux

__attribute__((weak)) int func2(int i) {
return 0;
}
int external_call2(int i) {
// linux-error@+2 {{'musttail' attribute for this call is impossible because external calls can not be tail called on PPC}}
// aix-error@+1 {{'musttail' attribute is not supported on AIX}}
[[clang::musttail]] return func2(i);
}
20 changes: 20 additions & 0 deletions clang/test/CodeGen/PowerPC/musttail.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -o /dev/null -emit-llvm -verify=aix
// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
// RUN: %clang_cc1 %s -triple powerpc-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -o /dev/null -emit-llvm -verify=good
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -target-feature +pcrelative-memops -o /dev/null -emit-llvm -verify=good
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -target-feature +longcall -o /dev/null -emit-llvm -verify=longcall
// RUN: %clang_cc1 %s -triple powerpc64le-unknown-linux-gnu -target-feature +pcrelative-memops -target-feature +longcall -o /dev/null -emit-llvm -verify=good

int foo(int x) {
return x;
}

int bar(int x)
{
// good-no-diagnostics
// longcall-error@+2 {{'musttail' attribute for this call is impossible because long calls can not be tail called on PPC}}
// aix-error@+1 {{'musttail' attribute is not supported on AIX}}
[[clang::musttail]] return foo(1);
}
88 changes: 44 additions & 44 deletions clang/test/CodeGen/attr-target-version.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,13 +428,6 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@fmv_default
// CHECK-SAME: () #[[ATTR11]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: ret i32 111
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@fmv_c._Mssbs
// CHECK-SAME: () #[[ATTR11]] {
// CHECK-NEXT: entry:
Expand Down Expand Up @@ -637,22 +630,18 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@recur
// CHECK-LABEL: define {{[^@]+}}@fmv_default
// CHECK-SAME: () #[[ATTR11]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @reca()
// CHECK-NEXT: ret void
// CHECK-NEXT: ret i32 111
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@main
// CHECK-LABEL: define {{[^@]+}}@recur
// CHECK-SAME: () #[[ATTR11]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4
// CHECK-NEXT: call void @recur()
// CHECK-NEXT: [[CALL:%.*]] = call i32 @goo()
// CHECK-NEXT: ret i32 [[CALL]]
// CHECK-NEXT: call void @reca()
// CHECK-NEXT: ret void
//
//
// CHECK: Function Attrs: noinline nounwind optnone
Expand Down Expand Up @@ -818,6 +807,17 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@main
// CHECK-SAME: () #[[ATTR11]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4
// CHECK-NEXT: call void @recur()
// CHECK-NEXT: [[CALL:%.*]] = call i32 @goo()
// CHECK-NEXT: ret i32 [[CALL]]
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@fmv_inline._Mf64mmMpmullMsha1
// CHECK-SAME: () #[[ATTR22:[0-9]+]] {
// CHECK-NEXT: entry:
Expand Down Expand Up @@ -1020,20 +1020,6 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_default
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 111
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_c
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret void
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@goo
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
Expand All @@ -1053,22 +1039,25 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@recur
// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_c
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: call void @reca()
// CHECK-NOFMV-NEXT: ret void
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@main
// CHECK-NOFMV-LABEL: define {{[^@]+}}@fmv_default
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
// CHECK-NOFMV-NEXT: store i32 0, ptr [[RETVAL]], align 4
// CHECK-NOFMV-NEXT: call void @recur()
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @goo()
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
// CHECK-NOFMV-NEXT: ret i32 111
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@recur
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: call void @reca()
// CHECK-NOFMV-NEXT: ret void
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
Expand All @@ -1089,31 +1078,42 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_default_def
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_default_def
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 1
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_default_def
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_forward_default_def
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 1
// CHECK-NOFMV-NEXT: ret i32 0
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_implicit_forward_default_def
// CHECK-NOFMV-LABEL: define {{[^@]+}}@default_def_with_version_decls
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 0
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@default_def_with_version_decls
// CHECK-NOFMV-LABEL: define {{[^@]+}}@main
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 0
// CHECK-NOFMV-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
// CHECK-NOFMV-NEXT: store i32 0, ptr [[RETVAL]], align 4
// CHECK-NOFMV-NEXT: call void @recur()
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @goo()
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
//
//
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
// CHECK-NOFMV-LABEL: define {{[^@]+}}@unused_with_default_def
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
// CHECK-NOFMV-NEXT: entry:
// CHECK-NOFMV-NEXT: ret i32 1
//
//.
// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+flagm,+fp-armv8,+fp16fml,+fullfp16,+neon,+rand,-v9.5a" }
Expand Down
9 changes: 9 additions & 0 deletions clang/test/CodeGen/bpf-debug-info-extern-func.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %clang -g -target bpf -S -emit-llvm %s -o - | FileCheck %s
//
// When linking BPF object files via bpftool, BTF info is required for
// every symbol. BTF is generated from debug info. Ensure that debug info
// is emitted for extern functions referenced via variable initializers.
//
// CHECK: !DISubprogram(name: "fn"
extern void fn(void);
void (*pfn) (void) = &fn;
11 changes: 11 additions & 0 deletions clang/test/CodeGen/bpf-debug-info-unref.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: %clang -g -target bpf -S -emit-llvm %s -o - | FileCheck %s
//
// No debug info is produced for unreferenced functions.
// CHECK-NOT: !DISubprogram
void unref(void);
void unref2(typeof(unref));

// No debug info for unused extern variables as well.
// CHECK-NOT: !DiGlobalVariable
extern int unused;
extern int unused2[sizeof(unused)];
60 changes: 47 additions & 13 deletions clang/test/CodeGenCXX/fmv-namespace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,26 @@ int __attribute((target_version("sve"))) foo() { return 2; }

int baz() { return OtherName::foo(); }

namespace Foo {
int bar();
__attribute((target_version("default"))) int bar() { return 0; }
__attribute((target_version("mops"))) int bar() { return 1; }
}

//.
// CHECK: @__aarch64_cpu_features = external dso_local global { i64 }
// CHECK: @_ZN4Name3fooEv = weak_odr ifunc i32 (), ptr @_ZN4Name3fooEv.resolver
// CHECK: @_ZN9OtherName3fooEv = weak_odr ifunc i32 (), ptr @_ZN9OtherName3fooEv.resolver
// CHECK: @_ZN3Foo3barEv = weak_odr ifunc i32 (), ptr @_ZN3Foo3barEv.resolver
//.
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default(
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 0
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv._Msve(
// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 1
//
//
// CHECK-LABEL: define dso_local noundef i32 @_Z3barv(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN4Name3fooEv()
// CHECK-NEXT: ret i32 [[CALL]]
Expand All @@ -56,13 +57,13 @@ int baz() { return OtherName::foo(); }
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN9OtherName3fooEv._Msve(
// CHECK-SAME: ) #[[ATTR1]] {
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 2
//
//
// CHECK-LABEL: define dso_local noundef i32 @_Z3bazv(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-SAME: ) #[[ATTR1]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN9OtherName3fooEv()
// CHECK-NEXT: ret i32 [[CALL]]
Expand All @@ -81,10 +82,43 @@ int baz() { return OtherName::foo(); }
// CHECK: [[RESOLVER_ELSE]]:
// CHECK-NEXT: ret ptr @_ZN9OtherName3fooEv.default
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN3Foo3barEv.default(
// CHECK-SAME: ) #[[ATTR1]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 0
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN3Foo3barEv._Mmops(
// CHECK-SAME: ) #[[ATTR2:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 1
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default(
// CHECK-SAME: ) #[[ATTR1]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 0
//
//
// CHECK-LABEL: define weak_odr ptr @_ZN3Foo3barEv.resolver() comdat {
// CHECK-NEXT: [[RESOLVER_ENTRY:.*:]]
// CHECK-NEXT: call void @__init_cpu_features_resolver()
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 576460752303423488
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 576460752303423488
// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
// CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]]
// CHECK: [[RESOLVER_RETURN]]:
// CHECK-NEXT: ret ptr @_ZN3Foo3barEv._Mmops
// CHECK: [[RESOLVER_ELSE]]:
// CHECK-NEXT: ret ptr @_ZN3Foo3barEv.default
//
//.
// CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
// CHECK: attributes #[[ATTR1]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" }
// CHECK: attributes #[[ATTR2:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
// CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" }
// CHECK: attributes #[[ATTR1]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
// CHECK: attributes #[[ATTR2]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+mops" }
// CHECK: attributes #[[ATTR3:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
//.
// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
Expand Down
71 changes: 71 additions & 0 deletions clang/test/CodeGenCXX/mangle-ms-auto-templates-memptrs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19.20 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-windows-msvc | FileCheck --check-prefix=AFTER %s
// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19.14 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-windows-msvc | FileCheck --check-prefix=BEFORE %s

template <auto a>
class AutoParmTemplate {
public:
AutoParmTemplate() {}
};

template <auto a>
auto AutoFunc() {
return a;
}

struct A {};
struct B {};

struct S { int a; void f(); virtual void g(); };
struct M : A, B { int a; void f(); virtual void g(); };
struct V : virtual A { int a; void f(); virtual void g(); };

void template_mangling() {

AutoParmTemplate<&S::f> auto_method_single_inheritance;
// AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MP8S@@EAAXXZ1?f@1@QEAAXXZ@@QEAA@XZ"
// BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$1?f@S@@QEAAXXZ@@QEAA@XZ"

AutoParmTemplate<&M::f> auto_method_multiple_inheritance;
// AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MP8M@@EAAXXZH?f@1@QEAAXXZA@@@QEAA@XZ"
// BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$H?f@M@@QEAAXXZA@@@QEAA@XZ"

AutoParmTemplate<&V::f> auto_method_virtual_inheritance;
// AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MP8V@@EAAXXZI?f@1@QEAAXXZA@A@@@QEAA@XZ"
// BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$I?f@V@@QEAAXXZA@A@@@QEAA@XZ"

AutoFunc<&S::f>();
// AFTER: call {{.*}} @"??$AutoFunc@$MP8S@@EAAXXZ1?f@1@QEAAXXZ@@YA?A?<auto>@@XZ"
// BEFORE: call {{.*}} @"??$AutoFunc@$1?f@S@@QEAAXXZ@@YA?A?<auto>@@XZ"

AutoFunc<&M::f>();
// AFTER: call {{.*}} @"??$AutoFunc@$MP8M@@EAAXXZH?f@1@QEAAXXZA@@@YA?A?<auto>@@XZ"
// BEFORE: call {{.*}} @"??$AutoFunc@$H?f@M@@QEAAXXZA@@@YA?A?<auto>@@XZ"

AutoFunc<&V::f>();
// AFTER: call {{.*}} @"??$AutoFunc@$MP8V@@EAAXXZI?f@1@QEAAXXZA@A@@@YA?A?<auto>@@XZ"
// BEFORE: call {{.*}} @"??$AutoFunc@$I?f@V@@QEAAXXZA@A@@@YA?A?<auto>@@XZ"

AutoParmTemplate<&S::a> auto_data_single_inheritance;
// AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MPEQS@@H07@@QEAA@XZ"
// BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$07@@QEAA@XZ"

AutoParmTemplate<&M::a> auto_data_multiple_inheritance;
// AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MPEQM@@H0M@@@QEAA@XZ"
// BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$0M@@@QEAA@XZ"

AutoParmTemplate<&V::a> auto_data_virtual_inheritance;
// AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MPEQV@@HFBA@A@@@QEAA@XZ"
// BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$FBA@A@@@QEAA@XZ"

AutoFunc<&S::a>();
// AFTER: call {{.*}} @"??$AutoFunc@$MPEQS@@H07@@YA?A?<auto>@@XZ"
// BEFORE: call {{.*}} @"??$AutoFunc@$07@@YA?A?<auto>@@XZ"

AutoFunc<&M::a>();
// AFTER: call {{.*}} @"??$AutoFunc@$MPEQM@@H0M@@@YA?A?<auto>@@XZ"
// BEFORE: call {{.*}} @"??$AutoFunc@$0M@@@YA?A?<auto>@@XZ"

AutoFunc<&V::a>();
// AFTER: call {{.*}} @"??$AutoFunc@$MPEQV@@HFBA@A@@@YA?A?<auto>@@XZ"
// BEFORE: call {{.*}} @"??$AutoFunc@$FBA@A@@@YA?A?<auto>@@XZ"
}
24 changes: 24 additions & 0 deletions clang/test/CodeGenCXX/mangle-ms-auto-templates-nullptr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19.20 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-windows-msvc | FileCheck --check-prefix=AFTER %s
// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19.14 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-windows-msvc | FileCheck --check-prefix=BEFORE %s

template <auto a>
class AutoParmTemplate {
public:
AutoParmTemplate() {}
};

template <auto a>
auto AutoFunc() {
return a;
}

void template_mangling() {

AutoParmTemplate<nullptr> auto_nullptr;
// AFTER: call {{.*}} @"??0?$AutoParmTemplate@$M$$T0A@@@QEAA@XZ"
// BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$0A@@@QEAA@XZ"

AutoFunc<nullptr>();
// AFTER: call {{.*}} @"??$AutoFunc@$M$$T0A@@@YA?A?<auto>@@XZ"
// BEFORE: call {{.*}} @"??$AutoFunc@$0A@@@YA?A?<auto>@@XZ"
}
8 changes: 8 additions & 0 deletions clang/test/CodeGenHIP/printf-builtin.hip
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// REQUIRES: amdgpu-registered-target
// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -emit-llvm -disable-llvm-optzns -mprintf-kind=hostcall -fno-builtin-printf -fcuda-is-device \
// RUN: -o - %s | FileCheck --check-prefixes=CHECK,HOSTCALL %s
// RUN: %clang_cc1 -triple spirv64-amd-amdhsa -emit-llvm -disable-llvm-optzns -mprintf-kind=hostcall -fno-builtin-printf -fcuda-is-device \
// RUN: -o - %s | FileCheck --check-prefixes=CHECK-AMDGCNSPIRV,HOSTCALL-AMDGCNSPIRV %s
// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -emit-llvm -disable-llvm-optzns -mprintf-kind=buffered -fno-builtin-printf -fcuda-is-device \
// RUN: -o - %s | FileCheck --check-prefixes=CHECK,BUFFERED %s
// RUN: %clang_cc1 -triple spirv64-amd-amdhsa -emit-llvm -disable-llvm-optzns -mprintf-kind=buffered -fno-builtin-printf -fcuda-is-device \
// RUN: -o - %s | FileCheck --check-prefixes=CHECK-AMDGCNSPIRV,BUFFERED-AMDGCNSPIRV %s

#define __device__ __attribute__((device))

Expand All @@ -11,13 +15,17 @@ extern "C" __device__ int printf(const char *format, ...);
// CHECK-LABEL: @_Z4foo1v()
__device__ int foo1() {
// HOSTCALL: call i64 @__ockl_printf_begin
// HOSTCALL-AMDGCNSPIRV: call addrspace(4) i64 @__ockl_printf_begin
// BUFFERED: call ptr addrspace(1) @__printf_alloc
// BUFFERED-AMDGCNSPIRV: call addrspace(4) ptr addrspace(1) @__printf_alloc
// CHECK-NOT: call i32 (ptr, ...) @printf
// CHECK-AMDGCNSPIRV-NOT: call i32 (ptr, ...) @printf
return __builtin_printf("Hello World\n");
}

// CHECK-LABEL: @_Z4foo2v()
__device__ int foo2() {
// CHECK: call i32 (ptr, ...) @printf
// CHECK-AMDGCNSPIRV: call spir_func addrspace(4) i32 (ptr addrspace(4), ...) @printf
return printf("Hello World\n");
}
229 changes: 202 additions & 27 deletions clang/test/CodeGenHIP/printf.cpp

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions clang/test/OpenMP/declare_mapper_codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ void foo(int a){
// CK0: }

// CK0: define internal void [[OMP_OUTLINED_16:@.+]](i32{{.*}} %{{[^,]+}}, ptr noalias noundef %{{[^,]+}}, ptr noalias noundef %{{[^,]+}}
// CK0-DAG: call void @__tgt_target_data_begin_nowait_mapper(ptr @{{.+}}, i64 -1, i32 1, ptr [[BP:%[^,]+]], ptr [[P:%[^,]+]], ptr [[SZ:%[^,]+]], ptr [[EDNWTYPES]], ptr null, ptr [[MPR:%.+]])
// CK0-DAG: call void @__tgt_target_data_begin_nowait_mapper(ptr @{{.+}}, i64 -1, i32 1, ptr [[BP:%[^,]+]], ptr [[P:%[^,]+]], ptr [[SZ:%[^,]+]], ptr [[EDNWTYPES]], ptr null, ptr [[MPR:%.+]], i32 0, ptr null, i32 0, ptr null)
// CK0-DAG: [[BP]] = getelementptr inbounds [1 x ptr], ptr [[BPADDR:%[^,]+]], i[[sz]] 0, i[[sz]] 0
// CK0-DAG: [[P]] = getelementptr inbounds [1 x ptr], ptr [[PADDR:%[^,]+]], i[[sz]] 0, i[[sz]] 0
// CK0-DAG: [[SZ]] = getelementptr inbounds [1 x i64], ptr [[SZADDR:%[^,]+]], i[[sz]] 0, i[[sz]] 0
Expand All @@ -533,7 +533,7 @@ void foo(int a){
// CK0: }

// CK0: define internal void [[OMP_OUTLINED_23:@.+]](i32{{.*}} %{{[^,]+}}, ptr noalias noundef %{{[^,]+}}, ptr noalias noundef %{{[^,]+}}
// CK0-DAG: call void @__tgt_target_data_end_nowait_mapper(ptr @{{.+}}, i64 -1, i32 1, ptr [[BP:%[^,]+]], ptr [[P:%[^,]+]], ptr [[SZ:%[^,]+]], ptr [[EXDNWTYPES]], ptr null, ptr [[MPR:%.+]])
// CK0-DAG: call void @__tgt_target_data_end_nowait_mapper(ptr @{{.+}}, i64 -1, i32 1, ptr [[BP:%[^,]+]], ptr [[P:%[^,]+]], ptr [[SZ:%[^,]+]], ptr [[EXDNWTYPES]], ptr null, ptr [[MPR:%.+]], i32 0, ptr null, i32 0, ptr null)
// CK0-DAG: [[BP]] = getelementptr inbounds [1 x ptr], ptr [[BPADDR:%[^,]+]], i[[sz]] 0, i[[sz]] 0
// CK0-DAG: [[P]] = getelementptr inbounds [1 x ptr], ptr [[PADDR:%[^,]+]], i[[sz]] 0, i[[sz]] 0
// CK0-DAG: [[SZ]] = getelementptr inbounds [1 x i64], ptr [[SZADDR:%[^,]+]], i[[sz]] 0, i[[sz]] 0
Expand All @@ -551,7 +551,7 @@ void foo(int a){
// CK0: }

// CK0: define internal void [[OMP_OUTLINED_32:@.+]](i32{{.*}} %{{[^,]+}}, ptr noalias noundef %{{[^,]+}}, ptr noalias noundef %{{[^,]+}}
// CK0-DAG: call void @__tgt_target_data_update_nowait_mapper(ptr @{{.+}}, i64 -1, i32 1, ptr [[BP:%[^,]+]], ptr [[P:%[^,]+]], ptr [[SZ:%[^,]+]], ptr [[FNWTYPES]], ptr null, ptr [[MPR:%.+]])
// CK0-DAG: call void @__tgt_target_data_update_nowait_mapper(ptr @{{.+}}, i64 -1, i32 1, ptr [[BP:%[^,]+]], ptr [[P:%[^,]+]], ptr [[SZ:%[^,]+]], ptr [[FNWTYPES]], ptr null, ptr [[MPR:%.+]], i32 0, ptr null, i32 0, ptr null)
// CK0-DAG: [[BP]] = getelementptr inbounds [1 x ptr], ptr [[BPADDR:%[^,]+]], i[[sz]] 0, i[[sz]] 0
// CK0-DAG: [[P]] = getelementptr inbounds [1 x ptr], ptr [[PADDR:%[^,]+]], i[[sz]] 0, i[[sz]] 0
// CK0-DAG: [[SZ]] = getelementptr inbounds [1 x i64], ptr [[SZADDR:%[^,]+]], i[[sz]] 0, i[[sz]] 0
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/deferred-diags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ namespace TestDeleteIncompleteClassDefinition {
struct a;
struct b {
b() {
delete c; // expected-warning {{deleting pointer to incomplete type 'a' may cause undefined behavior}}
delete c; // expected-warning {{deleting pointer to incomplete type 'a' is incompatible with C++2c and may cause undefined behavior}}
}
a *c;
};
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/target_enter_data_codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ void foo(int arg) {


// CK1: define internal {{.*}}i32 [[OMP_TASK_ENTRY]](i32 {{.*}}%0, ptr noalias noundef %1)
// CK1-DAG: call void @__tgt_target_data_begin_nowait_mapper(ptr @{{.+}}, i64 %{{[^,]+}}, i32 1, ptr [[BPADDR:%[^,]+]], ptr [[PADDR:%[^,]+]], ptr [[SZADDR:%[^,]+]], ptr [[MTYPE00]], ptr null, ptr null)
// CK1-DAG: call void @__tgt_target_data_begin_nowait_mapper(ptr @{{.+}}, i64 %{{[^,]+}}, i32 1, ptr [[BPADDR:%[^,]+]], ptr [[PADDR:%[^,]+]], ptr [[SZADDR:%[^,]+]], ptr [[MTYPE00]], ptr null, ptr null, i32 0, ptr null, i32 0, ptr null)
// CK1-DAG: [[BPADDR]] = load ptr, ptr [[FPBP:%[^,]+]], align
// CK1-DAG: [[PADDR]] = load ptr, ptr [[FPP:%[^,]+]], align
// CK1-DAG: [[SZADDR]] = load ptr, ptr [[FPSZ:%[^,]+]], align
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/target_exit_data_codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ void foo(int arg) {
}

// CK1: define internal {{.*}}i32 [[OMP_TASK_ENTRY]](i32 {{.*}}%{{[^,]+}}, ptr noalias noundef %{{[^,]+}})
// CK1-DAG: call void @__tgt_target_data_end_nowait_mapper(ptr @{{.+}}, i64 %{{[^,]+}}, i32 1, ptr [[BP:%[^,]+]], ptr [[P:%[^,]+]], ptr [[SZ:%[^,]+]], ptr [[MTYPE00]], ptr null, ptr null)
// CK1-DAG: call void @__tgt_target_data_end_nowait_mapper(ptr @{{.+}}, i64 %{{[^,]+}}, i32 1, ptr [[BP:%[^,]+]], ptr [[P:%[^,]+]], ptr [[SZ:%[^,]+]], ptr [[MTYPE00]], ptr null, ptr null, i32 0, ptr null, i32 0, ptr null)
// CK1-DAG: [[BP]] = load ptr, ptr [[FPBPADDR:%[^,]+]], align
// CK1-DAG: [[P]] = load ptr, ptr [[FPPADDR:%[^,]+]], align
// CK1-DAG: [[SZ]] = load ptr, ptr [[FPSZADDR:%[^,]+]], align
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/target_update_codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ void foo(int arg) {
}

// CK1: define internal {{.*}}i32 [[OMP_TASK_ENTRY]](i32 {{.*}}%{{[^,]+}}, ptr noalias noundef %{{[^,]+}})
// CK1-DAG: call void @__tgt_target_data_update_nowait_mapper(ptr @{{.+}}, i64 %{{[^,]+}}, i32 1, ptr [[BP:%[^,]+]], ptr [[P:%[^,]+]], ptr [[SZ:%[^,]+]], ptr [[MTYPE00]], ptr null, ptr null)
// CK1-DAG: call void @__tgt_target_data_update_nowait_mapper(ptr @{{.+}}, i64 %{{[^,]+}}, i32 1, ptr [[BP:%[^,]+]], ptr [[P:%[^,]+]], ptr [[SZ:%[^,]+]], ptr [[MTYPE00]], ptr null, ptr null, i32 0, ptr null, i32 0, ptr null)
// CK1-DAG: [[BP]] = load ptr, ptr [[FPBPADDR:%[^,]+]], align
// CK1-DAG: [[P]] = load ptr, ptr [[FPPADDR:%[^,]+]], align
// CK1-DAG: [[SZ]] = load ptr, ptr [[FPSZADDR:%[^,]+]], align
Expand Down
7 changes: 6 additions & 1 deletion clang/test/Sema/attr-target-version.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ int __attribute__((aarch64_vector_pcs, target_version("sha3"))) combine(void) {

int __attribute__((target_version("fp+aes+pmull+rcpc"))) unspec_args() { return -1; }
// expected-error@-1 {{multiversioned function must have a prototype}}
// expected-error@+1 {{multiversioned function must have a prototype}}
int __attribute__((target_version("default"))) unspec_args() { return 0; }
int cargs() { return unspec_args(); }

int unspec_args_implicit_default_first();
// expected-error@-1 {{multiversioned function must have a prototype}}
// expected-note@+1 {{function multiversioning caused by this declaration}}
int __attribute__((target_version("aes"))) unspec_args_implicit_default_first() { return -1; }
int __attribute__((target_version("default"))) unspec_args_implicit_default_first() { return 0; }
27 changes: 26 additions & 1 deletion clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ template <typename U>
using Bar = Foo<U>; // expected-note {{could not match 'Foo<type-parameter-0-0>' against 'int'}} \
// expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<type-parameter-0-0>) Bar(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
// expected-note {{candidate template ignored: constraints not satisfied}} \
// expected-note {{implicit deduction guide declared as 'template <typename T> requires False<T> && __is_deducible(test18::Bar, Foo<int>) Bar(type-parameter-0-0) -> Foo<int>'}} \
// expected-note {{implicit deduction guide declared as 'template <typename T> requires False<type-parameter-0-0> && __is_deducible(test18::Bar, Foo<int>) Bar(type-parameter-0-0) -> Foo<int>'}} \
// expected-note {{candidate function template not viable}} \
// expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<type-parameter-0-0>) Bar() -> Foo<type-parameter-0-0>'}}

Expand Down Expand Up @@ -414,4 +414,29 @@ struct A1 {
template <typename U>
using AFoo = A1<int>::A2<int>::Foo<U>;
AFoo case3(1);

// Case4: crashes on the constexpr evaluator due to the mixed-up index for the
// template parameters `V`.
template<class T, typename T2>
struct Case4 {
template<class V> requires C<V>
Case4(V, T);
};

template<class T2>
using ACase4 = Case4<T2, T2>;
ACase4 case4{0, 1};

} // namespace test24

namespace GH92212 {
template<typename T, typename...Us>
struct A{
template<typename V> requires __is_same(V, int)
A(V);
};

template<typename...TS>
using AA = A<int, TS...>;
AA a{0};
}
10 changes: 10 additions & 0 deletions clang/test/SemaCXX/eval-crashes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,13 @@ struct array {
array() : data(*new int[1][2]) {}
};
}

namespace GH96670 {
inline constexpr long ullNil = -1;

template<typename T = long, const T &Nil = ullNil>
struct Test {};

inline constexpr long lNil = -1;
Test<long, lNil> c;
}
26 changes: 17 additions & 9 deletions clang/test/SemaCXX/new-delete.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify=expected,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++98
// RUN: %clang_cc1 -fsyntax-only -verify=expected,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++11
// RUN: %clang_cc1 -fsyntax-only -verify=expected,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++14
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++17
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++98
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++11
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++14
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++17
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23
// RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++2c

// FIXME Location is (frontend)
// cxx17-note@*:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
Expand Down Expand Up @@ -172,8 +174,12 @@ void bad_deletes()
{
delete 0; // expected-error {{cannot delete expression of type 'int'}}
delete [0] (int*)0; // expected-error {{expected variable name or 'this' in lambda capture list}}
delete (void*)0; // expected-warning {{cannot delete expression with pointer-to-'void' type 'void *'}}
delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
delete (void*)0;
// cxx98-23-warning@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
delete (T*)0;
// cxx98-23-warning@-1 {{deleting pointer to incomplete type}}
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'T'}}
::S::delete (int*)0; // expected-error {{expected unqualified-id}}
}

Expand Down Expand Up @@ -513,8 +519,10 @@ namespace DeleteIncompleteClass {

namespace DeleteIncompleteClassPointerError {
struct A; // expected-note {{forward declaration}}
void f(A *x) { 1+delete x; } // expected-warning {{deleting pointer to incomplete type}} \
// expected-error {{invalid operands to binary expression}}
void f(A *x) { 1+delete x; }
// expected-error@-1 {{invalid operands to binary expression}}
// cxx98-23-warning@-2 {{deleting pointer to incomplete type}}
// since-cxx26-error@-3 {{cannot delete pointer to incomplete type 'A'}}
}

namespace PR10504 {
Expand Down
23 changes: 23 additions & 0 deletions clang/test/SemaTemplate/generic-lambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,26 @@ template<class T1> C1<X<X<T1>>> auto t3() {
template C1<X<X<int>>> auto t3<int>();
static_assert(is_same<decltype(t3<int>()), X<X<X<int>>>>);
#endif

namespace GH95735 {

int g(int fn) {
return [f = fn](auto tpl) noexcept(noexcept(f)) { return f; }(0);
}

int foo(auto... fn) {
// FIXME: This one hits the assertion "if the exception specification is dependent,
// then the noexcept expression should be value-dependent" in the constructor of
// FunctionProtoType.
// One possible solution is to update Sema::canThrow() to consider expressions
// (e.g. DeclRefExpr/FunctionParmPackExpr) involving unexpanded parameters as Dependent.
// This would effectively add an extra value-dependent flag to the noexcept expression.
// However, I'm afraid that would also cause ABI breakage.
// [...f = fn](auto tpl) noexcept(noexcept(f)) { return 0; }(0);
[...f = fn](auto tpl) noexcept(noexcept(g(fn...))) { return 0; }(0);
return [...f = fn](auto tpl) noexcept(noexcept(g(f...))) { return 0; }(0);
}

int v = foo(42);

} // namespace GH95735
9 changes: 9 additions & 0 deletions clang/unittests/Format/SortIncludesTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,15 @@ TEST_F(SortIncludesTest, DisableRawStringLiteralSorting) {
#undef X
}

TEST_F(SortIncludesTest, BlockCommentedOutIncludes) {
StringRef Code{"/* #include \"foo.h\"\n"
"#include \"bar.h\" */\n"
"#include <chrono>"};

FmtStyle = getGoogleStyle(FormatStyle::LK_Cpp);
verifyFormat(Code, sort(Code, "input.cpp", 0));
}

} // end namespace
} // end namespace format
} // end namespace clang
2 changes: 1 addition & 1 deletion clang/unittests/Frontend/CompilerInstanceTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
DiagOpts, DiagPrinter.get(), /*ShouldOwnClient=*/false);

Diags->Report(diag::err_expected) << "no crash";
ASSERT_EQ(DiagnosticsOS.str(), "error: expected no crash\n");
ASSERT_EQ(DiagnosticOutput, "error: expected no crash\n");
}

} // anonymous namespace
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) {
}
if (EmitDeclIndices)
OS << "@" << Index++;
Matcher.match(OS.str(), D);
Matcher.match(Path, D);
return true;
}

Expand All @@ -96,7 +96,7 @@ bool LexicallyOrderedDeclVisitor::VisitDeclRefExpr(const DeclRefExpr *D) {
llvm::raw_string_ostream OS(Name);
if (EmitStmtIndices)
OS << "@" << Index++;
Matcher.match(OS.str(), D);
Matcher.match(Name, D);
return true;
}

Expand Down
8 changes: 4 additions & 4 deletions clang/utils/TableGen/ClangAttrEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4786,7 +4786,7 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
// Write out the declaration merging check logic.
OS << "static bool DiagnoseMutualExclusions(Sema &S, const NamedDecl *D, "
<< "const Attr *A) {\n";
OS << MergeDeclOS.str();
OS << DeclMergeChecks;
OS << " return true;\n";
OS << "}\n\n";

Expand All @@ -4796,7 +4796,7 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << "static bool DiagnoseMutualExclusions(Sema &S, "
<< "const SmallVectorImpl<const Attr *> &C) {\n";
OS << " for (const Attr *A : C) {\n";
OS << MergeStmtOS.str();
OS << StmtMergeChecks;
OS << " }\n";
OS << " return true;\n";
OS << "}\n\n";
Expand Down Expand Up @@ -4939,7 +4939,7 @@ void EmitClangAttrTextNodeDump(RecordKeeper &Records, raw_ostream &OS) {
if (!Args.empty())
OS << " const auto *SA = cast<" << R.getName()
<< "Attr>(A); (void)SA;\n";
OS << SS.str();
OS << FunctionContent;
OS << " }\n";
}
}
Expand Down Expand Up @@ -4968,7 +4968,7 @@ void EmitClangAttrNodeTraverse(RecordKeeper &Records, raw_ostream &OS) {
if (!Args.empty())
OS << " const auto *SA = cast<" << R.getName()
<< "Attr>(A); (void)SA;\n";
OS << SS.str();
OS << FunctionContent;
OS << " }\n";
}
}
Expand Down
939 changes: 7 additions & 932 deletions clang/www/analyzer/alpha_checks.html

Large diffs are not rendered by default.

1,743 changes: 7 additions & 1,736 deletions clang/www/analyzer/available_checks.html

Large diffs are not rendered by default.

68 changes: 10 additions & 58 deletions clang/www/analyzer/codechecker.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>CodeChecker: running the analyzer from the command line</title>
<title>The CodeChecker documentation has moved to clang.llvm.org</title>
<link rel="canonical" href="https://clang.llvm.org/docs/analyzer/user-docs/CommandLineUsage.html#codechecker"/>
<meta http-equiv="refresh" content="0;url=https://clang.llvm.org/docs/analyzer/user-docs/CommandLineUsage.html#codechecker" />
<link type="text/css" rel="stylesheet" href="content.css">
<link type="text/css" rel="stylesheet" href="menu.css">
<script type="text/javascript" src="scripts/menu.js"></script>
Expand All @@ -13,61 +15,11 @@
<!--#include virtual="menu.html.incl"-->
<div id="content">

<h1>CodeChecker: running the analyzer from the command line</h1>
<h1>The Codechecker documentation has moved to clang.llvm.org</h1>
<p style="color:red; font-size:200%">This page is deprecated and will be removed in release 21.0</p>
<a href="https://clang.llvm.org/docs/analyzer/user-docs/CommandLineUsage.html#codechecker">The new site</a>
<script>window.location='https://clang.llvm.org/docs/analyzer/user-docs/CommandLineUsage.html#codechecker'</script>

<h2>Basic Usage</h2>

<p>
Install CodeChecker as described here: <a href="https://github.com/Ericsson/codechecker/#Install-guide"> CodeChecker Install Guide.</a>
</p>

<p>
Create a compilation database. If you use cmake then pass the <tt>-DCMAKE_EXPORT_COMPILE_COMMANDS=1</tt> parameter to cmake. Cmake will create a <tt>compile_commands.json</tt> file.
If you have a Makefile based or similar build system then you can log the build commands with the help of CodeChecker:
<pre class="code_example">
make clean
CodeChecker log -b "make" -o compile_commands.json
</pre>
</p>

<p>
Analyze your project.
<pre class="code_example">
CodeChecker analyze compile_commands.json -o ./reports
</pre>
</p>

<p>
View the analysis results.
Print the detailed results in the command line:
<pre class="code_example">
CodeChecker parse --print-steps ./reports
</pre>
Or view the detailed results in a browser:
<pre class="code_example">
CodeChecker parse ./reports -e html -o ./reports_html
firefox ./reports_html/index.html
</pre>
</p>

<p>
Optional: store the analysis results in a DB.
<pre class="code_example">
mkdir ./ws
CodeChecker server -w ./ws -v 8555 &
CodeChecker store ./reports --name my-project --url http://localhost:8555/Default
</pre>
</p>

<p>
Optional: manage (categorize, suppress) the results in your web browser:
<pre class="code_example">
firefox http://localhost:8555/Default
</pre>
</p>

<h2>Detailed Usage</h2>

<p>
For extended documentation please refer to the <a href="https://github.com/Ericsson/codechecker/blob/master/docs/usage.md">official site of CodeChecker</a>!
</p>
</div> <!-- content -->
</div> <!-- page -->
</body>
61 changes: 10 additions & 51 deletions clang/www/analyzer/command-line.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Running the analyzer from the command line</title>
<title>The command line documentation has moved to clang.llvm.org</title>
<link rel="canonical" href="https://clang.llvm.org/docs/analyzer/user-docs/CommandLineUsage.html"/>
<meta http-equiv="refresh" content="0;url=https://clang.llvm.org/docs/analyzer/user-docs/CommandLineUsage.html" />
<link type="text/css" rel="stylesheet" href="content.css">
<link type="text/css" rel="stylesheet" href="menu.css">
<script type="text/javascript" src="scripts/menu.js"></script>
Expand All @@ -13,55 +15,12 @@
<!--#include virtual="menu.html.incl"-->
<div id="content">

<h1>Running the analyzer from the command line</h1>
<h1>The command line documentation has moved to clang.llvm.org</h1>
<p style="color:red; font-size:200%">This page is deprecated and will be removed in release 21.0</p>
<a href="https://clang.llvm.org/docs/analyzer/user-docs/CommandLineUsage.html">The new site</a>
<script>window.location='https://clang.llvm.org/docs/analyzer/user-docs/CommandLineUsage.html'</script>

<p> Static Analyzer is by design a GUI tool. Its purpose is to find buggy execution
paths in the program, and such paths are very hard to comprehend by looking at
a non-interactive standard output. It is possible, however, to invoke the
Static Analyzer from the command line in order to obtain analysis results, and
then later view them interactively in a graphical interface. The following
tools are used commonly to run the analyzer from the command line. Both tools
are wrapper scripts to drive the analysis and the underlying invocations of the
Clang compiler:
<ol>
<li><a href="scan-build.html">Scan-Build</a>
is an old and simple command-line tool that emits static analyzer warnings as HTML files while compiling your project. You can view the analysis results in your web browser.
</li>
<ul>
<li>
Useful for individual developers who simply want to view static analysis results at their desk, or in a very simple collaborative environment.
</li>
<li>
Works on all major platforms (Windows, Linux, macOS) and is available as a package in many Linux distributions.
</li>
<li>
Does not include support for cross-translation-unit analysis.
</li>
</ul>
<li><a href="codechecker.html">CodeChecker</a>
is a web server that runs the Static Analyzer on your projects on demand and maintains a database of issues.
</li>
<ul>
<li>
Perfect for managing large amounts of Static Analyzer warnings in a collaborative environment.
</li>
<li>
Generally much more feature-rich than scan-build.
</li>
<li>Supports incremental analysis: Results can be stored in a database, subsequent analysis runs can be compared to list the newly added defects.</li>
<li><a href="https://clang.llvm.org/docs/analyzer/user-docs/CrossTranslationUnit.html">Cross Translation Unit (CTU) analysis</a> is supported fully on Linux via CodeChecker.</li>
<li>Can run clang-tidy checkers too.</li>
<li>Open source, but out-of-tree, i.e. not part of the LLVM project.</li>
</ul>
</ol>
</p>

<p>
</p>
<p>
</p>

</div>
</div>
</div> <!-- content -->
</div> <!-- page -->
</body>
</html>

37 changes: 9 additions & 28 deletions clang/www/analyzer/filing_bugs.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>The filing bugs documentation has moved to clang.llvm.org</title>
<link rel="canonical" href="https://clang.llvm.org/docs/analyzer/user-docs/FilingBugs.html"/>
<meta http-equiv="refresh" content="0;url=https://clang.llvm.org/docs/analyzer/user-docs/FilingBugs.html" />
<meta charset="UTF-8">
<title>Filing Bugs and Feature Requests</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
<script type="text/javascript" src="scripts/menu.js"></script>
Expand All @@ -14,32 +16,11 @@
<!--#include virtual="menu.html.incl"-->
<div id="content">

<h1>Filing Bugs and Feature Requests</h1>
<h1>The filing bugs documentation has moved to clang.llvm.org</h1>
<p style="color:red; font-size:200%">This page is deprecated and will be removed in release 21.0</p>
<a href="https://clang.llvm.org/docs/analyzer/user-docs/FilingBugs.html">The new site</a>
<script>window.location='https://clang.llvm.org/docs/analyzer/user-docs/FilingBugs.html'</script>

<p>We encourage users to file bug reports for any problems that they encounter.
We also welcome feature requests. When filing a bug report, please do the
following:</p>

<ul>

<li>Include the checker build (for prebuilt Mac OS X binaries) or the git hash.
</li>

<li>Provide a self-contained, reduced test case that exhibits the issue you are
experiencing.</li>

<li>Test cases don't tell us everything. Please briefly describe the problem you
are seeing, including what you thought should have been the expected behavior
and why.</li>

</ul>

<p>Please <a href="https://llvm.org/docs/HowToSubmitABug.html">file
bugs and feature requests</a> in
<a href="https://github.com/llvm/llvm-project/issues">LLVM's issue tracker</a>
and label the report with the <code>clang:static analyzer</code> label.</p>

</div>
</div>
</div> <!-- content -->
</div> <!-- page -->
</body>
</html>
2 changes: 1 addition & 1 deletion clang/www/analyzer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ <h2>Download</h2>
<h3 style="margin:0px;padding:0px">Mac OS X</h3>
<ul>
<li>Latest build (10.8+):<br>
<!--#include virtual="latest_checker.html.incl"-->
<b><a href="downloads/checker-279.tar.bz2">checker-279.tar.bz2</a></b> (built November 14, 2016)
</li>
<li><a href="/release_notes.html">Release notes</a></li>
<li>This build can be used both from the command line and from within Xcode</li>
Expand Down
103 changes: 9 additions & 94 deletions clang/www/analyzer/installation.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Obtaining the Static Analyzer</title>
<title>The installation documentation has moved to clang.llvm.org</title>
<link rel="canonical" href="https://clang.llvm.org/docs/analyzer/user-docs/Installation.html"/>
<meta http-equiv="refresh" content="0;url=https://clang.llvm.org/docs/analyzer/user-docs/Installation.html" />
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
<script type="text/javascript" src="scripts/menu.js"></script>
Expand All @@ -13,98 +15,11 @@
<!--#include virtual="menu.html.incl"-->
<div id="content">

<h1>Obtaining the Static Analyzer</h1>
<h1>The installation documentation has moved to clang.llvm.org</h1>
<p style="color:red; font-size:200%">This page is deprecated and will be removed in release 21.0</p>
<a href="https://clang.llvm.org/docs/analyzer/user-docs/Installation.html">The new site</a>
<script>window.location='https://clang.llvm.org/docs/analyzer/user-docs/Installation.html'</script>

<p>This page describes how to download and install the analyzer. Once
the analyzer is installed, follow the <a
href="/scan-build.html">instructions</a> on using <tt>scan-build</tt> to
get started analyzing your code.</p>

<h2>Packaged Builds (Mac OS X)</h2>

<p>Semi-regular pre-built binaries of the analyzer are available on Mac
OS X. These are built to run on OS X 10.7 and later.</p>

<p>Builds are released frequently. Often the differences between build
numbers being a few bug fixes or minor feature improvements. When using
the analyzer, we recommend that you check back here occasionally for new
builds, especially if the build you are using is more than a couple
weeks old.</p>

<p>The latest build is:
<!--#include virtual="latest_checker.html.incl"-->
</p>

<p>Packaged builds for other platforms may eventually be provided, but
we need volunteers who are willing to help provide such regular builds.
If you wish to help contribute regular builds of the analyzer on other
platforms, please email the <a
href="https://lists.llvm.org/mailman/listinfo/cfe-dev">Clang
Developers' mailing list</a>.</p>

<h3>Using Packaged Builds</h3>

<p>To use a package build, simply unpack it anywhere. If the build
archive has the name <b><tt>checker-XXX.tar.bz2</tt></b> then the
archive will expand to a directory called <b><tt>checker-XXX</tt></b>.
You do not need to place this directory or the contents of this
directory in any special place. Uninstalling the analyzer is as simple
as deleting this directory.</p>

<p>Most of the files in the <b><tt>checker-XXX</tt></b> directory will
be supporting files for the analyzer that you can simply ignore. Most
users will only care about two files, which are located at the top of
the <b><tt>checker-XXX</tt></b> directory:</p>

<ul>
<li><b>scan-build</b>: <tt>scan-build</tt> is the high-level command line utility for running the analyzer</li>
<li><b>scan-view</b>: <tt>scan-view</tt> a companion command line
utility to <tt>scan-build</tt>, <tt>scan-view</tt> is used to view
analysis results generated by <tt>scan-build</tt>. There is an option
that one can pass to <tt>scan-build</tt> to cause <tt>scan-view</tt> to
run as soon as it the analysis of a build completes</li>
</ul>

<h4>Running scan-build</h4>

<p>For specific details on using <tt>scan-build</tt>, please see
<tt>scan-build</tt>'s <a href="/scan-build">documentation</a>.</p>

<p>To run <tt>scan-build</tt>, either add the
<b><tt>checker-XXX</tt></b> directory to your path or specify a complete
path for <tt>scan-build</tt> when running it. It is also possible to use
a symbolic link to <tt>scan-build</tt>, such one located in a directory
in your path. When <tt>scan-build</tt> runs it will automatically
determine where to find its accompanying files.</p>

<h2 id="OtherPlatforms">Other Platforms (Building the Analyzer from Source)</h2>

<p>For other platforms, you must build Clang and LLVM manually. To do
so, please follow the instructions for <a
href="https://clang.llvm.org/get_started.html#build">building Clang from
source code</a>.<p>

<p>Once the Clang is built, you need to add the following to your path:</p>

<ul>

<li>The location of the <tt>clang</tt> binary.

<p>For example, if you built a <em>Debug+Asserts</em> build of LLVM/Clang (the
default), the resultant <tt>clang</tt> binary will be in <tt>$(OBJDIR)/Debug+Asserts/bin</tt>
(where <tt>$(OBJDIR)</tt> is often the same as the root source directory). You
can also do <tt>make install</tt> to install the LLVM/Clang libraries and
binaries to the installation directory of your choice (specified when you run
<tt>configure</tt>).</p></li>

<li>The locations of the <tt>scan-build</tt> and <tt>scan-view</tt>
programs.

<p>These are installed via <tt>make install</tt> into the bin directory
when clang is built.</p></li>

</ul>
</div>
</div>
</div> <!-- content -->
</div> <!-- page -->
</body>
</html>
1 change: 0 additions & 1 deletion clang/www/analyzer/latest_checker.html.incl

This file was deleted.

Loading