2,898 changes: 142 additions & 2,756 deletions clang/lib/Sema/SemaDeclAttr.cpp

Large diffs are not rendered by default.

15 changes: 11 additions & 4 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2469,11 +2469,18 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
// base class sub-objects shall be a constexpr constructor.
//
// Note that this rule is distinct from the "requirements for a constexpr
// function", so is not checked in CheckValid mode.
// function", so is not checked in CheckValid mode. Because the check for
// constexpr potential is expensive, skip the check if the diagnostic is
// disabled, the function is declared in a system header, or we're in C++23
// or later mode (see https://wg21.link/P2448).
bool SkipCheck =
!SemaRef.getLangOpts().CheckConstexprFunctionBodies ||
SemaRef.getSourceManager().isInSystemHeader(Dcl->getLocation()) ||
SemaRef.getDiagnostics().isIgnored(
diag::ext_constexpr_function_never_constant_expr, Dcl->getLocation());
SmallVector<PartialDiagnosticAt, 8> Diags;
if (Kind == Sema::CheckConstexprKind::Diagnose &&
!Expr::isPotentialConstantExpr(Dcl, Diags) &&
!SemaRef.getLangOpts().CPlusPlus23) {
if (Kind == Sema::CheckConstexprKind::Diagnose && !SkipCheck &&
!Expr::isPotentialConstantExpr(Dcl, Diags)) {
SemaRef.Diag(Dcl->getLocation(),
diag::ext_constexpr_function_never_constant_expr)
<< isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval()
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaExceptionSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {

// Most statements can throw if any substatement can throw.
case Stmt::OpenACCComputeConstructClass:
case Stmt::OpenACCLoopConstructClass:
case Stmt::AttributedStmtClass:
case Stmt::BreakStmtClass:
case Stmt::CapturedStmtClass:
Expand Down
27 changes: 25 additions & 2 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5813,6 +5813,27 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn,
return TypoCorrection();
}

// [C++26][[expr.unary.op]/p4
// A pointer to member is only formed when an explicit &
// is used and its operand is a qualified-id not enclosed in parentheses.
static bool isParenthetizedAndQualifiedAddressOfExpr(Expr *Fn) {
if (!isa<ParenExpr>(Fn))
return false;

Fn = Fn->IgnoreParens();

auto *UO = dyn_cast<UnaryOperator>(Fn);
if (!UO || UO->getOpcode() != clang::UO_AddrOf)
return false;
if (auto *DRE = dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParens())) {
assert(isa<FunctionDecl>(DRE->getDecl()) && "expected a function");
return DRE->hasQualifier();
}
if (auto *OVL = dyn_cast<OverloadExpr>(UO->getSubExpr()->IgnoreParens()))
return OVL->getQualifier();
return false;
}

/// ConvertArgumentsForCall - Converts the arguments specified in
/// Args/NumArgs to the parameter types of the function FDecl with
/// function prototype Proto. Call is the call expression itself, and
Expand All @@ -5834,8 +5855,10 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,

// C99 6.5.2.2p7 - the arguments are implicitly converted, as if by
// assignment, to the types of the corresponding parameter, ...

bool AddressOf = isParenthetizedAndQualifiedAddressOfExpr(Fn);
bool HasExplicitObjectParameter =
FDecl && FDecl->hasCXXExplicitFunctionObjectParameter();
!AddressOf && FDecl && FDecl->hasCXXExplicitFunctionObjectParameter();
unsigned ExplicitObjectParameterOffset = HasExplicitObjectParameter ? 1 : 0;
unsigned NumParams = Proto->getNumParams();
bool Invalid = false;
Expand Down Expand Up @@ -6546,7 +6569,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
OverloadExpr::FindResult find = OverloadExpr::find(Fn);

// We aren't supposed to apply this logic if there's an '&' involved.
if (!find.HasFormOfMemberPointer) {
if (!find.HasFormOfMemberPointer || find.IsAddressOfOperandWithParen) {
if (Expr::hasAnyTypeDependentArguments(ArgExprs))
return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy,
VK_PRValue, RParenLoc, CurFPFeatureOverrides());
Expand Down
228 changes: 228 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
Expand Down Expand Up @@ -295,6 +296,233 @@ void SemaHLSL::DiagnoseAttrStageMismatch(
<< (AllowedStages.size() != 1) << join(StageStrings, ", ");
}

void SemaHLSL::handleNumThreadsAttr(Decl *D, const ParsedAttr &AL) {
llvm::VersionTuple SMVersion =
getASTContext().getTargetInfo().getTriple().getOSVersion();
uint32_t ZMax = 1024;
uint32_t ThreadMax = 1024;
if (SMVersion.getMajor() <= 4) {
ZMax = 1;
ThreadMax = 768;
} else if (SMVersion.getMajor() == 5) {
ZMax = 64;
ThreadMax = 1024;
}

uint32_t X;
if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), X))
return;
if (X > 1024) {
Diag(AL.getArgAsExpr(0)->getExprLoc(),
diag::err_hlsl_numthreads_argument_oor)
<< 0 << 1024;
return;
}
uint32_t Y;
if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y))
return;
if (Y > 1024) {
Diag(AL.getArgAsExpr(1)->getExprLoc(),
diag::err_hlsl_numthreads_argument_oor)
<< 1 << 1024;
return;
}
uint32_t Z;
if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z))
return;
if (Z > ZMax) {
SemaRef.Diag(AL.getArgAsExpr(2)->getExprLoc(),
diag::err_hlsl_numthreads_argument_oor)
<< 2 << ZMax;
return;
}

if (X * Y * Z > ThreadMax) {
Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
return;
}

HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z);
if (NewAttr)
D->addAttr(NewAttr);
}

static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) {
if (!T->hasUnsignedIntegerRepresentation())
return false;
if (const auto *VT = T->getAs<VectorType>())
return VT->getNumElements() <= 3;
return true;
}

void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {
// FIXME: support semantic on field.
// See https://github.com/llvm/llvm-project/issues/57889.
if (isa<FieldDecl>(D)) {
Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
<< AL << "parameter";
return;
}

auto *VD = cast<ValueDecl>(D);
if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) {
Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
<< AL << "uint/uint2/uint3";
return;
}

D->addAttr(::new (getASTContext())
HLSLSV_DispatchThreadIDAttr(getASTContext(), AL));
}

void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) {
if (!isa<VarDecl>(D) || !isa<HLSLBufferDecl>(D->getDeclContext())) {
Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
<< AL << "shader constant in a constant buffer";
return;
}

uint32_t SubComponent;
if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent))
return;
uint32_t Component;
if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component))
return;

QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
// Check if T is an array or struct type.
// TODO: mark matrix type as aggregate type.
bool IsAggregateTy = (T->isArrayType() || T->isStructureType());

// Check Component is valid for T.
if (Component) {
unsigned Size = getASTContext().getTypeSize(T);
if (IsAggregateTy || Size > 128) {
Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
return;
} else {
// Make sure Component + sizeof(T) <= 4.
if ((Component * 32 + Size) > 128) {
Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
return;
}
QualType EltTy = T;
if (const auto *VT = T->getAs<VectorType>())
EltTy = VT->getElementType();
unsigned Align = getASTContext().getTypeAlign(EltTy);
if (Align > 32 && Component == 1) {
// NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
// So we only need to check Component 1 here.
Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
<< Align << EltTy;
return;
}
}
}

D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr(
getASTContext(), AL, SubComponent, Component));
}

void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation ArgLoc;
if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
return;

HLSLShaderAttr::ShaderType ShaderType;
if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType)) {
Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
<< AL << Str << ArgLoc;
return;
}

// FIXME: check function match the shader stage.

HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType);
if (NewAttr)
D->addAttr(NewAttr);
}

void SemaHLSL::handleResourceBindingAttr(Decl *D, const ParsedAttr &AL) {
StringRef Space = "space0";
StringRef Slot = "";

if (!AL.isArgIdent(0)) {
Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIdentifier;
return;
}

IdentifierLoc *Loc = AL.getArgAsIdent(0);
StringRef Str = Loc->Ident->getName();
SourceLocation ArgLoc = Loc->Loc;

SourceLocation SpaceArgLoc;
if (AL.getNumArgs() == 2) {
Slot = Str;
if (!AL.isArgIdent(1)) {
Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIdentifier;
return;
}

IdentifierLoc *Loc = AL.getArgAsIdent(1);
Space = Loc->Ident->getName();
SpaceArgLoc = Loc->Loc;
} else {
Slot = Str;
}

// Validate.
if (!Slot.empty()) {
switch (Slot[0]) {
case 'u':
case 'b':
case 's':
case 't':
break;
default:
Diag(ArgLoc, diag::err_hlsl_unsupported_register_type)
<< Slot.substr(0, 1);
return;
}

StringRef SlotNum = Slot.substr(1);
unsigned Num = 0;
if (SlotNum.getAsInteger(10, Num)) {
Diag(ArgLoc, diag::err_hlsl_unsupported_register_number);
return;
}
}

if (!Space.starts_with("space")) {
Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
return;
}
StringRef SpaceNum = Space.substr(5);
unsigned Num = 0;
if (SpaceNum.getAsInteger(10, Num)) {
Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
return;
}

// FIXME: check reg type match decl. Issue
// https://github.com/llvm/llvm-project/issues/57886.
HLSLResourceBindingAttr *NewAttr =
HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
if (NewAttr)
D->addAttr(NewAttr);
}

void SemaHLSL::handleParamModifierAttr(Decl *D, const ParsedAttr &AL) {
HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
D, AL,
static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
if (NewAttr)
D->addAttr(NewAttr);
}

