798 changes: 436 additions & 362 deletions clang/lib/Sema/TreeTransform.h

Large diffs are not rendered by default.

96 changes: 44 additions & 52 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,10 +915,9 @@ ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
using namespace llvm::support;

SelectorTable &SelTable = Reader.getContext().Selectors;
unsigned N =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
unsigned N = endian::readNext<uint16_t, llvm::endianness::little>(d);
const IdentifierInfo *FirstII = Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d));
F, endian::readNext<uint32_t, llvm::endianness::little>(d));
if (N == 0)
return SelTable.getNullarySelector(FirstII);
else if (N == 1)
Expand All @@ -928,7 +927,7 @@ ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
Args.push_back(FirstII);
for (unsigned I = 1; I != N; ++I)
Args.push_back(Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d)));
F, endian::readNext<uint32_t, llvm::endianness::little>(d)));

return SelTable.getSelector(N, Args.data());
}
Expand All @@ -941,11 +940,11 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
data_type Result;

Result.ID = Reader.getGlobalSelectorID(
F, endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d));
F, endian::readNext<uint32_t, llvm::endianness::little>(d));
unsigned FullInstanceBits =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint16_t, llvm::endianness::little>(d);
unsigned FullFactoryBits =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint16_t, llvm::endianness::little>(d);
Result.InstanceBits = FullInstanceBits & 0x3;
Result.InstanceHasMoreThanOneDecl = (FullInstanceBits >> 2) & 0x1;
Result.FactoryBits = FullFactoryBits & 0x3;
Expand All @@ -956,16 +955,14 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
// Load instance methods
for (unsigned I = 0; I != NumInstanceMethods; ++I) {
if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs<ObjCMethodDecl>(
F,
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d)))
F, endian::readNext<uint32_t, llvm::endianness::little>(d)))
Result.Instance.push_back(Method);
}

// Load factory methods
for (unsigned I = 0; I != NumFactoryMethods; ++I) {
if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs<ObjCMethodDecl>(
F,
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d)))
F, endian::readNext<uint32_t, llvm::endianness::little>(d)))
Result.Factory.push_back(Method);
}

Expand Down Expand Up @@ -1009,8 +1006,7 @@ static bool readBit(unsigned &Bits) {
IdentID ASTIdentifierLookupTrait::ReadIdentifierID(const unsigned char *d) {
using namespace llvm::support;

unsigned RawID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
unsigned RawID = endian::readNext<uint32_t, llvm::endianness::little>(d);
return Reader.getGlobalIdentifierID(F, RawID >> 1);
}

Expand All @@ -1028,8 +1024,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
unsigned DataLen) {
using namespace llvm::support;

unsigned RawID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
unsigned RawID = endian::readNext<uint32_t, llvm::endianness::little>(d);
bool IsInteresting = RawID & 0x01;

// Wipe out the "is interesting" bit.
Expand All @@ -1053,9 +1048,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
}

unsigned ObjCOrBuiltinID =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
unsigned Bits =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint16_t, llvm::endianness::little>(d);
unsigned Bits = endian::readNext<uint16_t, llvm::endianness::little>(d);
bool CPlusPlusOperatorKeyword = readBit(Bits);
bool HasRevertedTokenIDToIdentifier = readBit(Bits);
bool Poisoned = readBit(Bits);
Expand Down Expand Up @@ -1084,7 +1078,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// definition.
if (HadMacroDefinition) {
uint32_t MacroDirectivesOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint32_t, llvm::endianness::little>(d);
DataLen -= 4;

Reader.addPendingMacro(II, &F, MacroDirectivesOffset);
Expand All @@ -1098,8 +1092,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
SmallVector<uint32_t, 4> DeclIDs;
for (; DataLen > 0; DataLen -= 4)
DeclIDs.push_back(Reader.getGlobalDeclID(
F,
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d)));
F, endian::readNext<uint32_t, llvm::endianness::little>(d)));
Reader.SetGloballyVisibleDecls(II, DeclIDs);
}

Expand Down Expand Up @@ -1169,7 +1162,7 @@ ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) {
using namespace llvm::support;

uint32_t ModuleFileID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint32_t, llvm::endianness::little>(d);
return Reader.getLocalModuleFile(F, ModuleFileID);
}

Expand All @@ -1189,18 +1182,15 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) {
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXDeductionGuideName:
Data = (uint64_t)Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d));
F, endian::readNext<uint32_t, llvm::endianness::little>(d));
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
Data =
(uint64_t)Reader
.getLocalSelector(
F,
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(
d))
.getAsOpaquePtr();
Data = (uint64_t)Reader
.getLocalSelector(
F, endian::readNext<uint32_t, llvm::endianness::little>(d))
.getAsOpaquePtr();
break;
case DeclarationName::CXXOperatorName:
Data = *d++; // OverloadedOperatorKind
Expand All @@ -1223,8 +1213,7 @@ void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type,
using namespace llvm::support;

for (unsigned NumDecls = DataLen / 4; NumDecls; --NumDecls) {
uint32_t LocalID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
uint32_t LocalID = endian::readNext<uint32_t, llvm::endianness::little>(d);
Val.insert(Reader.getGlobalDeclID(F, LocalID));
}
}
Expand Down Expand Up @@ -2033,10 +2022,9 @@ HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
using namespace llvm::support;