namespace {

/// This class implements HLSL availability diagnostics for default
Expand Down
23 changes: 10 additions & 13 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,19 +814,13 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,

if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
const RecordDecl *RDecl = RType->getDecl();
if (RDecl->isUnion() && ILE->getInitializedFieldInUnion())
FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(),
Entity, ILE, RequiresSecondPass, FillWithNoInit);
else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) &&
cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) {
for (auto *Field : RDecl->fields()) {
if (Field->hasInClassInitializer()) {
FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass,
FillWithNoInit);
break;
}
}
if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) {
FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), Entity, ILE,
RequiresSecondPass, FillWithNoInit);
} else {
assert((!RDecl->isUnion() || !isa<CXXRecordDecl>(RDecl) ||
!cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) &&
"We should have computed initialized fields already");
// The fields beyond ILE->getNumInits() are default initialized, so in
// order to leave them uninitialized, the ILE is expanded and the extra
// fields are then filled with NoInitExpr.
Expand Down Expand Up @@ -2164,12 +2158,15 @@ void InitListChecker::CheckStructUnionTypes(
return;
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
if (Field->hasInClassInitializer()) {
if (Field->hasInClassInitializer() ||
(Field->isAnonymousStructOrUnion() &&
Field->getType()->getAsCXXRecordDecl()->hasInClassInitializer())) {
StructuredList->setInitializedFieldInUnion(*Field);
// FIXME: Actually build a CXXDefaultInitExpr?
return;
}
}
llvm_unreachable("Couldn't find in-class initializer");
}

// Value-initialize the first member of the union that isn't an unnamed
Expand Down
56 changes: 56 additions & 0 deletions clang/lib/Sema/SemaM68k.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===------ SemaM68k.cpp -------- M68k target-specific routines -----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis functions specific to M68k.
//
//===----------------------------------------------------------------------===//

#include "clang/Sema/SemaM68k.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Sema/ParsedAttr.h"

namespace clang {
SemaM68k::SemaM68k(Sema &S) : SemaBase(S) {}

void SemaM68k::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
if (!AL.checkExactlyNumArgs(SemaRef, 1))
return;

if (!AL.isArgExpr(0)) {
Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIntegerConstant;
return;
}

// FIXME: Check for decl - it should be void ()(void).

Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
auto MaybeNumParams = NumParamsExpr->getIntegerConstantExpr(getASTContext());
if (!MaybeNumParams) {
Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIntegerConstant
<< NumParamsExpr->getSourceRange();
return;
}

unsigned Num = MaybeNumParams->getLimitedValue(255);
if ((Num & 1) || Num > 30) {
Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< AL << (int)MaybeNumParams->getSExtValue()
<< NumParamsExpr->getSourceRange();
return;
}

D->addAttr(::new (getASTContext())
M68kInterruptAttr(getASTContext(), AL, Num));
D->addAttr(UsedAttr::CreateImplicit(getASTContext()));
}
} // namespace clang
60 changes: 60 additions & 0 deletions clang/lib/Sema/SemaMIPS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "clang/Sema/SemaMIPS.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Sema/Attr.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"

namespace clang {
Expand Down Expand Up @@ -237,4 +239,62 @@ bool SemaMIPS::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
SemaRef.BuiltinConstantArgMultiple(TheCall, i, m);
}

void SemaMIPS::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
// Only one optional argument permitted.
if (AL.getNumArgs() > 1) {
Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
return;
}

StringRef Str;
SourceLocation ArgLoc;

if (AL.getNumArgs() == 0)
Str = "";
else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
return;

// Semantic checks for a function with the 'interrupt' attribute for MIPS:
// a) Must be a function.
// b) Must have no parameters.
// c) Must have the 'void' return type.
// d) Cannot have the 'mips16' attribute, as that instruction set
// lacks the 'eret' instruction.
// e) The attribute itself must either have no argument or one of the
// valid interrupt types, see [MipsInterruptDocs].

if (!isFuncOrMethodForAttrSubject(D)) {
Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
<< AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod;
return;
}

if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
<< /*MIPS*/ 0 << 0;
return;
}

if (!getFunctionOrMethodResultType(D)->isVoidType()) {
Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
<< /*MIPS*/ 0 << 1;
return;
}

// We still have to do this manually because the Interrupt attributes are
// a bit special due to sharing their spellings across targets.
if (checkAttrMutualExclusion<Mips16Attr>(*this, D, AL))
return;

MipsInterruptAttr::InterruptType Kind;
if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
<< AL << "'" + std::string(Str) + "'";
return;
}

D->addAttr(::new (getASTContext())
MipsInterruptAttr(getASTContext(), AL, Kind));
}

} // namespace clang
78 changes: 78 additions & 0 deletions clang/lib/Sema/SemaMSP430.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//===------ SemaMSP430.cpp ----- MSP430 target-specific routines ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis functions specific to NVPTX.
//
//===----------------------------------------------------------------------===//

#include "clang/Sema/SemaMSP430.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Sema/Attr.h"
#include "clang/Sema/ParsedAttr.h"

namespace clang {

SemaMSP430::SemaMSP430(Sema &S) : SemaBase(S) {}

void SemaMSP430::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
// MSP430 'interrupt' attribute is applied to
// a function with no parameters and void return type.
if (!isFuncOrMethodForAttrSubject(D)) {
Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
<< AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod;
return;
}

if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
<< /*MSP430*/ 1 << 0;
return;
}

if (!getFunctionOrMethodResultType(D)->isVoidType()) {
Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
<< /*MSP430*/ 1 << 1;
return;
}

// The attribute takes one integer argument.
if (!AL.checkExactlyNumArgs(SemaRef, 1))
return;

if (!AL.isArgExpr(0)) {
Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIntegerConstant;
return;
}

Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
std::optional<llvm::APSInt> NumParams = llvm::APSInt(32);
if (!(NumParams = NumParamsExpr->getIntegerConstantExpr(getASTContext()))) {
Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIntegerConstant
<< NumParamsExpr->getSourceRange();
return;
}
// The argument should be in range 0..63.
unsigned Num = NumParams->getLimitedValue(255);
if (Num > 63) {
Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< AL << (int)NumParams->getSExtValue()
<< NumParamsExpr->getSourceRange();
return;
}

D->addAttr(::new (getASTContext())
MSP430InterruptAttr(getASTContext(), AL, Num));
D->addAttr(UsedAttr::CreateImplicit(getASTContext()));
}

} // namespace clang
772 changes: 772 additions & 0 deletions clang/lib/Sema/SemaObjC.cpp

Large diffs are not rendered by default.

141 changes: 114 additions & 27 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K,
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
case OpenACCDirectiveKind::Loop:
if (!IsStmt)
return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K;
break;
Expand Down Expand Up @@ -340,36 +341,93 @@ bool checkAlreadyHasClauseOfKind(
return false;
}

/// Implement check from OpenACC3.3: section 2.5.4:
/// Only the async, wait, num_gangs, num_workers, and vector_length clauses may
/// follow a device_type clause.
bool checkValidAfterDeviceType(
SemaOpenACC &S, const OpenACCDeviceTypeClause &DeviceTypeClause,
const SemaOpenACC::OpenACCParsedClause &NewClause) {
// This is only a requirement on compute constructs so far, so this is fine
// otherwise.
if (!isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind()))
// This is only a requirement on compute and loop constructs so far, so this
// is fine otherwise.
if (!isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind()) &&
NewClause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
return false;
switch (NewClause.getClauseKind()) {
case OpenACCClauseKind::Async:
case OpenACCClauseKind::Wait:
case OpenACCClauseKind::NumGangs:
case OpenACCClauseKind::NumWorkers:
case OpenACCClauseKind::VectorLength:
case OpenACCClauseKind::DType:
case OpenACCClauseKind::DeviceType:

// OpenACC3.3: Section 2.4: Clauses that precede any device_type clause are
// default clauses. Clauses that follow a device_type clause up to the end of
// the directive or up to the next device_type clause are device-specific
// clauses for the device types specified in the device_type argument.
//
// The above implies that despite what the individual text says, these are
// valid.
if (NewClause.getClauseKind() == OpenACCClauseKind::DType ||
NewClause.getClauseKind() == OpenACCClauseKind::DeviceType)
return false;
default:
S.Diag(NewClause.getBeginLoc(), diag::err_acc_clause_after_device_type)
<< NewClause.getClauseKind() << DeviceTypeClause.getClauseKind();
S.Diag(DeviceTypeClause.getBeginLoc(), diag::note_acc_previous_clause_here);
return true;

// Implement check from OpenACC3.3: section 2.5.4:
// Only the async, wait, num_gangs, num_workers, and vector_length clauses may
// follow a device_type clause.
if (isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind())) {
switch (NewClause.getClauseKind()) {
case OpenACCClauseKind::Async:
case OpenACCClauseKind::Wait:
case OpenACCClauseKind::NumGangs:
case OpenACCClauseKind::NumWorkers:
case OpenACCClauseKind::VectorLength:
return false;
default:
break;
}
} else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Loop) {
// Implement check from OpenACC3.3: section 2.9:
// Only the collapse, gang, worker, vector, seq, independent, auto, and tile
// clauses may follow a device_type clause.
switch (NewClause.getClauseKind()) {
case OpenACCClauseKind::Collapse:
case OpenACCClauseKind::Gang:
case OpenACCClauseKind::Worker:
case OpenACCClauseKind::Vector:
case OpenACCClauseKind::Seq:
case OpenACCClauseKind::Independent:
case OpenACCClauseKind::Auto:
case OpenACCClauseKind::Tile:
return false;
default:
break;
}
}
S.Diag(NewClause.getBeginLoc(), diag::err_acc_clause_after_device_type)
<< NewClause.getClauseKind() << DeviceTypeClause.getClauseKind()
<< isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind())
<< NewClause.getDirectiveKind();
S.Diag(DeviceTypeClause.getBeginLoc(), diag::note_acc_previous_clause_here);
return true;
}
} // namespace

SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {}

SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(SemaOpenACC &S,
OpenACCDirectiveKind DK)
: SemaRef(S), WasInsideComputeConstruct(S.InsideComputeConstruct),
DirKind(DK) {
// Compute constructs end up taking their 'loop'.
if (DirKind == OpenACCDirectiveKind::Parallel ||
DirKind == OpenACCDirectiveKind::Serial ||
DirKind == OpenACCDirectiveKind::Kernels) {
SemaRef.InsideComputeConstruct = true;
SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
}
}

SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
SemaRef.InsideComputeConstruct = WasInsideComputeConstruct;
if (DirKind == OpenACCDirectiveKind::Parallel ||
DirKind == OpenACCDirectiveKind::Serial ||
DirKind == OpenACCDirectiveKind::Kernels) {
assert(SemaRef.ParentlessLoopConstructs.empty() &&
"Didn't consume loop construct list?");
SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
}
}

OpenACCClause *
SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
OpenACCParsedClause &Clause) {
Expand Down Expand Up @@ -791,10 +849,12 @@ SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
}
case OpenACCClauseKind::DType:
case OpenACCClauseKind::DeviceType: {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
// Restrictions only properly implemented on 'compute' and 'loop'
// constructs, and 'compute'/'loop' constructs are the only construct that
// can do anything with this yet, so skip/treat as unimplemented in this
// case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
break;

// TODO OpenACC: Once we get enough of the CodeGen implemented that we have
Expand Down Expand Up @@ -927,6 +987,7 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
case OpenACCDirectiveKind::Loop:
// Nothing to do here, there is no real legalization that needs to happen
// here as these constructs do not take any arguments.
break;
Expand Down Expand Up @@ -1348,16 +1409,34 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K,
return StmtError();
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
// TODO OpenACC: Add clauses to the construct here.
return OpenACCComputeConstruct::Create(
case OpenACCDirectiveKind::Kernels: {
auto *ComputeConstruct = OpenACCComputeConstruct::Create(
getASTContext(), K, StartLoc, DirLoc, EndLoc, Clauses,
AssocStmt.isUsable() ? AssocStmt.get() : nullptr,
ParentlessLoopConstructs);

ParentlessLoopConstructs.clear();
return ComputeConstruct;
}
case OpenACCDirectiveKind::Loop: {
auto *LoopConstruct = OpenACCLoopConstruct::Create(
getASTContext(), StartLoc, DirLoc, EndLoc, Clauses,
AssocStmt.isUsable() ? AssocStmt.get() : nullptr);

// If we are in the scope of a compute construct, add this to the list of
// loop constructs that need assigning to the next closing compute
// construct.
if (InsideComputeConstruct)
ParentlessLoopConstructs.push_back(LoopConstruct);

return LoopConstruct;
}
}
llvm_unreachable("Unhandled case in directive handling?");
}

StmtResult SemaOpenACC::ActOnAssociatedStmt(OpenACCDirectiveKind K,
StmtResult SemaOpenACC::ActOnAssociatedStmt(SourceLocation DirectiveLoc,
OpenACCDirectiveKind K,
StmtResult AssocStmt) {
switch (K) {
default:
Expand All @@ -1375,6 +1454,14 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt(OpenACCDirectiveKind K,
// an interpretation of it is to allow this and treat the initializer as
// the 'structured block'.
return AssocStmt;
case OpenACCDirectiveKind::Loop:
if (AssocStmt.isUsable() &&
!isa<CXXForRangeStmt, ForStmt>(AssocStmt.get())) {
Diag(AssocStmt.get()->getBeginLoc(), diag::err_acc_loop_not_for_loop);
Diag(DirectiveLoc, diag::note_acc_construct_here) << K;
return StmtError();
}
return AssocStmt;
}
llvm_unreachable("Invalid associated statement application");
}
Expand Down
99 changes: 99 additions & 0 deletions clang/lib/Sema/SemaOpenCL.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//===--- SemaOpenCL.cpp --- Semantic Analysis for OpenCL constructs -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements semantic analysis for OpenCL.
///
//===----------------------------------------------------------------------===//

#include "clang/Sema/SemaOpenCL.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"

namespace clang {
SemaOpenCL::SemaOpenCL(Sema &S) : SemaBase(S) {}

void SemaOpenCL::handleNoSVMAttr(Decl *D, const ParsedAttr &AL) {
if (getLangOpts().getOpenCLCompatibleVersion() < 200)
Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version)
<< AL << "2.0" << 1;
else
Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored)
<< AL << getLangOpts().getOpenCLVersionString();
}

void SemaOpenCL::handleAccessAttr(Decl *D, const ParsedAttr &AL) {
if (D->isInvalidDecl())
return;

// Check if there is only one access qualifier.
if (D->hasAttr<OpenCLAccessAttr>()) {
if (D->getAttr<OpenCLAccessAttr>()->getSemanticSpelling() ==
AL.getSemanticSpelling()) {
Diag(AL.getLoc(), diag::warn_duplicate_declspec)
<< AL.getAttrName()->getName() << AL.getRange();
} else {
Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers)
<< D->getSourceRange();
D->setInvalidDecl(true);
return;
}
}

// OpenCL v2.0 s6.6 - read_write can be used for image types to specify that
// an image object can be read and written. OpenCL v2.0 s6.13.6 - A kernel
// cannot read from and write to the same pipe object. Using the read_write
// (or __read_write) qualifier with the pipe qualifier is a compilation error.
// OpenCL v3.0 s6.8 - For OpenCL C 2.0, or with the
// __opencl_c_read_write_images feature, image objects specified as arguments
// to a kernel can additionally be declared to be read-write.
// C++ for OpenCL 1.0 inherits rule from OpenCL C v2.0.
// C++ for OpenCL 2021 inherits rule from OpenCL C v3.0.
if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) {
const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr();
if (AL.getAttrName()->getName().contains("read_write")) {
bool ReadWriteImagesUnsupported =
(getLangOpts().getOpenCLCompatibleVersion() < 200) ||
(getLangOpts().getOpenCLCompatibleVersion() == 300 &&
!SemaRef.getOpenCLOptions().isSupported(
"__opencl_c_read_write_images", getLangOpts()));
if (ReadWriteImagesUnsupported || DeclTy->isPipeType()) {
Diag(AL.getLoc(), diag::err_opencl_invalid_read_write)
<< AL << PDecl->getType() << DeclTy->isImageType();
D->setInvalidDecl(true);
return;
}
}
}

D->addAttr(::new (getASTContext()) OpenCLAccessAttr(getASTContext(), AL));
}

void SemaOpenCL::handleSubGroupSize(Decl *D, const ParsedAttr &AL) {
uint32_t SGSize;
const Expr *E = AL.getArgAsExpr(0);
if (!SemaRef.checkUInt32Argument(AL, E, SGSize))
return;
if (SGSize == 0) {
Diag(AL.getLoc(), diag::err_attribute_argument_is_zero)
<< AL << E->getSourceRange();
return;
}

OpenCLIntelReqdSubGroupSizeAttr *Existing =
D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>();
if (Existing && Existing->getSubGroupSize() != SGSize)
Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;

D->addAttr(::new (getASTContext())
OpenCLIntelReqdSubGroupSizeAttr(getASTContext(), AL, SGSize));
}

} // namespace clang
38 changes: 38 additions & 0 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Frontend/OpenMP/OMPAssume.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
#include "llvm/IR/Assumptions.h"
#include <optional>
#include <set>

Expand Down Expand Up @@ -25372,5 +25373,42 @@ ExprResult SemaOpenMP::ActOnOMPIteratorExpr(Scope *S,
LLoc, RLoc, ID, Helpers);
}

/// Check if \p AssumptionStr is a known assumption and warn if not.
static void checkOMPAssumeAttr(Sema &S, SourceLocation Loc,
StringRef AssumptionStr) {
if (llvm::KnownAssumptionStrings.count(AssumptionStr))
return;

unsigned BestEditDistance = 3;
StringRef Suggestion;
for (const auto &KnownAssumptionIt : llvm::KnownAssumptionStrings) {
unsigned EditDistance =
AssumptionStr.edit_distance(KnownAssumptionIt.getKey());
if (EditDistance < BestEditDistance) {
Suggestion = KnownAssumptionIt.getKey();
BestEditDistance = EditDistance;
}
}

if (!Suggestion.empty())
S.Diag(Loc, diag::warn_omp_assume_attribute_string_unknown_suggested)
<< AssumptionStr << Suggestion;
else
S.Diag(Loc, diag::warn_omp_assume_attribute_string_unknown)
<< AssumptionStr;
}

void SemaOpenMP::handleOMPAssumeAttr(Decl *D, const ParsedAttr &AL) {
// Handle the case where the attribute has a text message.
StringRef Str;
SourceLocation AttrStrLoc;
if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &AttrStrLoc))
return;

checkOMPAssumeAttr(SemaRef, AttrStrLoc, Str);

D->addAttr(::new (getASTContext()) OMPAssumeAttr(getASTContext(), AL, Str));
}