internal_key_type ikey;
ikey.Size =
off_t(endian::readNext<uint64_t, llvm::endianness::little, unaligned>(d));
ikey.ModTime = time_t(
endian::readNext<uint64_t, llvm::endianness::little, unaligned>(d));
ikey.Size = off_t(endian::readNext<uint64_t, llvm::endianness::little>(d));
ikey.ModTime =
time_t(endian::readNext<uint64_t, llvm::endianness::little>(d));
ikey.Filename = (const char *)d;
ikey.Imported = true;
return ikey;
Expand Down Expand Up @@ -2064,9 +2052,9 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
HFI.DirInfo = (Flags >> 1) & 0x07;
HFI.IndexHeaderMapHeader = Flags & 0x01;
HFI.ControllingMacroID = Reader.getGlobalIdentifierID(
M, endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d));
M, endian::readNext<uint32_t, llvm::endianness::little>(d));
if (unsigned FrameworkOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d)) {
endian::readNext<uint32_t, llvm::endianness::little>(d)) {
// The framework offset is 1 greater than the actual offset,
// since 0 is used as an indicator for "no framework name".
StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1);
Expand All @@ -2077,7 +2065,7 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
"Wrong data length in HeaderFileInfo deserialization");
while (d != End) {
uint32_t LocalSMID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint32_t, llvm::endianness::little>(d);
auto HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>(LocalSMID & 7);
LocalSMID >>= 3;

Expand Down Expand Up @@ -4085,9 +4073,8 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const {
// how it goes...
using namespace llvm::support;
ModuleKind Kind = static_cast<ModuleKind>(
endian::readNext<uint8_t, llvm::endianness::little, unaligned>(Data));
uint16_t Len =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint8_t, llvm::endianness::little>(Data));
uint16_t Len = endian::readNext<uint16_t, llvm::endianness::little>(Data);
StringRef Name = StringRef((const char*)Data, Len);
Data += Len;
ModuleFile *OM = (Kind == MK_PrebuiltModule || Kind == MK_ExplicitModule ||
Expand All @@ -4103,21 +4090,21 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const {
}

SourceLocation::UIntTy SLocOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t IdentifierIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t MacroIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t PreprocessedEntityIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t SubmoduleIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t SelectorIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t DeclIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t TypeIndexOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);

auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset,
RemapBuilder &Remap) {
Expand Down Expand Up @@ -9798,7 +9785,7 @@ void ASTReader::finishPendingActions() {
!NonConstDefn->isLateTemplateParsed() &&
// We only perform ODR checks for decls not in the explicit
// global module fragment.
!FD->shouldSkipCheckingODR() &&
!shouldSkipCheckingODR(FD) &&
FD->getODRHash() != NonConstDefn->getODRHash()) {
if (!isa<CXXMethodDecl>(FD)) {
PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn);
Expand Down Expand Up @@ -11794,6 +11781,12 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
return OpenACCIfClause::Create(getContext(), BeginLoc, LParenLoc, CondExpr,
EndLoc);
}
case OpenACCClauseKind::Self: {
SourceLocation LParenLoc = readSourceLocation();
Expr *CondExpr = readBool() ? readSubExpr() : nullptr;
return OpenACCSelfClause::Create(getContext(), BeginLoc, LParenLoc,
CondExpr, EndLoc);
}
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::Seq:
Expand All @@ -11802,7 +11795,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
case OpenACCClauseKind::Worker:
case OpenACCClauseKind::Vector:
case OpenACCClauseKind::NoHost:
case OpenACCClauseKind::Self:
case OpenACCClauseKind::Copy:
case OpenACCClauseKind::UseDevice:
case OpenACCClauseKind::Attach:
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
Reader.mergeDefinitionVisibility(OldDef, ED);
// We don't want to check the ODR hash value for declarations from global
// module fragment.
if (!ED->shouldSkipCheckingODR() &&
if (!shouldSkipCheckingODR(ED) &&
OldDef->getODRHash() != ED->getODRHash())
Reader.PendingEnumOdrMergeFailures[OldDef].push_back(ED);
} else {
Expand Down Expand Up @@ -868,7 +868,7 @@ void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
VisitRecordDeclImpl(RD);
// We should only reach here if we're in C/Objective-C. There is no
// global module fragment.
assert(!RD->shouldSkipCheckingODR());
assert(!shouldSkipCheckingODR(RD));
RD->setODRHash(Record.readInt());

// Maintain the invariant of a redeclaration chain containing only
Expand Down Expand Up @@ -2155,7 +2155,7 @@ void ASTDeclReader::MergeDefinitionData(
}

// We don't want to check ODR for decls in the global module fragment.
if (MergeDD.Definition->shouldSkipCheckingODR())
if (shouldSkipCheckingODR(MergeDD.Definition))
return;

if (D->getODRHash() != MergeDD.ODRHash) {
Expand Down Expand Up @@ -3530,7 +3530,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
// same template specialization into the same CXXRecordDecl.
auto MergedDCIt = Reader.MergedDeclContexts.find(D->getLexicalDeclContext());
if (MergedDCIt != Reader.MergedDeclContexts.end() &&
!D->shouldSkipCheckingODR() && MergedDCIt->second == D->getDeclContext())
!shouldSkipCheckingODR(D) && MergedDCIt->second == D->getDeclContext())
Reader.PendingOdrMergeChecks.push_back(D);

return FindExistingResult(Reader, D, /*Existing=*/nullptr,
Expand Down
11 changes: 9 additions & 2 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6188,7 +6188,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {

BitsPacker DefinitionBits;

bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
DefinitionBits.addBit(ShouldSkipCheckingODR);

#define FIELD(Name, Width, Merge) \
Expand Down Expand Up @@ -7524,6 +7524,14 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
AddStmt(const_cast<Expr *>(IC->getConditionExpr()));
return;
}
case OpenACCClauseKind::Self: {
const auto *SC = cast<OpenACCIfClause>(C);
writeSourceLocation(SC->getLParenLoc());
writeBool(SC->hasConditionExpr());
if (SC->hasConditionExpr())
AddStmt(const_cast<Expr *>(SC->getConditionExpr()));
return;
}
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::Seq:
Expand All @@ -7532,7 +7540,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
case OpenACCClauseKind::Worker:
case OpenACCClauseKind::Vector:
case OpenACCClauseKind::NoHost:
case OpenACCClauseKind::Self:
case OpenACCClauseKind::Copy:
case OpenACCClauseKind::UseDevice:
case OpenACCClauseKind::Attach:
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
BitsPacker EnumDeclBits;
EnumDeclBits.addBits(D->getNumPositiveBits(), /*BitWidth=*/8);
EnumDeclBits.addBits(D->getNumNegativeBits(), /*BitWidth=*/8);
bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
EnumDeclBits.addBit(ShouldSkipCheckingODR);
EnumDeclBits.addBit(D->isScoped());
EnumDeclBits.addBit(D->isScopedUsingClassTag());
Expand All @@ -552,7 +552,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
!D->isTopLevelDeclInObjCContainer() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
!D->getIntegerTypeSourceInfo() && !D->getMemberSpecializationInfo() &&
!needsAnonymousDeclarationNumber(D) && !D->shouldSkipCheckingODR() &&
!needsAnonymousDeclarationNumber(D) && !shouldSkipCheckingODR(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclEnumAbbrev();

Expand Down Expand Up @@ -718,7 +718,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// FIXME: stable encoding
FunctionDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()), 3);
FunctionDeclBits.addBits((uint32_t)D->getStorageClass(), /*BitWidth=*/3);
bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
FunctionDeclBits.addBit(ShouldSkipCheckingODR);
FunctionDeclBits.addBit(D->isInlineSpecified());
FunctionDeclBits.addBit(D->isInlined());
Expand Down Expand Up @@ -1559,7 +1559,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() &&
!D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->shouldSkipCheckingODR() && !D->hasExtInfo() &&
!shouldSkipCheckingODR(D) && !D->hasExtInfo() &&
!D->isExplicitlyDefaulted()) {
if (D->getTemplatedKind() == FunctionDecl::TK_NonTemplate ||
D->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate ||
Expand Down
12 changes: 4 additions & 8 deletions clang/lib/Serialization/GlobalModuleIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,8 @@ class IdentifierIndexReaderTrait {
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d) {
using namespace llvm::support;
unsigned KeyLen =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
unsigned DataLen =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
unsigned KeyLen = endian::readNext<uint16_t, llvm::endianness::little>(d);
unsigned DataLen = endian::readNext<uint16_t, llvm::endianness::little>(d);
return std::make_pair(KeyLen, DataLen);
}

Expand All @@ -113,8 +111,7 @@ class IdentifierIndexReaderTrait {

data_type Result;
while (DataLen > 0) {
unsigned ID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
unsigned ID = endian::readNext<uint32_t, llvm::endianness::little>(d);
Result.push_back(ID);
DataLen -= 4;
}
Expand Down Expand Up @@ -514,8 +511,7 @@ namespace {
// The first bit indicates whether this identifier is interesting.
// That's all we care about.
using namespace llvm::support;
unsigned RawID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
unsigned RawID = endian::readNext<uint32_t, llvm::endianness::little>(d);
bool IsInteresting = RawID & 0x01;
return std::make_pair(k, IsInteresting);
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Serialization/MultiOnDiskHashTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,11 @@ template<typename Info> class MultiOnDiskHashTable {
storage_type Ptr = Data;

uint32_t BucketOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Ptr);
endian::readNext<uint32_t, llvm::endianness::little>(Ptr);

// Read the list of overridden files.
uint32_t NumFiles =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Ptr);
endian::readNext<uint32_t, llvm::endianness::little>(Ptr);
// FIXME: Add a reserve() to TinyPtrVector so that we don't need to make
// an additional copy.
llvm::SmallVector<file_type, 16> OverriddenFiles;
Expand Down
25 changes: 5 additions & 20 deletions clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
//
//===----------------------------------------------------------------------===//
//
// This checker evaluates clang builtin functions.
// This checker evaluates "standalone" clang builtin functions that are not
// just special-cased variants of well-known non-builtin functions.
// Builtin functions like __builtin_memcpy and __builtin_alloca should be
// evaluated by the same checker that handles their non-builtin variant to
// ensure that the two variants are handled consistently.
//
//===----------------------------------------------------------------------===//

Expand Down Expand Up @@ -80,25 +84,6 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
return true;
}

case Builtin::BI__builtin_alloca_with_align:
case Builtin::BI__builtin_alloca: {
SValBuilder &SVB = C.getSValBuilder();
const loc::MemRegionVal R =
SVB.getAllocaRegionVal(CE, C.getLocationContext(), C.blockCount());

// Set the extent of the region in bytes. This enables us to use the SVal
// of the argument directly. If we saved the extent in bits, it'd be more
// difficult to reason about values like symbol*8.
auto Size = Call.getArgSVal(0);
if (auto DefSize = Size.getAs<DefinedOrUnknownSVal>()) {
// This `getAs()` is mostly paranoia, because core.CallAndMessage reports
// undefined function arguments (unless it's disabled somehow).
state = setDynamicExtent(state, R.getRegion(), *DefSize, SVB);
}
C.addTransition(state->BindExpr(CE, LCtx, R));
return true;
}

case Builtin::BI__builtin_dynamic_object_size:
case Builtin::BI__builtin_object_size:
case Builtin::BI__builtin_constant_p: {
Expand Down
89 changes: 49 additions & 40 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,11 @@ class MallocChecker
};

const CallDescriptionMap<CheckFn> FreeingMemFnMap{
{{{"free"}, 1}, &MallocChecker::checkFree},
{{{"if_freenameindex"}, 1}, &MallocChecker::checkIfFreeNameIndex},
{{{"kfree"}, 1}, &MallocChecker::checkFree},
{{{"g_free"}, 1}, &MallocChecker::checkFree},
{{CDM::CLibrary, {"free"}, 1}, &MallocChecker::checkFree},
{{CDM::CLibrary, {"if_freenameindex"}, 1},
&MallocChecker::checkIfFreeNameIndex},
{{CDM::CLibrary, {"kfree"}, 1}, &MallocChecker::checkFree},
{{CDM::CLibrary, {"g_free"}, 1}, &MallocChecker::checkFree},
};

bool isFreeingCall(const CallEvent &Call) const;
Expand All @@ -413,41 +414,46 @@ class MallocChecker
friend class NoOwnershipChangeVisitor;

CallDescriptionMap<CheckFn> AllocatingMemFnMap{
{{{"alloca"}, 1}, &MallocChecker::checkAlloca},
{{{"_alloca"}, 1}, &MallocChecker::checkAlloca},
{{{"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{{"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
{{{"calloc"}, 2}, &MallocChecker::checkCalloc},
{{{"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDM::CLibrary, {"alloca"}, 1}, &MallocChecker::checkAlloca},
{{CDM::CLibrary, {"_alloca"}, 1}, &MallocChecker::checkAlloca},
// The line for "alloca" also covers "__builtin_alloca", but the
// _with_align variant must be listed separately because it takes an
// extra argument:
{{CDM::CLibrary, {"__builtin_alloca_with_align"}, 2},
&MallocChecker::checkAlloca},
{{CDM::CLibrary, {"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDM::CLibrary, {"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
{{CDM::CLibrary, {"calloc"}, 2}, &MallocChecker::checkCalloc},
{{CDM::CLibrary, {"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDM::CLibrary, {"strndup"}, 2}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"strdup"}, 1}, &MallocChecker::checkStrdup},
{{{"_strdup"}, 1}, &MallocChecker::checkStrdup},
{{{"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
{{{"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
{{CDM::CLibrary, {"_strdup"}, 1}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
{{CDM::CLibrary, {"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
{{CDM::CLibrary, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{{"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{{"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
{{{"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{{"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
{{{"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
{{{"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
{{{"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
{{{"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
{{{"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
{{CDM::CLibrary, {"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDM::CLibrary, {"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
{{CDM::CLibrary, {"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDM::CLibrary, {"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
{{CDM::CLibrary, {"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
{{CDM::CLibrary, {"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
{{CDM::CLibrary, {"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
{{CDM::CLibrary, {"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
{{CDM::CLibrary, {"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
};

CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
{{{"realloc"}, 2},
{{CDM::CLibrary, {"realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
{{{"reallocf"}, 2},
{{CDM::CLibrary, {"reallocf"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, true)},
{{{"g_realloc"}, 2},
{{CDM::CLibrary, {"g_realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
{{{"g_try_realloc"}, 2},
{{CDM::CLibrary, {"g_try_realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
{{{"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
{{{"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
{{CDM::CLibrary, {"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
{{CDM::CLibrary, {"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},

// NOTE: the following CallDescription also matches the C++ standard
// library function std::getline(); the callback will filter it out.
Expand Down Expand Up @@ -1259,9 +1265,6 @@ static bool isStandardRealloc(const CallEvent &Call) {
assert(FD);
ASTContext &AC = FD->getASTContext();

if (isa<CXXMethodDecl>(FD))
return false;

return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy &&
FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy &&
FD->getParamDecl(1)->getType().getDesugaredType(AC) ==
Expand All @@ -1273,9 +1276,6 @@ static bool isGRealloc(const CallEvent &Call) {
assert(FD);
ASTContext &AC = FD->getASTContext();

if (isa<CXXMethodDecl>(FD))
return false;

return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy &&
FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy &&
FD->getParamDecl(1)->getType().getDesugaredType(AC) ==
Expand All @@ -1284,14 +1284,14 @@ static bool isGRealloc(const CallEvent &Call) {

void MallocChecker::checkRealloc(const CallEvent &Call, CheckerContext &C,
bool ShouldFreeOnFail) const {
// HACK: CallDescription currently recognizes non-standard realloc functions
// as standard because it doesn't check the type, or wether its a non-method
// function. This should be solved by making CallDescription smarter.
// Mind that this came from a bug report, and all other functions suffer from
// this.
// https://bugs.llvm.org/show_bug.cgi?id=46253
// Ignore calls to functions whose type does not match the expected type of
// either the standard realloc or g_realloc from GLib.
// FIXME: Should we perform this kind of checking consistently for each
// function? If yes, then perhaps extend the `CallDescription` interface to
// handle this.
if (!isStandardRealloc(Call) && !isGRealloc(Call))
return;

ProgramStateRef State = C.getState();
State = ReallocMemAux(C, Call, ShouldFreeOnFail, State, AF_Malloc);
State = ProcessZeroAllocCheck(Call, 1, State);
Expand Down Expand Up @@ -1842,9 +1842,18 @@ static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
return nullptr;

SymbolRef Sym = RetVal->getAsLocSymbol();

// This is a return value of a function that was not inlined, such as malloc()
// or new(). We've checked that in the caller. Therefore, it must be a symbol.
assert(Sym);
// FIXME: In theory this assertion should fail for `alloca()` calls (because
// `AllocaRegion`s are not symbolic); but in practice this does not happen.
// As the current code appears to work correctly, I'm not touching this issue
// now, but it would be good to investigate and clarify this.
// Also note that perhaps the special `AllocaRegion` should be replaced by
// `SymbolicRegion` (or turned into a subclass of `SymbolicRegion`) to enable
// proper tracking of memory allocated by `alloca()` -- and after that change
// this assertion would become valid again.

// Set the symbol's state to Allocated.
return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
Expand Down
258 changes: 258 additions & 0 deletions clang/test/AST/Interp/builtin-align-cxx.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
// C++-specific checks for the alignment builtins
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 %s -fsyntax-only -verify=expected,both -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 %s -fsyntax-only -verify=ref,both


/// This is just a copy of the one from test/SemaCXX/ with some of the
/// diagnostic output adapted.
/// Also, align32array has an initializer now, which means it's not just
/// a dummy pointer for us and we do actually have type information for it.
/// In the future, we need to retain type information for dummy pointers as
/// well, so here is a test that will break once we do that:
namespace {
_Alignas(32) char heh[4];
static_assert(!__builtin_is_aligned(&heh[1], 4), ""); // expected-error {{failed}}
}


// Check that we don't crash when using dependent types in __builtin_align:
template <typename a, a b>
void *c(void *d) { // both-note{{candidate template ignored}}
return __builtin_align_down(d, b);
}

struct x {};
x foo;
void test(void *value) {
c<int, 16>(value);
c<struct x, foo>(value); // both-error{{no matching function for call to 'c'}}
}

template <typename T, long Alignment, long ArraySize = 16>
void test_templated_arguments() {
T array[ArraySize]; // both-error{{variable has incomplete type 'fwddecl'}}
static_assert(__is_same(decltype(__builtin_align_up(array, Alignment)), T *), // both-error{{requested alignment is not a power of 2}}
"return type should be the decayed array type");
static_assert(__is_same(decltype(__builtin_align_down(array, Alignment)), T *),
"return type should be the decayed array type");
static_assert(__is_same(decltype(__builtin_is_aligned(array, Alignment)), bool),
"return type should be bool");
T *x1 = __builtin_align_up(array, Alignment);
T *x2 = __builtin_align_down(array, Alignment);
bool x3 = __builtin_align_up(array, Alignment);
}

void test() {
test_templated_arguments<int, 32>(); // fine
test_templated_arguments<struct fwddecl, 16>();
// both-note@-1{{in instantiation of function template specialization 'test_templated_arguments<fwddecl, 16L, 16L>'}}
// both-note@-2{{forward declaration of 'fwddecl'}}
test_templated_arguments<int, 7>(); // invalid alignment value
// both-note@-1{{in instantiation of function template specialization 'test_templated_arguments<int, 7L, 16L>'}}
}

template <typename T, long ArraySize>
void test_incorrect_alignment_without_instatiation(T value) {
int array[32];
static_assert(__is_same(decltype(__builtin_align_up(array, 31)), int *), // both-error{{requested alignment is not a power of 2}}
"return type should be the decayed array type");
static_assert(__is_same(decltype(__builtin_align_down(array, 7)), int *), // both-error{{requested alignment is not a power of 2}}
"return type should be the decayed array type");
static_assert(__is_same(decltype(__builtin_is_aligned(array, -1)), bool), // both-error{{requested alignment must be 1 or greater}}
"return type should be bool");
__builtin_align_up(array); // both-error{{too few arguments to function call, expected 2, have 1}}
__builtin_align_up(array, 31); // both-error{{requested alignment is not a power of 2}}
__builtin_align_down(array, 31); // both-error{{requested alignment is not a power of 2}}
__builtin_align_up(array, 31); // both-error{{requested alignment is not a power of 2}}
__builtin_align_up(value, 31); // This shouldn't want since the type is dependent
__builtin_align_up(value); // Same here

__builtin_align_up(array, sizeof(sizeof(value)) - 1); // both-error{{requested alignment is not a power of 2}}
__builtin_align_up(array, value); // no diagnostic as the alignment is value dependent.
(void)__builtin_align_up(array, ArraySize); // The same above here
}

// The original fix for the issue above broke some legitimate code.
// Here is a regression test:
typedef __SIZE_TYPE__ size_t;
void *allocate_impl(size_t size);
template <typename T>
T *allocate() {
constexpr size_t allocation_size =
__builtin_align_up(sizeof(T), sizeof(void *));
return static_cast<T *>(
__builtin_assume_aligned(allocate_impl(allocation_size), sizeof(void *)));
}
struct Foo {
int value;
};
void *test2() {
return allocate<struct Foo>();
}

// Check that pointers-to-members cannot be used:
class MemPtr {
public:
int data;
void func();
virtual void vfunc();
};
void test_member_ptr() {
__builtin_align_up(&MemPtr::data, 64); // both-error{{operand of type 'int MemPtr::*' where arithmetic or pointer type is required}}
__builtin_align_down(&MemPtr::func, 64); // both-error{{operand of type 'void (MemPtr::*)()' where arithmetic or pointer type is required}}
__builtin_is_aligned(&MemPtr::vfunc, 64); // both-error{{operand of type 'void (MemPtr::*)()' where arithmetic or pointer type is required}}
}

void test_references(Foo &i) {
// Check that the builtins look at the referenced type rather than the reference itself.
(void)__builtin_align_up(i, 64); // both-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
(void)__builtin_align_up(static_cast<Foo &>(i), 64); // both-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
(void)__builtin_align_up(static_cast<const Foo &>(i), 64); // both-error{{operand of type 'const Foo' where arithmetic or pointer type is required}}
(void)__builtin_align_up(static_cast<Foo &&>(i), 64); // both-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
(void)__builtin_align_up(static_cast<const Foo &&>(i), 64); // both-error{{operand of type 'const Foo' where arithmetic or pointer type is required}}
(void)__builtin_align_up(&i, 64);
}

// Check that constexpr wrapper functions can be constant-evaluated.
template <typename T>
constexpr bool wrap_is_aligned(T ptr, long align) {
return __builtin_is_aligned(ptr, align);
// both-note@-1{{requested alignment -3 is not a positive power of two}}
// both-note@-2{{requested alignment 19 is not a positive power of two}}
// both-note@-3{{requested alignment must be 128 or less for type 'char'; 4194304 is invalid}}
}
template <typename T>
constexpr T wrap_align_up(T ptr, long align) {
return __builtin_align_up(ptr, align);
// both-note@-1{{requested alignment -2 is not a positive power of two}}
// both-note@-2{{requested alignment 18 is not a positive power of two}}
// both-note@-3{{requested alignment must be 2147483648 or less for type 'int'; 8589934592 is invalid}}
// both-error@-4{{operand of type 'bool' where arithmetic or pointer type is required}}
}

template <typename T>
constexpr T wrap_align_down(T ptr, long align) {
return __builtin_align_down(ptr, align);
// both-note@-1{{requested alignment -1 is not a positive power of two}}
// both-note@-2{{requested alignment 17 is not a positive power of two}}
// both-note@-3{{requested alignment must be 32768 or less for type 'short'; 1048576 is invalid}}
}

constexpr int a1 = wrap_align_up(22, 32);
static_assert(a1 == 32, "");
constexpr int a2 = wrap_align_down(22, 16);
static_assert(a2 == 16, "");
constexpr bool a3 = wrap_is_aligned(22, 32);
static_assert(!a3, "");
static_assert(wrap_align_down(wrap_align_up(22, 16), 32) == 32, "");
static_assert(wrap_is_aligned(wrap_align_down(wrap_align_up(22, 16), 32), 32), "");
static_assert(!wrap_is_aligned(wrap_align_down(wrap_align_up(22, 16), 32), 64), "");

constexpr long const_value(long l) { return l; }
// Check some invalid values during constant-evaluation
static_assert(wrap_align_down(1, const_value(-1)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_align_up(1, const_value(-2)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_is_aligned(1, const_value(-3)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_align_down(1, const_value(17)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_align_up(1, const_value(18)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_is_aligned(1, const_value(19)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}

// Check invalid values for smaller types:
static_assert(wrap_align_down(static_cast<short>(1), const_value(1 << 20)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to }}
// Check invalid boolean type
static_assert(wrap_align_up(static_cast<int>(1), const_value(1ull << 33)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_is_aligned(static_cast<char>(1), const_value(1 << 22)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}

// Check invalid boolean type
static_assert(wrap_align_up(static_cast<bool>(1), const_value(1 << 21)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in instantiation of function template specialization 'wrap_align_up<bool>' requested here}}

// Check constant evaluation for pointers:
_Alignas(32) char align32array[128] = {};
static_assert(&align32array[0] == &align32array[0], "");
// __builtin_align_up/down can be constant evaluated as a no-op for values
// that are known to have greater alignment:
static_assert(__builtin_align_up(&align32array[0], 32) == &align32array[0], "");
static_assert(__builtin_align_up(&align32array[0], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[0], 4) == __builtin_align_up(&align32array[0], 8), "");
// But it can not be evaluated if the alignment is greater than the minimum
// known alignment, since in that case the value might be the same if it happens
// to actually be aligned to 64 bytes at run time.
static_assert(&align32array[0] == __builtin_align_up(&align32array[0], 64), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}
static_assert(__builtin_align_up(&align32array[0], 64) == __builtin_align_up(&align32array[0], 64), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}

// However, we can compute in case the requested alignment is less than the
// base alignment:
static_assert(__builtin_align_up(&align32array[0], 4) == &align32array[0], "");
static_assert(__builtin_align_up(&align32array[1], 4) == &align32array[4], "");
static_assert(__builtin_align_up(&align32array[2], 4) == &align32array[4], "");
static_assert(__builtin_align_up(&align32array[3], 4) == &align32array[4], "");
static_assert(__builtin_align_up(&align32array[4], 4) == &align32array[4], "");
static_assert(__builtin_align_up(&align32array[5], 4) == &align32array[8], "");
static_assert(__builtin_align_up(&align32array[6], 4) == &align32array[8], "");
static_assert(__builtin_align_up(&align32array[7], 4) == &align32array[8], "");
static_assert(__builtin_align_up(&align32array[8], 4) == &align32array[8], "");

static_assert(__builtin_align_down(&align32array[0], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[1], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[2], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[3], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[4], 4) == &align32array[4], "");
static_assert(__builtin_align_down(&align32array[5], 4) == &align32array[4], "");
static_assert(__builtin_align_down(&align32array[6], 4) == &align32array[4], "");
static_assert(__builtin_align_down(&align32array[7], 4) == &align32array[4], "");
static_assert(__builtin_align_down(&align32array[8], 4) == &align32array[8], "");

// Achieving the same thing using casts to uintptr_t is not allowed:
static_assert((char *)((__UINTPTR_TYPE__)&align32array[7] & ~3) == &align32array[4], ""); // both-error{{not an integral constant expression}} \
// expected-note {{cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression}}

static_assert(__builtin_align_down(&align32array[1], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[1], 64) == &align32array[0], ""); // both-error{{not an integral constant expression}}
// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}

// Add some checks for __builtin_is_aligned:
static_assert(__builtin_is_aligned(&align32array[0], 32), "");
static_assert(__builtin_is_aligned(&align32array[4], 4), "");
// We cannot constant evaluate whether the array is aligned to > 32 since this
// may well be true at run time.
static_assert(!__builtin_is_aligned(&align32array[0], 64), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{cannot constant evaluate whether run-time alignment is at least 64}}

// However, if the alignment being checked is less than the minimum alignment of
// the base object we can check the low bits of the alignment:
static_assert(__builtin_is_aligned(&align32array[0], 4), "");
static_assert(!__builtin_is_aligned(&align32array[1], 4), "");
static_assert(!__builtin_is_aligned(&align32array[2], 4), "");
static_assert(!__builtin_is_aligned(&align32array[3], 4), "");
static_assert(__builtin_is_aligned(&align32array[4], 4), "");

// TODO: this should evaluate to true even though we can't evaluate the result
// of __builtin_align_up() to a concrete value
static_assert(__builtin_is_aligned(__builtin_align_up(&align32array[0], 64), 64), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}

// Check different source and alignment type widths are handled correctly.
static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<signed short>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<signed short>(7), static_cast<signed long>(4)), "");
// Also check signed -- unsigned mismatch.
static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<signed long>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), static_cast<unsigned long>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<unsigned long>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), static_cast<signed long>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<unsigned short>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<unsigned short>(7), static_cast<signed long>(4)), "");

// Check the diagnostic message
_Alignas(void) char align_void_array[1]; // both-error {{invalid application of '_Alignas' to an incomplete type 'void'}}
24 changes: 8 additions & 16 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,13 @@ namespace strcmp {
static_assert(__builtin_strcmp("abab", "abab\0banana") == 0, "");
static_assert(__builtin_strcmp("abab\0banana", "abab\0canada") == 0, "");
static_assert(__builtin_strcmp(0, "abab") == 0, ""); // both-error {{not an integral constant}} \
// both-note {{dereferenced null}} \
// expected-note {{in call to}}
// both-note {{dereferenced null}}
static_assert(__builtin_strcmp("abab", 0) == 0, ""); // both-error {{not an integral constant}} \
// both-note {{dereferenced null}} \
// expected-note {{in call to}}
// both-note {{dereferenced null}}

static_assert(__builtin_strcmp(kFoobar, kFoobazfoobar) == -1, "");
static_assert(__builtin_strcmp(kFoobar, kFoobazfoobar + 6) == 0, ""); // both-error {{not an integral constant}} \
// both-note {{dereferenced one-past-the-end}} \
// expected-note {{in call to}}
// both-note {{dereferenced one-past-the-end}}

/// Used to assert because we're passing a dummy pointer to
/// __builtin_strcmp() when evaluating the return statement.
Expand Down Expand Up @@ -72,14 +69,11 @@ constexpr const char *a = "foo\0quux";
static_assert(check(c), "");

constexpr int over1 = __builtin_strlen(a + 9); // both-error {{constant expression}} \
// both-note {{one-past-the-end}} \
// expected-note {{in call to}}
// both-note {{one-past-the-end}}
constexpr int over2 = __builtin_strlen(b + 9); // both-error {{constant expression}} \
// both-note {{one-past-the-end}} \
// expected-note {{in call to}}
// both-note {{one-past-the-end}}
constexpr int over3 = __builtin_strlen(c + 9); // both-error {{constant expression}} \
// both-note {{one-past-the-end}} \
// expected-note {{in call to}}
// both-note {{one-past-the-end}}

constexpr int under1 = __builtin_strlen(a - 1); // both-error {{constant expression}} \
// both-note {{cannot refer to element -1}}
Expand All @@ -90,8 +84,7 @@ constexpr const char *a = "foo\0quux";

constexpr char d[] = { 'f', 'o', 'o' }; // no nul terminator.
constexpr int bad = __builtin_strlen(d); // both-error {{constant expression}} \
// both-note {{one-past-the-end}} \
// expected-note {{in call to}}
// both-note {{one-past-the-end}}
}

namespace nan {
Expand All @@ -114,8 +107,7 @@ namespace nan {
/// FIXME: Current interpreter misses diagnostics.
constexpr char f2[] = {'0', 'x', 'A', 'E'}; /// No trailing 0 byte.
constexpr double NaN7 = __builtin_nan(f2); // both-error {{must be initialized by a constant expression}} \
// expected-note {{read of dereferenced one-past-the-end pointer}} \
// expected-note {{in call to}}
// expected-note {{read of dereferenced one-past-the-end pointer}}
static_assert(!__builtin_issignaling(__builtin_nan("")), "");
static_assert(__builtin_issignaling(__builtin_nans("")), "");
}
Expand Down
14 changes: 14 additions & 0 deletions clang/test/AST/Interp/cxx03.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,17 @@ namespace NonInitializingMemberExpr {
// both-note {{required by}} \
// both-note {{subexpression not valid}}
}


namespace NonLValueMemberExpr {
struct PODType {
int value;
};

#define ATTR __attribute__((require_constant_initialization))
struct TT1 {
ATTR static const int &subobj_init;
};

const int &TT1::subobj_init = PODType().value;
}
15 changes: 13 additions & 2 deletions clang/test/AST/Interp/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,9 +584,20 @@ namespace VariadicOperator {
namespace WeakCompare {
[[gnu::weak]]void weak_method();
static_assert(weak_method != nullptr, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}

constexpr auto A = &weak_method;
static_assert(A != nullptr, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}
}

namespace FromIntegral {
#if __cplusplus >= 202002L
typedef double (*DoubleFn)();
int a[(int)DoubleFn((void*)-1)()]; // both-error {{not allowed at file scope}} \
// both-warning {{variable length arrays}}
int b[(int)DoubleFn((void*)(-1 + 1))()]; // both-error {{not allowed at file scope}} \
// expected-note {{evaluates to a null function pointer}} \
// both-warning {{variable length arrays}}
#endif
}
8 changes: 8 additions & 0 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,3 +1309,11 @@ namespace pr18633 {
func2<int>();
}
}

namespace {
struct F {
static constexpr int Z = 12;
};
F f;
static_assert(f.Z == 12, "");
}
10 changes: 9 additions & 1 deletion clang/test/AST/Interp/vectors.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -verify=ref,both %s

// both-no-diagnostics
// ref-no-diagnostics

typedef int __attribute__((vector_size(16))) VI4;
constexpr VI4 A = {1,2,3,4};
Expand All @@ -13,10 +13,18 @@ namespace Vector {
return VI4 { n * 3, n + 4, n - 5, n / 6 };
}
constexpr auto v1 = f(10);
static_assert(__builtin_vectorelements(v1) == (16 / sizeof(int)), "");

typedef double __attribute__((vector_size(32))) VD4;
constexpr VD4 g(int n) {
return (VD4) { n / 2.0, n + 1.5, n - 5.4, n * 0.9 };
}
constexpr auto v2 = g(4);
static_assert(__builtin_vectorelements(v2) == (32 / sizeof(double)), "");
}

/// FIXME: We need to support BitCasts between vector types.
namespace {
typedef float __attribute__((vector_size(16))) VI42;
constexpr VI42 A2 = A; // expected-error {{must be initialized by a constant expression}}
}
6 changes: 4 additions & 2 deletions clang/test/Analysis/Inputs/system-header-simulator-cxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,7 @@ using ostream = basic_ostream<char>;
extern std::ostream cout;

ostream &operator<<(ostream &, const string &);

#if __cplusplus >= 202002L
template <class T>
ostream &operator<<(ostream &, const std::unique_ptr<T> &);
Expand All @@ -1122,11 +1123,12 @@ istream &getline(istream &, string &, char);
istream &getline(istream &, string &);
} // namespace std

#ifdef TEST_INLINABLE_ALLOCATORS
namespace std {
void *malloc(size_t);
void free(void *);
}
} // namespace std

#ifdef TEST_INLINABLE_ALLOCATORS
void* operator new(std::size_t size, const std::nothrow_t&) throw() { return std::malloc(size); }
void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return std::malloc(size); }
void operator delete(void* ptr, const std::nothrow_t&) throw() { std::free(ptr); }
Expand Down
24 changes: 16 additions & 8 deletions clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.UninitializedObject \
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,optin.cplusplus.UninitializedObject \
// RUN: -analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
// RUN: -analyzer-config optin.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
// RUN: -std=c++11 -verify %s

// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.UninitializedObject \
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,optin.cplusplus.UninitializedObject \
// RUN: -analyzer-config optin.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
// RUN: -std=c++11 -verify %s

Expand Down Expand Up @@ -316,7 +316,10 @@ void fCyclicPointerTest2() {

// Void pointer tests are mainly no-crash tests.

void *malloc(int size);
typedef __typeof(sizeof(int)) size_t;

void *calloc(size_t nmemb, size_t size);
void free(void *p);

class VoidPointerTest1 {
void *vptr;
Expand All @@ -328,8 +331,9 @@ class VoidPointerTest1 {
};

void fVoidPointerTest1() {
void *vptr = malloc(sizeof(int));
void *vptr = calloc(1, sizeof(int));
VoidPointerTest1(vptr, char());
free(vptr);
}

class VoidPointerTest2 {
Expand All @@ -342,8 +346,9 @@ class VoidPointerTest2 {
};

void fVoidPointerTest2() {
void *vptr = malloc(sizeof(int));
void *vptr = calloc(1, sizeof(int));
VoidPointerTest2(&vptr, char());
free(vptr);
}

class VoidPointerRRefTest1 {
Expand All @@ -359,8 +364,9 @@ upon returning to the caller. This will be a dangling reference}}
};

void fVoidPointerRRefTest1() {
void *vptr = malloc(sizeof(int));
void *vptr = calloc(1, sizeof(int));
VoidPointerRRefTest1(vptr, char());
free(vptr);
}

class VoidPointerRRefTest2 {
Expand All @@ -376,8 +382,9 @@ upon returning to the caller. This will be a dangling reference}}
};

void fVoidPointerRRefTest2() {
void *vptr = malloc(sizeof(int));
void *vptr = calloc(1, sizeof(int));
VoidPointerRRefTest2(&vptr, char());
free(vptr);
}

class VoidPointerLRefTest {
Expand All @@ -393,8 +400,9 @@ upon returning to the caller. This will be a dangling reference}}
};

void fVoidPointerLRefTest() {
void *vptr = malloc(sizeof(int));
void *vptr = calloc(1, sizeof(int));
VoidPointerLRefTest(vptr, char());
free(vptr);
}

struct CyclicVoidPointerTest {
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Analysis/exercise-ps.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_analyze_cc1 %s -verify -Wno-error=implicit-function-declaration \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=core,unix.Malloc \
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
//
// Just exercise the analyzer on code that has at one point caused issues
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Analysis/explain-svals.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -verify %s \
// RUN: -analyzer-checker=core.builtin \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-checker=unix.cstring \
// RUN: -analyzer-checker=unix.Malloc \
// RUN: -analyzer-config display-checker-name=false

typedef unsigned long size_t;
Expand Down
24 changes: 24 additions & 0 deletions clang/test/Analysis/malloc-std-namespace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -verify -analyzer-output=text %s

// This file tests that unix.Malloc can handle C++ code where e.g. malloc and
// free are declared within the namespace 'std' by the header <cstdlib>.

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

void leak() {
int *p = static_cast<int*>(std::malloc(sizeof(int))); // expected-note{{Memory is allocated}}
} // expected-warning{{Potential leak of memory pointed to by 'p'}}
// expected-note@-1{{Potential leak of memory pointed to by 'p'}}

void no_leak() {
int *p = static_cast<int*>(std::malloc(sizeof(int)));
std::free(p); // no-warning
}

void invalid_free() {
int i;
int *p = &i;
//expected-note@+2{{Argument to free() is the address of the local variable 'i', which is not memory allocated by malloc()}}
//expected-warning@+1{{Argument to free() is the address of the local variable 'i', which is not memory allocated by malloc()}}
std::free(p);
}
11 changes: 11 additions & 0 deletions clang/test/Analysis/malloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,17 @@ void allocaFree(void) {
free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
}

void allocaFreeBuiltin(void) {
int *p = __builtin_alloca(sizeof(int));
free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
}

void allocaFreeBuiltinAlign(void) {
int *p = __builtin_alloca_with_align(sizeof(int), 64);
free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
}


int* mallocEscapeRet(void) {
int *p = malloc(12);
return p; // no warning
Expand Down
11 changes: 11 additions & 0 deletions clang/test/Analysis/malloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,14 @@ void *realloc(void **ptr, size_t size) { realloc(ptr, size); } // no-crash
namespace pr46253_paramty2{
void *realloc(void *ptr, int size) { realloc(ptr, size); } // no-crash
} // namespace pr46253_paramty2

namespace pr81597 {
struct S {};
struct T {
void free(const S& s);
};
void f(T& t) {
S s;
t.free(s); // no-warning: This is not the free you are looking for...
}
} // namespace pr81597
2 changes: 1 addition & 1 deletion clang/test/Analysis/stack-addr-ps.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core -fblocks -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -fblocks -verify %s

int* f1(void) {
int x = 0;
Expand Down
4 changes: 2 additions & 2 deletions clang/test/Analysis/stackaddrleak.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -std=c99 -Dbool=_Bool -Wno-bool-conversion %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -x c++ -Wno-bool-conversion %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -verify -std=c99 -Dbool=_Bool -Wno-bool-conversion %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -verify -x c++ -Wno-bool-conversion %s

typedef __INTPTR_TYPE__ intptr_t;
char const *p;
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGen/target-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,11 @@

// RUN: %clang_cc1 -triple spir-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=SPIR
// SPIR: target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
// SPIR: target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1"

// RUN: %clang_cc1 -triple spir64-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=SPIR64
// SPIR64: target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
// SPIR64: target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1"

// RUN: %clang_cc1 -triple bpfel -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=BPFEL
Expand Down
393 changes: 0 additions & 393 deletions clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp

This file was deleted.

31 changes: 26 additions & 5 deletions clang/test/CodeGenCXX/module-funcs-from-imports.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ int func_in_gmf_not_called() {
return 44;
}

template <class T>
class A {
public:
__attribute__((always_inline))
inline constexpr int getValue() {
return 43;
}

inline constexpr int getValue2() {
return 43;
}
};

extern template class A<char>;

//--- M.cppm
module;
#include "foo.h"
Expand All @@ -47,17 +62,21 @@ int always_inline_func() {
return 45;
}

export using ::A;

//--- Use.cpp
import M;
int use() {
return exported_func() + always_inline_func();
A<char> a;
return exported_func() + always_inline_func() +
a.getValue() + a.getValue2();
}

// Checks that none of the function (except the always_inline_func) in the importees
// are generated in the importer's code.
// CHECK-O0: define{{.*}}_Z3usev(
// CHECK-O0: declare{{.*}}_ZW1M13exported_funcv(
// CHECK-O0: define{{.*}}available_externally{{.*}}_ZW1M18always_inline_funcv(
// CHECK-O0: declare{{.*}}_ZW1M18always_inline_funcv(
// CHECK-O0: define{{.*}}@_ZN1AIcE8getValueEv(
// CHECK-O0: declare{{.*}}@_ZN1AIcE9getValue2Ev(
// CHECK-O0-NOT: func_in_gmf
// CHECK-O0-NOT: func_in_gmf_not_called
// CHECK-O0-NOT: non_exported_func
Expand All @@ -68,7 +87,9 @@ int use() {
// O0 to keep consistent ABI.
// CHECK-O1: define{{.*}}_Z3usev(
// CHECK-O1: declare{{.*}}_ZW1M13exported_funcv(
// CHECK-O1: define{{.*}}available_externally{{.*}}_ZW1M18always_inline_funcv(
// CHECK-O1: declare{{.*}}_ZW1M18always_inline_funcv(
// CHECK-O1: define{{.*}}@_ZN1AIcE8getValueEv(
// CHECK-O1: declare{{.*}}@_ZN1AIcE9getValue2Ev(
// CHECK-O1-NOT: func_in_gmf
// CHECK-O1-NOT: func_in_gmf_not_called
// CHECK-O1-NOT: non_exported_func
Expand Down
93 changes: 0 additions & 93 deletions clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp

This file was deleted.

24 changes: 24 additions & 0 deletions clang/test/Driver/windows-seh-async-verify.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang --target=x86_64-pc-windows -fasync-exceptions -fsyntax-only -### %s 2>&1 | FileCheck %s
// RUN: %clang_cl --target=x86_64-pc-windows /EHa -fsyntax-only -### -- %s 2>&1 | FileCheck %s
// RUN: %clang --target=x86_64-pc-windows-gnu -fasync-exceptions -fsyntax-only -### %s 2>&1 | FileCheck %s --check-prefixes=GNU-ALL,GNU
// RUN: %clang_cl --target=x86_64-pc-windows-gnu /EHa -fsyntax-only -### -- %s 2>&1 | FileCheck %s --check-prefixes=GNU-ALL,CL-GNU

// CHECK-NOT: warning
// GNU: warning: argument unused during compilation: '-fasync-exceptions' [-Wunused-command-line-argument]
// CL-GNU: warning: argument unused during compilation: '/EHa' [-Wunused-command-line-argument]

// CHECK: -fasync-exceptions
// GNU-ALL-NOT: -fasync-exceptions
struct S {
union _Un {
~_Un() {}
char _Buf[12];
};
_Un _un;
};

struct Embed {
S v2;
};

void PR62449() { Embed v{}; }
12 changes: 12 additions & 0 deletions clang/test/Index/USR/func-type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,15 @@ void Func( void (* (*)(int, int))(int, int) );
// CHECK: {{[0-9]+}}:6 | function/C | Func | c:@F@Func#*F*Fv(#I#I)(#I#I)# |
void Func( void (* (*)(int, int, int))(int) );
// CHECK: {{[0-9]+}}:6 | function/C | Func | c:@F@Func#*F*Fv(#I)(#I#I#I)# |

// Functions with parameter types that only differ in top-level cv-qualification should generate the same USR.

void f( const int );
// CHECK: {{[0-9]+}}:6 | function/C | f | c:@F@f#I# |
void f( int );
// CHECK: {{[0-9]+}}:6 | function/C | f | c:@F@f#I# |

void g( int );
// CHECK: {{[0-9]+}}:6 | function/C | g | c:@F@g#I# |
void g( const int );
// CHECK: {{[0-9]+}}:6 | function/C | g | c:@F@g#I# |
44 changes: 44 additions & 0 deletions clang/test/Modules/hashing-decls-in-exprs-from-gmf-2.cppm
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf %t/A.cppm -emit-module-interface -o %t/A.pcm
// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf %t/test.cpp -fprebuilt-module-path=%t -fsyntax-only -verify

//--- header.h
#pragma once
template <class _Tp>
class Optional {};

template <class _Tp>
concept C = requires(const _Tp& __t) {
[]<class _Up>(const Optional<_Up>&) {}(__t);
};

//--- func.h
#include "header.h"
template <C T>
void func() {}

//--- test_func.h
#include "func.h"

inline void test_func() {
func<Optional<int>>();
}

//--- A.cppm
module;
#include "header.h"
#include "test_func.h"
export module A;
export using ::test_func;

//--- test.cpp
// expected-no-diagnostics
import A;
#include "test_func.h"

void test() {
test_func();
}
5 changes: 1 addition & 4 deletions clang/test/ParserOpenACC/parse-clauses.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,16 +376,13 @@ void SelfClause() {
#pragma acc serial self(i > j, seq
for(;;){}

// expected-warning@+2{{left operand of comma operator has no effect}}
// expected-warning@+1{{OpenACC clause 'self' not yet implemented, clause ignored}}
// expected-warning@+1{{left operand of comma operator has no effect}}
#pragma acc serial self(i, j)
for(;;){}

// expected-warning@+1{{OpenACC clause 'self' not yet implemented, clause ignored}}
#pragma acc serial self(i > j)
for(;;){}

// expected-warning@+2{{OpenACC clause 'self' not yet implemented, clause ignored}}
// expected-warning@+1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
#pragma acc serial self(1+5>3), seq
for(;;){}
Expand Down
20 changes: 20 additions & 0 deletions clang/test/SemaCXX/instantiate-new-placement-size.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %clang -S -fno-discard-value-names -emit-llvm -o - %s | FileCheck %s
// Issue no: 41441
#include <new>

// CHECK: call void @llvm.memset.p0.i64(ptr align 1 %x, i8 0, i64 8, i1 false)
// CHECK: call void @llvm.memset.p0.i64(ptr align 16 %x, i8 0, i64 32, i1 false)
template <typename TYPE>
void f()
{
typedef TYPE TArray[8];

TArray x;
new(&x) TArray();
}

int main()
{
f<char>();
f<int>();
}
91 changes: 91 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-clause-ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,50 @@ void TemplFunc() {
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

#pragma acc serial self
while(true);
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}serial
// CHECK-NEXT: self clause
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

#pragma acc kernels self(T::SomeFloat)
while(true);
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: self clause
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

#pragma acc parallel self(T::SomeFloat) if (T::SomeFloat)
while(true);
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: self clause
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
// CHECK-NEXT: if clause
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

#pragma acc serial if(T::SomeFloat) self(T::SomeFloat)
while(true);
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}serial
// CHECK-NEXT: if clause
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
// CHECK-NEXT: self clause
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'T'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

// Match the instantiation:
// CHECK: FunctionDecl{{.*}}TemplFunc{{.*}}implicit_instantiation
// CHECK-NEXT: TemplateArgument type 'InstTy'
Expand Down Expand Up @@ -171,6 +215,53 @@ void TemplFunc() {
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}serial
// CHECK-NEXT: self clause
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: self clause
// CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
// CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: self clause
// CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
// CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
// CHECK-NEXT: if clause
// CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
// CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}serial
// CHECK-NEXT: if clause
// CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
// CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
// CHECK-NEXT: self clause
// CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' <FloatingToBoolean>
// CHECK-NEXT: ImplicitCastExpr{{.*}}'float' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt

}

struct BoolConversion{ operator bool() const;};
Expand Down
82 changes: 82 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-self-clause.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// RUN: %clang_cc1 %s -fopenacc -verify

void BoolExpr(int *I, float *F) {
typedef struct {} SomeStruct;
struct C{};
// expected-error@+1{{expected expression}}
#pragma acc parallel self (struct C f())
while(0);

// expected-error@+1{{unexpected type name 'SomeStruct': expected expression}}
#pragma acc serial self (SomeStruct)
while(0);

// expected-error@+1{{unexpected type name 'SomeStruct': expected expression}}
#pragma acc serial self (SomeStruct())
while(0);

SomeStruct S;
// expected-error@+1{{statement requires expression of scalar type ('SomeStruct' invalid)}}
#pragma acc serial self (S)
while(0);

#pragma acc parallel self (I)
while(0);

#pragma acc serial self (F)
while(0);

#pragma acc kernels self (*I < *F)
while(0);
}

void WarnMaybeNotUsed(int val1, int val2) {

// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel self if(val1)
while(0);

// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel self(val1) if(val1)
while(0);

// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel if(val1) self
while(0);

// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel if(val1) self(val2)
while(0);

// The below don't warn because one side or the other has an error, thus is
// not added to the AST.

// expected-error@+1{{use of undeclared identifier 'invalid'}}
#pragma acc parallel self if(invalid)
while(0);

// expected-error@+1{{use of undeclared identifier 'invalid'}}
#pragma acc parallel self(invalid) if(val1)
while(0);

// expected-error@+2{{expected expression}}
// expected-error@+1{{use of undeclared identifier 'invalid'}}
#pragma acc parallel self() if(invalid)
while(0);

// expected-error@+1{{use of undeclared identifier 'invalid'}}
#pragma acc parallel if(invalid) self
while(0);

// expected-error@+1{{use of undeclared identifier 'invalid'}}
#pragma acc parallel if(val2) self(invalid)
while(0);

// expected-error@+1{{use of undeclared identifier 'invalid'}}
#pragma acc parallel if(invalid) self(val1)
while(0);
}
99 changes: 99 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-self-clause.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct NoBoolConversion{};
struct BoolConversion{
operator bool();
};

template <typename T, typename U>
void BoolExpr() {
// expected-error@+1{{value of type 'NoBoolConversion' is not contextually convertible to 'bool'}}
#pragma acc parallel self (NoBoolConversion{})
while(0);
// expected-error@+2{{no member named 'NotValid' in 'NoBoolConversion'}}
// expected-note@#INST{{in instantiation of function template specialization}}
#pragma acc parallel self (T::NotValid)
while(0);

#pragma acc parallel self (BoolConversion{})
while(0);

// expected-error@+1{{value of type 'NoBoolConversion' is not contextually convertible to 'bool'}}
#pragma acc parallel self (T{})
while(0);

#pragma acc parallel self (U{})
while(0);
}

struct HasBool {
static constexpr bool B = true;
};

template<typename T>
void WarnMaybeNotUsed() {
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel self if(T::B)
while(0);

// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel self(T::B) if(T::B)
while(0);

// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel if(T::B) self
while(0);

// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel if(T::B) self(T::B)
while(0);

// We still warn in the cases of dependent failures, since the diagnostic
// happens immediately rather than during instantiation.

// expected-error@+4{{no member named 'Invalid' in 'HasBool'}}
// expected-note@#NOT_USED_INST{{in instantiation of function template specialization 'WarnMaybeNotUsed<HasBool>' requested here}}
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel self if(T::Invalid)
while(0);

// expected-error@+3{{no member named 'Invalid' in 'HasBool'}}
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel self(T::Invalid) if(T::B)
while(0);

// expected-error@+3{{no member named 'Invalid' in 'HasBool'}}
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel self(T::B) if(T::Invalid)
while(0);

// expected-error@+3{{no member named 'Invalid' in 'HasBool'}}
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel if(T::Invalid) self
while(0);

// expected-error@+3{{no member named 'Invalid' in 'HasBool'}}
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel if(T::Invalid) self(T::B)
while(0);

// expected-error@+3{{no member named 'Invalid' in 'HasBool'}}
// expected-warning@+2{{OpenACC construct 'self' has no effect when an 'if' clause evaluates to true}}
// expected-note@+1{{previous clause is here}}
#pragma acc parallel if(T::B) self(T::Invalid)
while(0);
}

void Instantiate() {
BoolExpr<NoBoolConversion, BoolConversion>(); // #INST
WarnMaybeNotUsed<HasBool>(); // #NOT_USED_INST
}
4 changes: 4 additions & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2791,6 +2791,10 @@ void OpenACCClauseEnqueue::VisitDefaultClause(const OpenACCDefaultClause &C) {}
void OpenACCClauseEnqueue::VisitIfClause(const OpenACCIfClause &C) {
Visitor.AddStmt(C.getConditionExpr());
}
void OpenACCClauseEnqueue::VisitSelfClause(const OpenACCSelfClause &C) {
if (C.hasConditionExpr())
Visitor.AddStmt(C.getConditionExpr());
}
} // namespace

void EnqueueVisitor::EnqueueChildren(const OpenACCClause *C) {
Expand Down
52 changes: 52 additions & 0 deletions clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3098,6 +3098,58 @@ TEST(TransferTest, ResultObjectLocationForCXXOperatorCallExpr) {
});
}

// Check that the `std::strong_ordering` object returned by builtin `<=>` has a
// correctly modeled result object location.
TEST(TransferTest, ResultObjectLocationForBuiltinSpaceshipOperator) {
std::string Code = R"(
namespace std {
// This is the minimal definition required to get
// `Sema::CheckComparisonCategoryType()` to accept this fake.
struct strong_ordering {
enum class ordering { less, equal, greater };
ordering o;
static const strong_ordering less;
static const strong_ordering equivalent;
static const strong_ordering equal;
static const strong_ordering greater;
};

inline constexpr strong_ordering strong_ordering::less =
{ strong_ordering::ordering::less };
inline constexpr strong_ordering strong_ordering::equal =
{ strong_ordering::ordering::equal };
inline constexpr strong_ordering strong_ordering::equivalent =
{ strong_ordering::ordering::equal };
inline constexpr strong_ordering strong_ordering::greater =
{ strong_ordering::ordering::greater };
}
void target(int i, int j) {
auto ordering = i <=> j;
// [[p]]
}
)";
using ast_matchers::binaryOperator;
using ast_matchers::hasOperatorName;
using ast_matchers::match;
using ast_matchers::selectFirst;
using ast_matchers::traverse;
runDataflow(
Code,
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
ASTContext &ASTCtx) {
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");

auto *Spaceship = selectFirst<BinaryOperator>(
"op",
match(binaryOperator(hasOperatorName("<=>")).bind("op"), ASTCtx));

EXPECT_EQ(
&Env.getResultObjectLocation(*Spaceship),
&getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "ordering"));
},
LangStandard::lang_cxx20);
}

TEST(TransferTest, ResultObjectLocationForStdInitializerListExpr) {
std::string Code = R"(
namespace std {
Expand Down
8 changes: 8 additions & 0 deletions flang/docs/Intrinsics.md
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,14 @@ CALL CO_REDUCE
CALL CO_SUM
```

### Inquiry Functions
ACCESS (GNU extension) is not supported on Windows. Otherwise:
```
CHARACTER(LEN=*) :: path = 'path/to/file'
IF (ACCESS(path, 'rwx')) &
...
```

## Non-standard intrinsics
### PGI
```
Expand Down
7 changes: 7 additions & 0 deletions flang/include/flang/Runtime/extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,12 @@ std::int64_t RTNAME(Signal)(std::int64_t number, void (*handler)(int));
// GNU extension subroutine SLEEP(SECONDS)
void RTNAME(Sleep)(std::int64_t seconds);

// GNU extension function ACCESS(NAME, MODE)
// TODO: not supported on Windows
#ifndef _WIN32
std::int64_t FORTRAN_PROCEDURE_NAME(access)(const char *name,
std::int64_t nameLength, const char *mode, std::int64_t modeLength);
#endif

} // extern "C"
#endif // FORTRAN_RUNTIME_EXTENSIONS_H_
4 changes: 2 additions & 2 deletions flang/lib/Lower/OpenMP/ClauseProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -832,8 +832,8 @@ createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc,
}

bool ClauseProcessor::processMap(
mlir::Location currentLocation, const llvm::omp::Directive &directive,
Fortran::lower::StatementContext &stmtCtx, mlir::omp::MapClauseOps &result,
mlir::Location currentLocation, Fortran::lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *mapSyms,
llvm::SmallVectorImpl<mlir::Location> *mapSymLocs,
llvm::SmallVectorImpl<mlir::Type> *mapSymTypes) const {
Expand Down
3 changes: 1 addition & 2 deletions flang/lib/Lower/OpenMP/ClauseProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ class ClauseProcessor {
// They may be used later on to create the block_arguments for some of the
// target directives that require it.
bool processMap(
mlir::Location currentLocation, const llvm::omp::Directive &directive,
Fortran::lower::StatementContext &stmtCtx,
mlir::Location currentLocation, Fortran::lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *mapSyms =
nullptr,
Expand Down
2,451 changes: 1,237 additions & 1,214 deletions flang/lib/Lower/OpenMP/OpenMP.cpp

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions flang/runtime/extensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "flang/Runtime/entry-names.h"
#include "flang/Runtime/io-api.h"
#include <chrono>
#include <cstring>
#include <ctime>
#include <signal.h>
#include <thread>
Expand Down Expand Up @@ -138,5 +139,77 @@ void RTNAME(Sleep)(std::int64_t seconds) {
std::this_thread::sleep_for(std::chrono::seconds(seconds));
}

// TODO: not supported on Windows
#ifndef _WIN32
std::int64_t FORTRAN_PROCEDURE_NAME(access)(const char *name,
std::int64_t nameLength, const char *mode, std::int64_t modeLength) {
std::int64_t ret{-1};
if (nameLength <= 0 || modeLength <= 0 || !name || !mode) {
return ret;
}

// ensure name is null terminated
char *newName{nullptr};
if (name[nameLength - 1] != '\0') {
newName = static_cast<char *>(std::malloc(nameLength + 1));
std::memcpy(newName, name, nameLength);
newName[nameLength] = '\0';
name = newName;
}

// calculate mode
bool read{false};
bool write{false};
bool execute{false};
bool exists{false};
int imode{0};

for (std::int64_t i = 0; i < modeLength; ++i) {
switch (mode[i]) {
case 'r':
read = true;
break;
case 'w':
write = true;
break;
case 'x':
execute = true;
break;
case ' ':
exists = true;
break;
default:
// invalid mode
goto cleanup;
}
}
if (!read && !write && !execute && !exists) {
// invalid mode
goto cleanup;
}

if (!read && !write && !execute) {
imode = F_OK;
} else {
if (read) {
imode |= R_OK;
}
if (write) {
imode |= W_OK;
}
if (execute) {
imode |= X_OK;
}
}
ret = access(name, imode);

cleanup:
if (newName) {
free(newName);
}
return ret;
}
#endif

} // namespace Fortran::runtime
} // extern "C"
2 changes: 1 addition & 1 deletion flang/test/Lower/OpenMP/FIR/target.f90
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,8 @@ end subroutine omp_target_implicit_bounds
!CHECK-LABEL: func.func @_QPomp_target_thread_limit() {
subroutine omp_target_thread_limit
integer :: a
!CHECK: %[[VAL_1:.*]] = arith.constant 64 : i32
!CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}}) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "a"}
!CHECK: %[[VAL_1:.*]] = arith.constant 64 : i32
!CHECK: omp.target thread_limit(%[[VAL_1]] : i32) map_entries(%[[MAP]] -> %[[ARG_0:.*]] : !fir.ref<i32>) {
!CHECK: ^bb0(%[[ARG_0]]: !fir.ref<i32>):
!$omp target map(tofrom: a) thread_limit(64)
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Lower/OpenMP/target.f90
Original file line number Diff line number Diff line change
Expand Up @@ -490,8 +490,8 @@ end subroutine omp_target_implicit_bounds
!CHECK-LABEL: func.func @_QPomp_target_thread_limit() {
subroutine omp_target_thread_limit
integer :: a
!CHECK: %[[VAL_1:.*]] = arith.constant 64 : i32
!CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}}) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "a"}
!CHECK: %[[VAL_1:.*]] = arith.constant 64 : i32
!CHECK: omp.target thread_limit(%[[VAL_1]] : i32) map_entries(%[[MAP]] -> %{{.*}} : !fir.ref<i32>) {
!CHECK: ^bb0(%{{.*}}: !fir.ref<i32>):
!$omp target map(tofrom: a) thread_limit(64)
Expand Down
4 changes: 2 additions & 2 deletions flang/test/Lower/OpenMP/use-device-ptr-to-use-device-addr.f90
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ subroutine only_use_device_ptr

!CHECK: func.func @{{.*}}mix_use_device_ptr_and_addr()
!CHECK: omp.target_data use_device_ptr({{.*}} : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) use_device_addr(%{{.*}}, %{{.*}} : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) {
!CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>):
!CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>):
subroutine mix_use_device_ptr_and_addr
use iso_c_binding
integer, pointer, dimension(:) :: array
Expand All @@ -47,7 +47,7 @@ subroutine only_use_device_addr

!CHECK: func.func @{{.*}}mix_use_device_ptr_and_addr_and_map()
!CHECK: omp.target_data map_entries(%{{.*}}, %{{.*}} : !fir.ref<i32>, !fir.ref<i32>) use_device_ptr(%{{.*}} : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) use_device_addr(%{{.*}}, %{{.*}} : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) {
!CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>):
!CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>):
subroutine mix_use_device_ptr_and_addr_and_map
use iso_c_binding
integer :: i, j
Expand Down
422 changes: 422 additions & 0 deletions flang/unittests/Runtime/AccessTest.cpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions flang/unittests/Runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_flang_unittest(FlangRuntimeTests
AccessTest.cpp
Allocatable.cpp
ArrayConstructor.cpp
BufferTest.cpp
Expand Down
15 changes: 8 additions & 7 deletions libclc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
# Generated files are given just as file names, which we must make
# absolute to the binary directory.
set( input_file ${CMAKE_CURRENT_BINARY_DIR}/${file} )
set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${file}.o" )
set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${file}.bc" )
else()
# Other files are originally relative to each SOURCE file, which are
# then make relative to the libclc root directory. We must normalize
Expand All @@ -336,7 +336,7 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
get_filename_component( abs_path ${file} ABSOLUTE BASE_DIR ${PROJECT_SOURCE_DIR} )
file( RELATIVE_PATH root_rel_path ${PROJECT_SOURCE_DIR} ${abs_path} )
set( input_file ${PROJECT_SOURCE_DIR}/${file} )
set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${root_rel_path}.o" )
set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${root_rel_path}.bc" )
endif()

get_filename_component( file_dir ${file} DIRECTORY )
Expand Down Expand Up @@ -364,7 +364,7 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
set( spv_suffix ${arch_suffix}.spv )
add_custom_command( OUTPUT ${spv_suffix}
COMMAND ${LLVM_SPIRV} ${spvflags} -o ${spv_suffix} ${builtins_link_lib}
DEPENDS ${builtins_link_lib_tgt}
DEPENDS ${builtins_link_lib}
)
add_custom_target( "prepare-${spv_suffix}" ALL DEPENDS "${spv_suffix}" )
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${spv_suffix}
Expand All @@ -376,7 +376,7 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
add_custom_command( OUTPUT ${builtins_opt_lib_tgt}.bc
COMMAND libclc::opt ${opt_flags} -o ${builtins_opt_lib_tgt}.bc
${builtins_link_lib}
DEPENDS libclc::opt ${builtins_link_lib_tgt}
DEPENDS libclc::opt ${builtins_link_lib}
)
add_custom_target( ${builtins_opt_lib_tgt}
ALL DEPENDS ${builtins_opt_lib_tgt}.bc
Expand All @@ -385,12 +385,13 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
PROPERTIES TARGET_FILE ${builtins_opt_lib_tgt}.bc
)

set( builtins_opt_lib $<TARGET_PROPERTY:${builtins_opt_lib_tgt},TARGET_FILE> )

# Add prepare target
set( obj_suffix ${arch_suffix}.bc )
add_custom_command( OUTPUT ${obj_suffix}
COMMAND prepare_builtins -o ${obj_suffix}
$<TARGET_PROPERTY:${builtins_opt_lib_tgt},TARGET_FILE>
DEPENDS ${builtins_opt_lib_tgt} prepare_builtins )
COMMAND prepare_builtins -o ${obj_suffix} ${builtins_opt_lib}
DEPENDS ${builtins_opt_lib} prepare_builtins )
add_custom_target( prepare-${obj_suffix} ALL DEPENDS ${obj_suffix} )

# nvptx-- targets don't include workitem builtins
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _Backend, class _Index, class _Brick>
_LIBCPP_HIDE_FROM_ABI optional<bool> __parallel_or(_Index __first, _Index __last, _Brick __f) {
std::atomic<bool> __found(false);
auto __ret = __pstl::__cpu_traits<_Backend>::__parallel_for(__first, __last, [__f, &__found](_Index __i, _Index __j) {
auto __ret = __pstl::__cpu_traits<_Backend>::__for_each(__first, __last, [__f, &__found](_Index __i, _Index __j) {
if (!__found.load(std::memory_order_relaxed) && __f(__i, __j)) {
__found.store(true, std::memory_order_relaxed);
__pstl::__cpu_traits<_Backend>::__cancel_execution();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ _LIBCPP_HIDE_FROM_ABI optional<__empty>
__pstl_fill(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
return __pstl::__cpu_traits<__cpu_backend_tag>::__parallel_for(
return __pstl::__cpu_traits<__cpu_backend_tag>::__for_each(
__first, __last, [&__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
[[maybe_unused]] auto __res = std::__pstl_fill<__remove_parallel_policy_t<_ExecutionPolicy>>(
__cpu_backend_tag{}, __brick_first, __brick_last, __value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ __parallel_find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool
_DifferenceType __initial_dist = __b_first ? __n : -1;
std::atomic<_DifferenceType> __extremum(__initial_dist);
// TODO: find out what is better here: parallel_for or parallel_reduce
auto __res = __pstl::__cpu_traits<_Backend>::__parallel_for(
auto __res = __pstl::__cpu_traits<_Backend>::__for_each(
__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) {
// See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of
// why using a shared variable scales fairly well in this situation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ _LIBCPP_HIDE_FROM_ABI optional<__empty>
__pstl_for_each(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Functor __func) {
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
return __pstl::__cpu_traits<__cpu_backend_tag>::__parallel_for(
return __pstl::__cpu_traits<__cpu_backend_tag>::__for_each(
__first, __last, [__func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
[[maybe_unused]] auto __res = std::__pstl_for_each<__remove_parallel_policy_t<_ExecutionPolicy>>(
__cpu_backend_tag{}, __brick_first, __brick_last, __func);
Expand Down
24 changes: 12 additions & 12 deletions libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ template <>
struct __cpu_traits<__libdispatch_backend_tag> {
template <class _RandomAccessIterator, class _Functor>
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func) {
__for_each(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func) {
return __libdispatch::__dispatch_parallel_for(
__libdispatch::__partition_chunks(__last - __first), std::move(__first), std::move(__func));
}
Expand All @@ -105,14 +105,14 @@ struct __cpu_traits<__libdispatch_backend_tag> {
typename _RandomAccessIterator3,
typename _Compare,
typename _LeafMerge>
_LIBCPP_HIDE_FROM_ABI static optional<__empty> __parallel_merge(
_RandomAccessIterator1 __first1,
_RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2,
_RandomAccessIterator2 __last2,
_RandomAccessIterator3 __result,
_Compare __comp,
_LeafMerge __leaf_merge) noexcept {
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__merge(_RandomAccessIterator1 __first1,
_RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2,
_RandomAccessIterator2 __last2,
_RandomAccessIterator3 __result,
_Compare __comp,
_LeafMerge __leaf_merge) noexcept {
__libdispatch::__chunk_partitions __partitions =
__libdispatch::__partition_chunks(std::max<ptrdiff_t>(__last1 - __first1, __last2 - __first2));

Expand Down Expand Up @@ -201,7 +201,7 @@ struct __cpu_traits<__libdispatch_backend_tag> {
}

template <class _RandomAccessIterator, class _Transform, class _Value, class _Combiner, class _Reduction>
_LIBCPP_HIDE_FROM_ABI static optional<_Value> __parallel_transform_reduce(
_LIBCPP_HIDE_FROM_ABI static optional<_Value> __transform_reduce(
_RandomAccessIterator __first,
_RandomAccessIterator __last,
_Transform __transform,
Expand Down Expand Up @@ -248,8 +248,8 @@ struct __cpu_traits<__libdispatch_backend_tag> {
}

template <class _RandomAccessIterator, class _Comp, class _LeafSort>
_LIBCPP_HIDE_FROM_ABI static optional<__empty> __parallel_stable_sort(
_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) {
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) {
const auto __size = __last - __first;
auto __partitions = __libdispatch::__partition_chunks(__size);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_merge(
__has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
__has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
__has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
auto __res = __pstl::__cpu_traits<__cpu_backend_tag>::__parallel_merge(
auto __res = __pstl::__cpu_traits<__cpu_backend_tag>::__merge(
__first1,
__last1,
__first2,
Expand Down
24 changes: 12 additions & 12 deletions libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,20 @@ template <>
struct __cpu_traits<__serial_backend_tag> {
template <class _RandomAccessIterator, class _Fp>
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
__for_each(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
__f(__first, __last);
return __empty{};
}

template <class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce>
_LIBCPP_HIDE_FROM_ABI static optional<_Tp>
__parallel_transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) {
__transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) {
return __reduce(std::move(__first), std::move(__last), std::move(__init));
}

template <class _RandomAccessIterator, class _Compare, class _LeafSort>
_LIBCPP_HIDE_FROM_ABI static optional<__empty> __parallel_stable_sort(
_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) {
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) {
__leaf_sort(__first, __last, __comp);
return __empty{};
}
Expand All @@ -60,14 +60,14 @@ struct __cpu_traits<__serial_backend_tag> {
class _RandomAccessIterator3,
class _Compare,
class _LeafMerge>
_LIBCPP_HIDE_FROM_ABI static optional<__empty> __parallel_merge(
_RandomAccessIterator1 __first1,
_RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2,
_RandomAccessIterator2 __last2,
_RandomAccessIterator3 __outit,
_Compare __comp,
_LeafMerge __leaf_merge) {
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__merge(_RandomAccessIterator1 __first1,
_RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2,
_RandomAccessIterator2 __last2,
_RandomAccessIterator3 __outit,
_Compare __comp,
_LeafMerge __leaf_merge) {
__leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp);
return __empty{};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ template <class _ExecutionPolicy, class _RandomAccessIterator, class _Comp>
_LIBCPP_HIDE_FROM_ABI optional<__empty>
__pstl_stable_sort(__cpu_backend_tag, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
return __pstl::__cpu_traits<__cpu_backend_tag>::__parallel_stable_sort(
return __pstl::__cpu_traits<__cpu_backend_tag>::__stable_sort(
__first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) {
std::stable_sort(__g_first, __g_last, __g_comp);
});
Expand Down
Loading