SemaOpenMP::SemaOpenMP(Sema &S)
: SemaBase(S), VarDataSharingAttributesStack(nullptr) {}
110 changes: 91 additions & 19 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6972,6 +6972,7 @@ void Sema::AddOverloadCandidate(
Candidate.IsSurrogate = false;
Candidate.IsADLCandidate = IsADLCandidate;
Candidate.IgnoreObjectArgument = false;
Candidate.TookAddressOfOverload = false;
Candidate.ExplicitCallArguments = Args.size();

// Explicit functions are not actually candidates at all if we're not
Expand Down Expand Up @@ -7546,10 +7547,24 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CandidateSet.getRewriteInfo().getRewriteKind(Method, PO);
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.TookAddressOfOverload =
CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
Candidate.ExplicitCallArguments = Args.size();

unsigned NumParams = Method->getNumExplicitParams();
unsigned ExplicitOffset = Method->isExplicitObjectMemberFunction() ? 1 : 0;
bool IgnoreExplicitObject =
(Method->isExplicitObjectMemberFunction() &&
CandidateSet.getKind() ==
OverloadCandidateSet::CSK_AddressOfOverloadSet);
bool ImplicitObjectMethodTreatedAsStatic =
CandidateSet.getKind() ==
OverloadCandidateSet::CSK_AddressOfOverloadSet &&
Method->isImplicitObjectMemberFunction();

unsigned ExplicitOffset =
!IgnoreExplicitObject && Method->isExplicitObjectMemberFunction() ? 1 : 0;

unsigned NumParams = Method->getNumParams() - ExplicitOffset +
int(ImplicitObjectMethodTreatedAsStatic);

// (C++ 13.3.2p2): A candidate function having fewer than m
// parameters is viable only if it has an ellipsis in its parameter
Expand All @@ -7567,7 +7582,10 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// (8.3.6). For the purposes of overload resolution, the
// parameter list is truncated on the right, so that there are
// exactly m parameters.
unsigned MinRequiredArgs = Method->getMinRequiredExplicitArguments();
unsigned MinRequiredArgs = Method->getMinRequiredArguments() -
ExplicitOffset +
int(ImplicitObjectMethodTreatedAsStatic);

if (Args.size() < MinRequiredArgs && !PartialOverloading) {
// Not enough arguments.
Candidate.Viable = false;
Expand Down Expand Up @@ -7637,7 +7655,14 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// exist for each argument an implicit conversion sequence
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
QualType ParamType = Proto->getParamType(ArgIdx + ExplicitOffset);
QualType ParamType;
if (ImplicitObjectMethodTreatedAsStatic) {
ParamType = ArgIdx == 0
? Method->getFunctionObjectParameterReferenceType()
: Proto->getParamType(ArgIdx - 1);
} else {
ParamType = Proto->getParamType(ArgIdx + ExplicitOffset);
}
Candidate.Conversions[ConvIdx]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
SuppressUserConversions,
Expand Down Expand Up @@ -7718,6 +7743,7 @@ void Sema::AddMethodTemplateCandidate(
Candidate.IgnoreObjectArgument =
cast<CXXMethodDecl>(Candidate.Function)->isStatic() ||
ObjectType.isNull();
Candidate.TookAddressOfOverload = false;
Candidate.ExplicitCallArguments = Args.size();
if (Result == TemplateDeductionResult::NonDependentConversionFailure)
Candidate.FailureKind = ovl_fail_bad_conversion;
Expand Down Expand Up @@ -7808,6 +7834,7 @@ void Sema::AddTemplateOverloadCandidate(
Candidate.IgnoreObjectArgument =
isa<CXXMethodDecl>(Candidate.Function) &&
!isa<CXXConstructorDecl>(Candidate.Function);
Candidate.TookAddressOfOverload = false;
Candidate.ExplicitCallArguments = Args.size();
if (Result == TemplateDeductionResult::NonDependentConversionFailure)
Candidate.FailureKind = ovl_fail_bad_conversion;
Expand Down Expand Up @@ -7999,6 +8026,7 @@ void Sema::AddConversionCandidate(
Candidate.Function = Conversion;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.TookAddressOfOverload = false;
Candidate.FinalConversion.setAsIdentityConversion();
Candidate.FinalConversion.setFromType(ConvType);
Candidate.FinalConversion.setAllToTypes(ToType);
Expand Down Expand Up @@ -8201,6 +8229,7 @@ void Sema::AddTemplateConversionCandidate(
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.TookAddressOfOverload = false;
Candidate.ExplicitCallArguments = 1;
Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
Info);
Expand Down Expand Up @@ -8241,6 +8270,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Candidate.Viable = true;
Candidate.IsSurrogate = true;
Candidate.IgnoreObjectArgument = false;
Candidate.TookAddressOfOverload = false;
Candidate.ExplicitCallArguments = Args.size();

// Determine the implicit conversion sequence for the implicit
Expand Down Expand Up @@ -8466,6 +8496,7 @@ void Sema::AddBuiltinCandidate(QualType *ParamTys, ArrayRef<Expr *> Args,
Candidate.Function = nullptr;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.TookAddressOfOverload = false;
std::copy(ParamTys, ParamTys + Args.size(), Candidate.BuiltinParamTypes);

// Determine the implicit conversion sequences for each of the
Expand Down Expand Up @@ -10930,6 +10961,12 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
if (Best->Function && Best->Function->isDeleted())
return OR_Deleted;

if (auto *M = dyn_cast_or_null<CXXMethodDecl>(Best->Function);
Kind == CSK_AddressOfOverloadSet && M &&
M->isImplicitObjectMemberFunction()) {
return OR_No_Viable_Function;
}

if (!EquivalentCands.empty())
S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function,
EquivalentCands);
Expand Down Expand Up @@ -11517,9 +11554,10 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
/// candidates. This is not covered by the more general DiagnoseArityMismatch()
/// over a candidate in any candidate set.
static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned NumArgs) {
unsigned NumArgs, bool IsAddressOf = false) {
FunctionDecl *Fn = Cand->Function;
unsigned MinParams = Fn->getMinRequiredArguments();
unsigned MinParams = Fn->getMinRequiredExplicitArguments() +
((IsAddressOf && !Fn->isStatic()) ? 1 : 0);

// With invalid overloaded operators, it's possible that we think we
// have an arity mismatch when in fact it looks like we have the
Expand Down Expand Up @@ -11547,7 +11585,8 @@ static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,

/// General arity mismatch diagnosis over a candidate in a candidate set.
static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
unsigned NumFormalArgs) {
unsigned NumFormalArgs,
bool IsAddressOf = false) {
assert(isa<FunctionDecl>(D) &&
"The templated declaration should at least be a function"
" when diagnosing bad template argument deduction due to too many"
Expand All @@ -11557,12 +11596,17 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,

// TODO: treat calls to a missing default constructor as a special case
const auto *FnTy = Fn->getType()->castAs<FunctionProtoType>();
unsigned MinParams = Fn->getMinRequiredExplicitArguments();
unsigned MinParams = Fn->getMinRequiredExplicitArguments() +
((IsAddressOf && !Fn->isStatic()) ? 1 : 0);

// at least / at most / exactly
bool HasExplicitObjectParam = Fn->hasCXXExplicitFunctionObjectParameter();
unsigned ParamCount = FnTy->getNumParams() - (HasExplicitObjectParam ? 1 : 0);
bool HasExplicitObjectParam =
!IsAddressOf && Fn->hasCXXExplicitFunctionObjectParameter();

unsigned ParamCount =
Fn->getNumNonObjectParams() + ((IsAddressOf && !Fn->isStatic()) ? 1 : 0);
unsigned mode, modeCount;

if (NumFormalArgs < MinParams) {
if (MinParams != ParamCount || FnTy->isVariadic() ||
FnTy->isTemplateVariadic())
Expand All @@ -11582,7 +11626,7 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
ClassifyOverloadCandidate(S, Found, Fn, CRK_None, Description);

if (modeCount == 1 &&
if (modeCount == 1 && !IsAddressOf &&
Fn->getParamDecl(HasExplicitObjectParam ? 1 : 0)->getDeclName())
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
Expand All @@ -11601,8 +11645,9 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
/// Arity mismatch diagnosis specific to a function overload candidate.
static void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned NumFormalArgs) {
if (!CheckArityMismatch(S, Cand, NumFormalArgs))
DiagnoseArityMismatch(S, Cand->FoundDecl, Cand->Function, NumFormalArgs);
if (!CheckArityMismatch(S, Cand, NumFormalArgs, Cand->TookAddressOfOverload))
DiagnoseArityMismatch(S, Cand->FoundDecl, Cand->Function, NumFormalArgs,
Cand->TookAddressOfOverload);
}

static TemplateDecl *getDescribedTemplate(Decl *Templated) {
Expand Down Expand Up @@ -12042,6 +12087,13 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
Cand->FailureKind != ovl_fail_bad_conversion)
return;

// Skip implicit member functions when trying to resolve
// the address of a an overload set for a function pointer.
if (Cand->TookAddressOfOverload &&
!Cand->Function->hasCXXExplicitFunctionObjectParameter() &&
!Cand->Function->isStatic())
return;

// Note deleted candidates, but only if they're viable.
if (Cand->Viable) {
if (Fn->isDeleted()) {
Expand Down Expand Up @@ -14085,6 +14137,21 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
}

case OR_No_Viable_Function: {
if (*Best != CandidateSet->end() &&
CandidateSet->getKind() ==
clang::OverloadCandidateSet::CSK_AddressOfOverloadSet) {
if (CXXMethodDecl *M =
dyn_cast_if_present<CXXMethodDecl>((*Best)->Function);
M && M->isImplicitObjectMemberFunction()) {
CandidateSet->NoteCandidates(
PartialDiagnosticAt(
Fn->getBeginLoc(),
SemaRef.PDiag(diag::err_member_call_without_object) << 0 << M),
SemaRef, OCD_AmbiguousCandidates, Args);
return ExprError();
}
}

// Try to recover by looking for viable functions which the user might
// have meant to call.
ExprResult Recovery = BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc,
Expand Down Expand Up @@ -14176,8 +14243,10 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
Expr *ExecConfig,
bool AllowTypoCorrection,
bool CalleesAddressIsTaken) {
OverloadCandidateSet CandidateSet(Fn->getExprLoc(),
OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet CandidateSet(
Fn->getExprLoc(), CalleesAddressIsTaken
? OverloadCandidateSet::CSK_AddressOfOverloadSet
: OverloadCandidateSet::CSK_Normal);
ExprResult result;

if (buildOverloadedCallSet(S, Fn, ULE, Args, LParenLoc, &CandidateSet,
Expand Down Expand Up @@ -16342,9 +16411,9 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
assert(UnOp->getOpcode() == UO_AddrOf &&
"Can only take the address of an overloaded function");
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
if (Method->isStatic()) {
// Do nothing: static member functions aren't any different
// from non-member functions.
if (!Method->isImplicitObjectMemberFunction()) {
// Do nothing: the address of static and
// explicit object member functions is a (non-member) function pointer.
} else {
// Fix the subexpression, which really has to be an
// UnresolvedLookupExpr holding an overloaded member function
Expand Down Expand Up @@ -16402,7 +16471,10 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
}

QualType Type = Fn->getType();
ExprValueKind ValueKind = getLangOpts().CPlusPlus ? VK_LValue : VK_PRValue;
ExprValueKind ValueKind =
getLangOpts().CPlusPlus && !Fn->hasCXXExplicitFunctionObjectParameter()
? VK_LValue
: VK_PRValue;

// FIXME: Duplicated from BuildDeclarationNameExpr.
if (unsigned BID = Fn->getBuiltinID()) {
Expand Down
65 changes: 65 additions & 0 deletions clang/lib/Sema/SemaRISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Attr.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/RISCVIntrinsicManager.h"
#include "clang/Sema/Sema.h"
#include "clang/Support/RISCVVIntrinsicUtils.h"
Expand Down Expand Up @@ -1422,6 +1424,69 @@ bool SemaRISCV::isValidRVVBitcast(QualType srcTy, QualType destTy) {
ValidScalableConversion(destTy, srcTy);
}

void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
// Warn about repeated attributes.
if (const auto *A = D->getAttr<RISCVInterruptAttr>()) {
Diag(AL.getRange().getBegin(),
diag::warn_riscv_repeated_interrupt_attribute);
Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute);
return;
}

// Check the attribute argument. Argument is optional.
if (!AL.checkAtMostNumArgs(SemaRef, 1))
return;

StringRef Str;
SourceLocation ArgLoc;

// 'machine'is the default interrupt mode.
if (AL.getNumArgs() == 0)
Str = "machine";
else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
return;

// Semantic checks for a function with the 'interrupt' attribute:
// - Must be a function.
// - Must have no parameters.
// - Must have the 'void' return type.
// - The attribute itself must either have no argument or one of the
// valid interrupt types, see [RISCVInterruptDocs].

if (D->getFunctionType() == nullptr) {
Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
<< AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
return;
}

if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
<< /*RISC-V*/ 2 << 0;
return;
}

if (!getFunctionOrMethodResultType(D)->isVoidType()) {
Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
<< /*RISC-V*/ 2 << 1;
return;
}

RISCVInterruptAttr::InterruptType Kind;
if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
<< AL << Str << ArgLoc;
return;
}

D->addAttr(::new (getASTContext())
RISCVInterruptAttr(getASTContext(), AL, Kind));
}

bool SemaRISCV::isAliasValid(unsigned BuiltinID, StringRef AliasName) {
return BuiltinID >= RISCV::FirstRVVBuiltin &&
BuiltinID <= RISCV::LastRVVBuiltin;
}

SemaRISCV::SemaRISCV(Sema &S) : SemaBase(S) {}

} // namespace clang
41 changes: 41 additions & 0 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include "clang/Sema/SemaSYCL.h"
#include "clang/AST/Mangle.h"
#include "clang/Sema/Attr.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"

Expand Down Expand Up @@ -156,3 +158,42 @@ ExprResult SemaSYCL::ActOnUniqueStableNameExpr(SourceLocation OpLoc,

return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI);
}

void SemaSYCL::handleKernelAttr(Decl *D, const ParsedAttr &AL) {
// The 'sycl_kernel' attribute applies only to function templates.
const auto *FD = cast<FunctionDecl>(D);
const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate();
assert(FT && "Function template is expected");

// Function template must have at least two template parameters.
const TemplateParameterList *TL = FT->getTemplateParameters();
if (TL->size() < 2) {
Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params);
return;
}

// Template parameters must be typenames.
for (unsigned I = 0; I < 2; ++I) {
const NamedDecl *TParam = TL->getParam(I);
if (isa<NonTypeTemplateParmDecl>(TParam)) {
Diag(FT->getLocation(),
diag::warn_sycl_kernel_invalid_template_param_type);
return;
}
}

// Function must have at least one argument.
if (getFunctionOrMethodNumParams(D) != 1) {
Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params);
return;
}

// Function must return void.
QualType RetTy = getFunctionOrMethodResultType(D);
if (!RetTy->isVoidType()) {
Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type);
return;
}

handleSimpleAttribute<SYCLKernelAttr>(*this, D, AL);
}
765 changes: 765 additions & 0 deletions clang/lib/Sema/SemaSwift.cpp

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaSwift.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/Support/TimeProfiler.h"
Expand Down Expand Up @@ -840,14 +841,15 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}

if (const auto *ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) {
AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI());
Swift().AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI());
continue;
}

if (isa<NSConsumedAttr>(TmplAttr) || isa<OSConsumedAttr>(TmplAttr) ||
isa<CFConsumedAttr>(TmplAttr)) {
AddXConsumedAttr(New, *TmplAttr, attrToRetainOwnershipKind(TmplAttr),
/*template instantiation=*/true);
ObjC().AddXConsumedAttr(New, *TmplAttr,
attrToRetainOwnershipKind(TmplAttr),
/*template instantiation=*/true);
continue;
}

Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2704,7 +2704,7 @@ QualType Sema::BuildFunctionType(QualType T,

if (EPI.ExtInfo.getProducesResult()) {
// This is just a warning, so we can't fail to build if we see it.
checkNSReturnsRetainedReturnType(Loc, T);
ObjC().checkNSReturnsRetainedReturnType(Loc, T);
}

if (Invalid)
Expand Down Expand Up @@ -7639,8 +7639,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
return false;

// Check whether the return type is reasonable.
if (S.checkNSReturnsRetainedReturnType(attr.getLoc(),
unwrapped.get()->getReturnType()))
if (S.ObjC().checkNSReturnsRetainedReturnType(
attr.getLoc(), unwrapped.get()->getReturnType()))
return true;

// Only actually change the underlying type in ARC builds.
Expand Down
94 changes: 94 additions & 0 deletions clang/lib/Sema/SemaX86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "clang/Sema/SemaX86.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Sema/Attr.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/TargetParser/Triple.h"
Expand Down Expand Up @@ -875,4 +877,96 @@ bool SemaX86::CheckBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
/*RangeIsError*/ false);
}

void SemaX86::handleAnyInterruptAttr(Decl *D, const ParsedAttr &AL) {
// Semantic checks for a function with the 'interrupt' attribute.
// a) Must be a function.
// b) Must have the 'void' return type.
// c) Must take 1 or 2 arguments.
// d) The 1st argument must be a pointer.
// e) The 2nd argument (if any) must be an unsigned integer.
ASTContext &Context = getASTContext();

if (!isFuncOrMethodForAttrSubject(D) || !hasFunctionProto(D) ||
isInstanceMethod(D) ||
CXXMethodDecl::isStaticOverloadedOperator(
cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) {
Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
<< AL << AL.isRegularKeywordAttribute()
<< ExpectedFunctionWithProtoType;
return;
}
// Interrupt handler must have void return type.
if (!getFunctionOrMethodResultType(D)->isVoidType()) {
Diag(getFunctionOrMethodResultSourceRange(D).getBegin(),
diag::err_anyx86_interrupt_attribute)
<< (SemaRef.Context.getTargetInfo().getTriple().getArch() ==
llvm::Triple::x86
? 0
: 1)
<< 0;
return;
}
// Interrupt handler must have 1 or 2 parameters.
unsigned NumParams = getFunctionOrMethodNumParams(D);
if (NumParams < 1 || NumParams > 2) {
Diag(D->getBeginLoc(), diag::err_anyx86_interrupt_attribute)
<< (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
? 0
: 1)
<< 1;
return;
}
// The first argument must be a pointer.
if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) {
Diag(getFunctionOrMethodParamRange(D, 0).getBegin(),
diag::err_anyx86_interrupt_attribute)
<< (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
? 0
: 1)
<< 2;
return;
}
// The second argument, if present, must be an unsigned integer.
unsigned TypeSize =
Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64
? 64
: 32;
if (NumParams == 2 &&
(!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() ||
Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) {
Diag(getFunctionOrMethodParamRange(D, 1).getBegin(),
diag::err_anyx86_interrupt_attribute)
<< (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
? 0
: 1)
<< 3 << Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false);
return;
}
D->addAttr(::new (Context) AnyX86InterruptAttr(Context, AL));
D->addAttr(UsedAttr::CreateImplicit(Context));
}

void SemaX86::handleForceAlignArgPointerAttr(Decl *D, const ParsedAttr &AL) {
// If we try to apply it to a function pointer, don't warn, but don't
// do anything, either. It doesn't matter anyway, because there's nothing
// special about calling a force_align_arg_pointer function.
const auto *VD = dyn_cast<ValueDecl>(D);
if (VD && VD->getType()->isFunctionPointerType())
return;
// Also don't warn on function pointer typedefs.
const auto *TD = dyn_cast<TypedefNameDecl>(D);
if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
TD->getUnderlyingType()->isFunctionType()))
return;
// Attribute can only be applied to function types.
if (!isa<FunctionDecl>(D)) {
Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
<< AL << AL.isRegularKeywordAttribute() << ExpectedFunction;
return;
}

D->addAttr(::new (getASTContext())
X86ForceAlignArgPointerAttr(getASTContext(), AL));
}

} // namespace clang
44 changes: 39 additions & 5 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -4041,6 +4041,15 @@ class TreeTransform {
EndLoc, Clauses, StrBlock);
}

StmtResult RebuildOpenACCLoopConstruct(SourceLocation BeginLoc,
SourceLocation DirLoc,
SourceLocation EndLoc,
ArrayRef<OpenACCClause *> Clauses,
StmtResult Loop) {
return getSema().OpenACC().ActOnEndStmtDirective(
OpenACCDirectiveKind::Loop, BeginLoc, DirLoc, EndLoc, Clauses, Loop);
}

private:
TypeLoc TransformTypeInObjectScope(TypeLoc TL,
QualType ObjectType,
Expand Down Expand Up @@ -11541,8 +11550,6 @@ template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOpenACCComputeConstruct(
OpenACCComputeConstruct *C) {
getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc());
// FIXME: When implementing this for constructs that can take arguments, we
// should do Sema for them here.

if (getSema().OpenACC().ActOnStartStmtDirective(C->getDirectiveKind(),
C->getBeginLoc()))
Expand All @@ -11551,17 +11558,44 @@ StmtResult TreeTransform<Derived>::TransformOpenACCComputeConstruct(
llvm::SmallVector<OpenACCClause *> TransformedClauses =
getDerived().TransformOpenACCClauseList(C->getDirectiveKind(),
C->clauses());

// Transform Structured Block.
SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getSema().OpenACC(),
C->getDirectiveKind());
StmtResult StrBlock = getDerived().TransformStmt(C->getStructuredBlock());
StrBlock =
getSema().OpenACC().ActOnAssociatedStmt(C->getDirectiveKind(), StrBlock);
StrBlock = getSema().OpenACC().ActOnAssociatedStmt(
C->getBeginLoc(), C->getDirectiveKind(), StrBlock);

return getDerived().RebuildOpenACCComputeConstruct(
C->getDirectiveKind(), C->getBeginLoc(), C->getDirectiveLoc(),
C->getEndLoc(), TransformedClauses, StrBlock);
}

template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOpenACCLoopConstruct(OpenACCLoopConstruct *C) {

getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc());

if (getSema().OpenACC().ActOnStartStmtDirective(C->getDirectiveKind(),
C->getBeginLoc()))
return StmtError();

llvm::SmallVector<OpenACCClause *> TransformedClauses =
getDerived().TransformOpenACCClauseList(C->getDirectiveKind(),
C->clauses());

// Transform Loop.
SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getSema().OpenACC(),
C->getDirectiveKind());
StmtResult Loop = getDerived().TransformStmt(C->getLoop());
Loop = getSema().OpenACC().ActOnAssociatedStmt(C->getBeginLoc(),
C->getDirectiveKind(), Loop);

return getDerived().RebuildOpenACCLoopConstruct(
C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(),
TransformedClauses, Loop);
}

//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2810,6 +2810,12 @@ void ASTStmtReader::VisitOpenACCAssociatedStmtConstruct(
void ASTStmtReader::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) {
VisitStmt(S);
VisitOpenACCAssociatedStmtConstruct(S);
S->findAndSetChildLoops();
}

void ASTStmtReader::VisitOpenACCLoopConstruct(OpenACCLoopConstruct *S) {
VisitStmt(S);
VisitOpenACCAssociatedStmtConstruct(S);
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -4235,6 +4241,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = OpenACCComputeConstruct::CreateEmpty(Context, NumClauses);
break;
}
case STMT_OPENACC_LOOP_CONSTRUCT: {
unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
S = OpenACCLoopConstruct::CreateEmpty(Context, NumClauses);
break;
}
case EXPR_REQUIRES:
unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields];
unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1];
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Serialization/ASTWriterStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2863,6 +2863,12 @@ void ASTStmtWriter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) {
Code = serialization::STMT_OPENACC_COMPUTE_CONSTRUCT;
}

void ASTStmtWriter::VisitOpenACCLoopConstruct(OpenACCLoopConstruct *S) {
VisitStmt(S);
VisitOpenACCAssociatedStmtConstruct(S);
Code = serialization::STMT_OPENACC_LOOP_CONSTRUCT;
}

//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
Expand Down
98 changes: 85 additions & 13 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Lexer.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Checkers/Taint.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
Expand Down Expand Up @@ -322,6 +323,7 @@ class MallocChecker
CK_NewDeleteLeaksChecker,
CK_MismatchedDeallocatorChecker,
CK_InnerPointerChecker,
CK_TaintedAllocChecker,
CK_NumCheckKinds
};

Expand Down Expand Up @@ -365,6 +367,7 @@ class MallocChecker
mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
mutable std::unique_ptr<BugType> BT_TaintedAlloc;

#define CHECK_FN(NAME) \
void NAME(const CallEvent &Call, CheckerContext &C) const;
Expand Down Expand Up @@ -462,6 +465,13 @@ class MallocChecker
};

bool isMemCall(const CallEvent &Call) const;
void reportTaintBug(StringRef Msg, ProgramStateRef State, CheckerContext &C,
llvm::ArrayRef<SymbolRef> TaintedSyms,
AllocationFamily Family) const;

void checkTaintedness(CheckerContext &C, const CallEvent &Call,
const SVal SizeSVal, ProgramStateRef State,
AllocationFamily Family) const;

// TODO: Remove mutable by moving the initializtaion to the registry function.
mutable std::optional<uint64_t> KernelZeroFlagVal;
Expand Down Expand Up @@ -521,9 +531,9 @@ class MallocChecker
/// malloc leaves it undefined.
/// \param [in] State The \c ProgramState right before allocation.
/// \returns The ProgramState right after allocation.
[[nodiscard]] static ProgramStateRef
[[nodiscard]] ProgramStateRef
MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx,
SVal Init, ProgramStateRef State, AllocationFamily Family);
SVal Init, ProgramStateRef State, AllocationFamily Family) const;

/// Models memory allocation.
///
Expand All @@ -534,9 +544,10 @@ class MallocChecker
/// malloc leaves it undefined.
/// \param [in] State The \c ProgramState right before allocation.
/// \returns The ProgramState right after allocation.
[[nodiscard]] static ProgramStateRef
MallocMemAux(CheckerContext &C, const CallEvent &Call, SVal Size, SVal Init,
ProgramStateRef State, AllocationFamily Family);
[[nodiscard]] ProgramStateRef MallocMemAux(CheckerContext &C,
const CallEvent &Call, SVal Size,
SVal Init, ProgramStateRef State,
AllocationFamily Family) const;

// Check if this malloc() for special flags. At present that means M_ZERO or
// __GFP_ZERO (in which case, treat it like calloc).
Expand Down Expand Up @@ -649,8 +660,9 @@ class MallocChecker
/// \param [in] Call The expression that reallocated memory
/// \param [in] State The \c ProgramState right before reallocation.
/// \returns The ProgramState right after allocation.
[[nodiscard]] static ProgramStateRef
CallocMem(CheckerContext &C, const CallEvent &Call, ProgramStateRef State);
[[nodiscard]] ProgramStateRef CallocMem(CheckerContext &C,
const CallEvent &Call,
ProgramStateRef State) const;

/// See if deallocation happens in a suspicious context. If so, escape the
/// pointers that otherwise would have been deallocated and return true.
Expand Down Expand Up @@ -1695,6 +1707,11 @@ MallocChecker::processNewAllocation(const CXXAllocatorCall &Call,
// MallocUpdateRefState() instead of MallocMemAux() which breaks the
// existing binding.
SVal Target = Call.getObjectUnderConstruction();
if (Call.getOriginExpr()->isArray()) {
if (auto SizeEx = NE->getArraySize())
checkTaintedness(C, Call, C.getSVal(*SizeEx), State, AF_CXXNewArray);
}

State = MallocUpdateRefState(C, NE, State, Family, Target);
State = ProcessZeroAllocCheck(Call, 0, State, Target);
return State;
Expand Down Expand Up @@ -1779,18 +1796,74 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
const CallEvent &Call,
const Expr *SizeEx, SVal Init,
ProgramStateRef State,
AllocationFamily Family) {
AllocationFamily Family) const {
if (!State)
return nullptr;

assert(SizeEx);
return MallocMemAux(C, Call, C.getSVal(SizeEx), Init, State, Family);
}

void MallocChecker::reportTaintBug(StringRef Msg, ProgramStateRef State,
CheckerContext &C,
llvm::ArrayRef<SymbolRef> TaintedSyms,
AllocationFamily Family) const {
if (ExplodedNode *N = C.generateNonFatalErrorNode(State, this)) {
if (!BT_TaintedAlloc)
BT_TaintedAlloc.reset(new BugType(CheckNames[CK_TaintedAllocChecker],
"Tainted Memory Allocation",
categories::TaintedData));
auto R = std::make_unique<PathSensitiveBugReport>(*BT_TaintedAlloc, Msg, N);
for (auto TaintedSym : TaintedSyms) {
R->markInteresting(TaintedSym);
}
C.emitReport(std::move(R));
}
}

void MallocChecker::checkTaintedness(CheckerContext &C, const CallEvent &Call,
const SVal SizeSVal, ProgramStateRef State,
AllocationFamily Family) const {
if (!ChecksEnabled[CK_TaintedAllocChecker])
return;
std::vector<SymbolRef> TaintedSyms =
taint::getTaintedSymbols(State, SizeSVal);
if (TaintedSyms.empty())
return;

SValBuilder &SVB = C.getSValBuilder();
QualType SizeTy = SVB.getContext().getSizeType();
QualType CmpTy = SVB.getConditionType();
// In case the symbol is tainted, we give a warning if the
// size is larger than SIZE_MAX/4
BasicValueFactory &BVF = SVB.getBasicValueFactory();
const llvm::APSInt MaxValInt = BVF.getMaxValue(SizeTy);
NonLoc MaxLength =
SVB.makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));
std::optional<NonLoc> SizeNL = SizeSVal.getAs<NonLoc>();
auto Cmp = SVB.evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
.getAs<DefinedOrUnknownSVal>();
if (!Cmp)
return;
auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
if (!StateTooLarge && StateNotTooLarge) {
// We can prove that size is not too large so there is no issue.
return;
}

std::string Callee = "Memory allocation function";
if (Call.getCalleeIdentifier())
Callee = Call.getCalleeIdentifier()->getName().str();
reportTaintBug(
Callee + " is called with a tainted (potentially attacker controlled) "
"value. Make sure the value is bound checked.",
State, C, TaintedSyms, Family);
}

ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
const CallEvent &Call, SVal Size,
SVal Init, ProgramStateRef State,
AllocationFamily Family) {
AllocationFamily Family) const {
if (!State)
return nullptr;

Expand Down Expand Up @@ -1819,9 +1892,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
if (Size.isUndef())
Size = UnknownVal();

// TODO: If Size is tainted and we cannot prove that it is within
// reasonable bounds, emit a warning that an attacker may
// provoke a memory exhaustion error.
checkTaintedness(C, Call, Size, State, AF_Malloc);

// Set the region's extent.
State = setDynamicExtent(State, RetVal.getAsRegion(),
Expand Down Expand Up @@ -2761,7 +2832,7 @@ MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call,

ProgramStateRef MallocChecker::CallocMem(CheckerContext &C,
const CallEvent &Call,
ProgramStateRef State) {
ProgramStateRef State) const {
if (!State)
return nullptr;

Expand Down Expand Up @@ -3734,3 +3805,4 @@ REGISTER_CHECKER(MallocChecker)
REGISTER_CHECKER(NewDeleteChecker)
REGISTER_CHECKER(NewDeleteLeaksChecker)
REGISTER_CHECKER(MismatchedDeallocatorChecker)
REGISTER_CHECKER(TaintedAllocChecker)
1 change: 1 addition & 0 deletions clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1822,6 +1822,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
case Stmt::CapturedStmtClass:
case Stmt::OpenACCComputeConstructClass:
case Stmt::OpenACCLoopConstructClass:
case Stmt::OMPUnrollDirectiveClass:
case Stmt::OMPMetaDirectiveClass: {
const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/ast-dump-APValue-anon-union.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void Test() {

constexpr U0 u0a{};
// CHECK: | `-VarDecl {{.*}} <col:{{.*}}, col:{{.*}}> col:{{.*}} u0a 'const U0' constexpr listinit
// CHECK-NEXT: | |-value: Union None
// CHECK-NEXT: | |-value: Union .U0::(anonymous union at {{.*}}) Union .f Float 3.141500e+00

constexpr U0 u0b{3.1415f};
// CHECK: | `-VarDecl {{.*}} <col:{{.*}}, col:{{.*}}> col:{{.*}} u0b 'const U0' constexpr listinit
Expand Down
35 changes: 35 additions & 0 deletions clang/test/AST/ast-print-openacc-loop-construct.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// RUN: %clang_cc1 -fopenacc -Wno-openacc-deprecated-clause-alias -ast-print %s -o - | FileCheck %s

struct SomeStruct{};

void foo() {
// CHECK: #pragma acc loop
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc loop
for(;;);

// CHECK: #pragma acc loop device_type(SomeStruct)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc loop device_type(SomeStruct)
for(;;);

// CHECK: #pragma acc loop device_type(int)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc loop device_type(int)
for(;;);

// CHECK: #pragma acc loop dtype(bool)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc loop dtype(bool)
for(;;);

// CHECK: #pragma acc loop dtype(AnotherIdent)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc loop dtype(AnotherIdent)
for(;;);
}
43 changes: 42 additions & 1 deletion clang/test/Analysis/malloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// RUN: -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN: -analyzer-checker=alpha.core.CastSize \
// RUN: -analyzer-checker=unix \
// RUN: -analyzer-checker=debug.ExprInspection
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-checker=alpha.security.taint.TaintPropagation \
// RUN: -analyzer-checker=optin.taint.TaintedAlloc

#include "Inputs/system-header-simulator.h"

Expand Down Expand Up @@ -48,6 +50,45 @@ void myfoo(int *p);
void myfooint(int p);
char *fooRetPtr(void);

void t1(void) {
size_t size = 0;
scanf("%zu", &size);
int *p = malloc(size); // expected-warning{{malloc is called with a tainted (potentially attacker controlled) value}}
free(p);
}

void t2(void) {
size_t size = 0;
scanf("%zu", &size);
int *p = calloc(size,2); // expected-warning{{calloc is called with a tainted (potentially attacker controlled) value}}
free(p);
}

void t3(void) {
size_t size = 0;
scanf("%zu", &size);
if (1024 < size)
return;
int *p = malloc(size); // No warning expected as the the user input is bound
free(p);
}

void t4(void) {
size_t size = 0;
int *p = malloc(sizeof(int));
scanf("%zu", &size);
p = (int*) realloc((void*) p, size); // expected-warning{{realloc is called with a tainted (potentially attacker controlled) value}}
free(p);
}

void t5(void) {
size_t size = 0;
int *p = alloca(sizeof(int));
scanf("%zu", &size);
p = (int*) alloca(size); // expected-warning{{alloca is called with a tainted (potentially attacker controlled) value}}
}


void f1(void) {
int *p = malloc(12);
return; // expected-warning{{Potential leak of memory pointed to by 'p'}}
Expand Down
24 changes: 20 additions & 4 deletions clang/test/Analysis/malloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,38 @@
// RUN: -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN: -analyzer-checker=alpha.core.CastSize \
// RUN: -analyzer-checker=unix.Malloc \
// RUN: -analyzer-checker=cplusplus.NewDelete
// RUN: -analyzer-checker=cplusplus.NewDelete \
// RUN: -analyzer-checker=alpha.security.taint.TaintPropagation \
// RUN: -analyzer-checker=optin.taint.TaintedAlloc

// RUN: %clang_analyze_cc1 -w -verify %s \
// RUN: -triple i386-unknown-linux-gnu \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN: -analyzer-checker=alpha.core.CastSize \
// RUN: -analyzer-checker=unix.Malloc \
// RUN: -analyzer-checker=cplusplus.NewDelete
// RUN: -analyzer-checker=cplusplus.NewDelete \
// RUN: -analyzer-checker=alpha.security.taint.TaintPropagation \
// RUN: -analyzer-checker=optin.taint.TaintedAlloc

// RUN: %clang_analyze_cc1 -w -verify %s -DTEST_INLINABLE_ALLOCATORS \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN: -analyzer-checker=alpha.core.CastSize \
// RUN: -analyzer-checker=unix.Malloc \
// RUN: -analyzer-checker=cplusplus.NewDelete
// RUN: -analyzer-checker=cplusplus.NewDelete \
// RUN: -analyzer-checker=alpha.security.taint.TaintPropagation \
// RUN: -analyzer-checker=optin.taint.TaintedAlloc

// RUN: %clang_analyze_cc1 -w -verify %s -DTEST_INLINABLE_ALLOCATORS \
// RUN: -triple i386-unknown-linux-gnu \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN: -analyzer-checker=alpha.core.CastSize \
// RUN: -analyzer-checker=unix.Malloc \
// RUN: -analyzer-checker=cplusplus.NewDelete
// RUN: -analyzer-checker=cplusplus.NewDelete \
// RUN: -analyzer-checker=alpha.security.taint.TaintPropagation \
// RUN: -analyzer-checker=optin.taint.TaintedAlloc

#include "Inputs/system-header-simulator-cxx.h"

Expand All @@ -36,6 +44,14 @@ void free(void *);
void *realloc(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
char *strdup(const char *s);
int scanf( const char* format, ... );

void taintAlloc() {
size_t size = 0;
scanf("%zu", &size);
int *ptr = new int[size];// expected-warning{{Memory allocation function is called with a tainted (potentially attacker controlled) value}}
delete[] ptr;
}

void checkThatMallocCheckerIsRunning() {
malloc(4);
Expand Down
11 changes: 10 additions & 1 deletion clang/test/Analysis/taint-diagnostic-visitor.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2,optin.taint.TaintedAlloc -analyzer-output=text -verify %s

// This file is for testing enhanced diagnostics produced by the GenericTaintChecker

Expand Down Expand Up @@ -115,3 +115,12 @@ void multipleTaintedArgs(void) {
system(buf); // expected-warning {{Untrusted data is passed to a system call}}
// expected-note@-1{{Untrusted data is passed to a system call}}
}

void testTaintedMalloc(){
size_t size = 0;
scanf("%zu", &size); // expected-note {{Taint originated here}}
// expected-note@-1 {{Taint propagated to the 2nd argument}}
int *p = malloc(size);// expected-warning{{malloc is called with a tainted (potentially attacker controlled) value}}
// expected-note@-1{{malloc is called with a tainted (potentially attacker controlled) value}}
free(p);
}
8 changes: 3 additions & 5 deletions clang/test/CXX/drs/cwg1xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -883,23 +883,21 @@ namespace cwg161 { // cwg161: 3.1
};
}

namespace cwg162 { // cwg162: no
namespace cwg162 { // cwg162: 19
struct A {
char &f(char);
static int &f(int);

void g() {
int &a = (&A::f)(0);
// FIXME: expected-error@-1 {{reference to overloaded function could not be resolved; did you mean to call it?}}
char &b = (&A::f)('0');
// expected-error@-1 {{reference to overloaded function could not be resolved; did you mean to call it?}}
// expected-error@-1 {{non-const lvalue reference to type 'char' cannot bind to a value of unrelated type 'int'}}
}
};

int &c = (&A::f)(0);
// FIXME: expected-error@-1 {{reference to overloaded function could not be resolved; did you mean to call it?}}
char &d = (&A::f)('0');
// expected-error@-1 {{reference to overloaded function could not be resolved; did you mean to call it?}}
// expected-error@-1 {{non-const lvalue reference to type 'char' cannot bind to a value of unrelated type 'int'}}
}

// cwg163: na
Expand Down
27 changes: 27 additions & 0 deletions clang/test/CXX/drs/cwg26xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,30 @@ void test() {
}
}
#endif


namespace cwg2692 { // cwg2692: 19
#if __cplusplus >= 202302L

struct A {
static void f(A); // #cwg2692-1
void f(this A); // #cwg2692-2

void g();
};

void A::g() {
(&A::f)(A());
// expected-error@-1 {{call to 'f' is ambiguous}}
// expected-note@#cwg2692-1 {{candidate}}
// expected-note@#cwg2692-2 {{candidate}}



(&A::f)();
// expected-error@-1 {{no matching function for call to 'f'}}
// expected-note@#cwg2692-1 {{candidate function not viable: requires 1 argument, but 0 were provided}}
// expected-note@#cwg2692-2 {{candidate function not viable: requires 1 argument, but 0 were provided}}
}
#endif
}
19 changes: 19 additions & 0 deletions clang/test/CXX/drs/cwg2771.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %clang_cc1 -std=c++23 %s -ast-dump | FileCheck --check-prefixes=CXX23 %s

namespace cwg2771 { // cwg2771: 18

struct A{
int a;
void cwg2771(){
int* r = &a;
}
};
// CXX23: CXXMethodDecl{{.+}}cwg2771
// CXX23-NEXT: CompoundStmt
// CXX23-NEXT: DeclStmt
// CXX23-NEXT: VarDecl
// CXX23-NEXT: UnaryOperator
// CXX23-NEXT: MemberExpr
// CXX23-NEXT: CXXThisExpr{{.+}}'cwg2771::A *'

} // namespace cwg2771
20 changes: 20 additions & 0 deletions clang/test/CodeGenCXX/cxx2b-deducing-this.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,23 @@ void f() {
d();
}
}


namespace P2797 {
struct C {
void c(this const C&); // #first
void c() &; // #second
static void c(int = 0); // #third

void d() {
(&C::c)(C{});
(&C::c)();
}
};
void test() {
(void)C{}.d();
}
// CHECK-LABEL: {{.*}} @_ZN5P27971C1dEv
// CHECK: call void @_ZNH5P27971C1cERKS0_
// CHECK: call void @_ZN5P27971C1cEi
}
6 changes: 3 additions & 3 deletions clang/test/Driver/cl-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,15 +549,15 @@
// RTTI-NOT: "-fno-rtti-data"
// RTTI-NOT: "-fno-rtti"

// RUN: %clang_cl /Zi /c -### -- %s 2>&1 | FileCheck -check-prefix=Zi %s
// RUN: %clang_cl -target x86_64-windows /Zi /c -### -- %s 2>&1 | FileCheck -check-prefix=Zi %s
// Zi: "-gcodeview"
// Zi: "-debug-info-kind=constructor"

// RUN: %clang_cl /Z7 /c -### -- %s 2>&1 | FileCheck -check-prefix=Z7 %s
// RUN: %clang_cl -target x86_64-windows /Z7 /c -### -- %s 2>&1 | FileCheck -check-prefix=Z7 %s
// Z7: "-gcodeview"
// Z7: "-debug-info-kind=constructor"

// RUN: %clang_cl -gline-tables-only /c -### -- %s 2>&1 | FileCheck -check-prefix=ZGMLT %s
// RUN: %clang_cl -target x86_64-windows -gline-tables-only /c -### -- %s 2>&1 | FileCheck -check-prefix=ZGMLT %s
// ZGMLT: "-gcodeview"
// ZGMLT: "-debug-info-kind=line-tables-only"

Expand Down
10 changes: 5 additions & 5 deletions clang/test/Driver/cl-outputs.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,15 +298,15 @@
// FioRACE2: "-E"
// FioRACE2: "-o" "foo.x"

// RUN: %clang_cl /Z7 /Foa.obj -### -- %s 2>&1 | FileCheck -check-prefix=ABSOLUTE_OBJPATH %s
// RUN: %clang_cl -target x86_64-windows /Z7 /Foa.obj -### -- %s 2>&1 | FileCheck -check-prefix=ABSOLUTE_OBJPATH %s
// ABSOLUTE_OBJPATH: "-object-file-name={{.*}}a.obj"

// RUN: %clang_cl -fdebug-compilation-dir=. /Z7 /Foa.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH1 %s
// RUN: %clang_cl -target x86_64-windows -fdebug-compilation-dir=. /Z7 /Foa.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH1 %s
// RELATIVE_OBJPATH1: "-object-file-name=a.obj"

// RUN: %clang_cl -fdebug-compilation-dir=. /Z7 /Fo:a.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH1_COLON %s
// RUN: %clang_cl -fdebug-compilation-dir=. /Z7 /Fo: a.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH1_COLON %s
// RUN: %clang_cl -target x86_64-windows -fdebug-compilation-dir=. /Z7 /Fo:a.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH1_COLON %s
// RUN: %clang_cl -target x86_64-windows -fdebug-compilation-dir=. /Z7 /Fo: a.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH1_COLON %s
// RELATIVE_OBJPATH1_COLON: "-object-file-name=a.obj"

// RUN: %clang_cl -fdebug-compilation-dir=. /Z7 /Fofoo/a.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH2 %s
// RUN: %clang_cl -target x86_64-windows -fdebug-compilation-dir=. /Z7 /Fofoo/a.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH2 %s
// RELATIVE_OBJPATH2: "-object-file-name=foo\\a.obj"
12 changes: 6 additions & 6 deletions clang/test/Driver/gcodeview-command-line.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
// OFF: "-gno-codeview-command-line"

// default
// RUN: %clang_cl /Z7 -### -- %s 2>&1 | FileCheck -check-prefix=ON %s
// RUN: %clang_cl -target x86_64-windows /Z7 -### -- %s 2>&1 | FileCheck -check-prefix=ON %s
// enabled
// RUN: %clang_cl /Z7 -gno-codeview-command-line -gcodeview-command-line -### -- %s 2>&1 | FileCheck -check-prefix=ON %s
// RUN: %clang_cl -target x86_64-windows /Z7 -gno-codeview-command-line -gcodeview-command-line -### -- %s 2>&1 | FileCheck -check-prefix=ON %s
// disabled
// RUN: %clang_cl /Z7 -gcodeview-command-line -gno-codeview-command-line -### -- %s 2>&1 | FileCheck -check-prefix=OFF %s
// RUN: %clang_cl -target x86_64-windows /Z7 -gcodeview-command-line -gno-codeview-command-line -### -- %s 2>&1 | FileCheck -check-prefix=OFF %s

// enabled, no /Z7
// RUN: %clang_cl -gcodeview-command-line -### -- %s 2>&1 | FileCheck -check-prefix=ON %s
// RUN: %clang_cl -target x86_64-windows -gcodeview-command-line -### -- %s 2>&1 | FileCheck -check-prefix=ON %s

// GCC-style driver
// RUN: %clang -g -gcodeview -gno-codeview-command-line -gcodeview-command-line -### -- %s 2>&1 | FileCheck -check-prefix=ON %s
// RUN: %clang -g -gcodeview -gcodeview-command-line -gno-codeview-command-line -### -- %s 2>&1 | FileCheck -check-prefix=OFF %s
// RUN: %clang -target x86_64-windows -g -gcodeview -gno-codeview-command-line -gcodeview-command-line -### -- %s 2>&1 | FileCheck -check-prefix=ON %s
// RUN: %clang -target x86_64-windows -g -gcodeview -gcodeview-command-line -gno-codeview-command-line -### -- %s 2>&1 | FileCheck -check-prefix=OFF %s
12 changes: 6 additions & 6 deletions clang/test/Driver/gcodeview-ghash.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
// NO_GHASH-NOT: "-gcodeview-ghash"

// default
// RUN: %clang_cl /Z7 -### -- %s 2>&1 | FileCheck -check-prefix=NO_GHASH %s
// RUN: %clang_cl -target x86_64-windows /Z7 -### -- %s 2>&1 | FileCheck -check-prefix=NO_GHASH %s
// enabled
// RUN: %clang_cl /Z7 -gcodeview-ghash -### -- %s 2>&1 | FileCheck -check-prefix=GHASH %s
// RUN: %clang_cl -target x86_64-windows /Z7 -gcodeview-ghash -### -- %s 2>&1 | FileCheck -check-prefix=GHASH %s
// disabled
// RUN: %clang_cl /Z7 -gcodeview-ghash -gno-codeview-ghash -### -- %s 2>&1 | FileCheck -check-prefix=NO_GHASH %s
// RUN: %clang_cl -target x86_64-windows /Z7 -gcodeview-ghash -gno-codeview-ghash -### -- %s 2>&1 | FileCheck -check-prefix=NO_GHASH %s

// enabled, no /Z7
// RUN: %clang_cl -gcodeview-ghash -### -- %s 2>&1 | FileCheck -check-prefix=NO_GHASH %s
// RUN: %clang_cl -target x86_64-windows -gcodeview-ghash -### -- %s 2>&1 | FileCheck -check-prefix=NO_GHASH %s

// GCC-style driver
// RUN: %clang -g -gcodeview -gcodeview-ghash -### -- %s 2>&1 | FileCheck -check-prefix=GHASH %s
// RUN: %clang -g -gcodeview -gcodeview-ghash -gno-codeview-ghash -### -- %s 2>&1 | FileCheck -check-prefix=NO_GHASH %s
// RUN: %clang -target x86_64-windows -g -gcodeview -gcodeview-ghash -### -- %s 2>&1 | FileCheck -check-prefix=GHASH %s
// RUN: %clang -target x86_64-windows -g -gcodeview -gcodeview-ghash -gno-codeview-ghash -### -- %s 2>&1 | FileCheck -check-prefix=NO_GHASH %s
2 changes: 1 addition & 1 deletion clang/test/Misc/target-invalid-cpu-note.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

// RUN: not %clang_cc1 -triple nvptx--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix NVPTX
// NVPTX: error: unknown target CPU 'not-a-cpu'
// NVPTX-NEXT: note: valid target CPU values are: sm_20, sm_21, sm_30, sm_32, sm_35, sm_37, sm_50, sm_52, sm_53, sm_60, sm_61, sm_62, sm_70, sm_72, sm_75, sm_80, sm_86, sm_87, sm_89, sm_90, sm_90a, gfx600, gfx601, gfx602, gfx700, gfx701, gfx702, gfx703, gfx704, gfx705, gfx801, gfx802, gfx803, gfx805, gfx810, gfx900, gfx902, gfx904, gfx906, gfx908, gfx909, gfx90a, gfx90c, gfx940, gfx941, gfx942, gfx1010, gfx1011, gfx1012, gfx1013, gfx1030, gfx1031, gfx1032, gfx1033, gfx1034, gfx1035, gfx1036, gfx1100, gfx1101, gfx1102, gfx1103, gfx1150, gfx1151, gfx1200, gfx1201{{$}}
// NVPTX-NEXT: note: valid target CPU values are: sm_20, sm_21, sm_30, sm_32, sm_35, sm_37, sm_50, sm_52, sm_53, sm_60, sm_61, sm_62, sm_70, sm_72, sm_75, sm_80, sm_86, sm_87, sm_89, sm_90, sm_90a, gfx600, gfx601, gfx602, gfx700, gfx701, gfx702, gfx703, gfx704, gfx705, gfx801, gfx802, gfx803, gfx805, gfx810, gfx9-generic, gfx900, gfx902, gfx904, gfx906, gfx908, gfx909, gfx90a, gfx90c, gfx940, gfx941, gfx942, gfx10-1-generic, gfx1010, gfx1011, gfx1012, gfx1013, gfx10-3-generic, gfx1030, gfx1031, gfx1032, gfx1033, gfx1034, gfx1035, gfx1036, gfx11-generic, gfx1100, gfx1101, gfx1102, gfx1103, gfx1150, gfx1151, gfx12-generic, gfx1200, gfx1201{{$}}

// RUN: not %clang_cc1 -triple r600--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix R600
// R600: error: unknown target CPU 'not-a-cpu'
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Misc/win32-elf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Check that basic use of win32-elf targets works.
// RUN: %clang -fsyntax-only -target x86_64-pc-win32-elf %s

// RUN: %clang -fsyntax-only -target x86_64-pc-win32-elf -g %s -### 2>&1 | FileCheck %s -check-prefix=DEBUG-INFO
// DEBUG-INFO: -dwarf-version={{.*}}
4 changes: 2 additions & 2 deletions clang/test/OpenMP/parallel_codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,8 +822,8 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[TID_ADDR]], align 4
// CHECK3-NEXT: store i32 [[TMP1]], ptr [[TID_ADDR_LOCAL]], align 4
// CHECK3-NEXT: [[TID:%.*]] = load i32, ptr [[TID_ADDR_LOCAL]], align 4
// CHECK3-NEXT: [[TMP2:%.*]] = load i64, ptr [[LOADGEP__RELOADED]], align 8
// CHECK3-NEXT: [[VAR:%.*]] = alloca ptr, align 8
// CHECK3-NEXT: [[TMP2:%.*]] = load i64, ptr [[LOADGEP__RELOADED]], align 8
// CHECK3-NEXT: br label [[OMP_PAR_REGION:%.*]]
// CHECK3: omp.par.region:
// CHECK3-NEXT: [[TMP3:%.*]] = load ptr, ptr [[LOADGEP_ARGC_ADDR]], align 8
Expand Down Expand Up @@ -966,8 +966,8 @@ int main (int argc, char **argv) {
// CHECK4-NEXT: [[TMP1:%.*]] = load i32, ptr [[TID_ADDR]], align 4
// CHECK4-NEXT: store i32 [[TMP1]], ptr [[TID_ADDR_LOCAL]], align 4
// CHECK4-NEXT: [[TID:%.*]] = load i32, ptr [[TID_ADDR_LOCAL]], align 4
// CHECK4-NEXT: [[TMP2:%.*]] = load i64, ptr [[LOADGEP__RELOADED]], align 8
// CHECK4-NEXT: [[VAR:%.*]] = alloca ptr, align 8
// CHECK4-NEXT: [[TMP2:%.*]] = load i64, ptr [[LOADGEP__RELOADED]], align 8
// CHECK4-NEXT: br label [[OMP_PAR_REGION:%.*]]
// CHECK4: omp.par.region:
// CHECK4-NEXT: [[TMP3:%.*]] = load ptr, ptr [[LOADGEP_ARGC_ADDR]], align 8, !dbg [[DBG58:![0-9]+]]
Expand Down
Loading