832 changes: 412 additions & 420 deletions clang/lib/Sema/SemaChecking.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7479,7 +7479,7 @@ ExprResult Sema::ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy,
SourceLocation RParenLoc) {
TypeSourceInfo *TInfo;
GetTypeFromParser(ParsedDestTy, &TInfo);
return SemaConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc);
return ConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc);
}

/// BuildResolvedCallExpr - Build a call to a resolved expression,
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3938,9 +3938,8 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
llvm_unreachable("Unreachable, bad result from BestViableFunction");
}

ExprResult
Sema::SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult,
bool IsDelete) {
ExprResult Sema::BuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult,
bool IsDelete) {
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
if (!getLangOpts().CPlusPlus) {
Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language)
Expand Down Expand Up @@ -6026,6 +6025,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
return false;
}
case BTT_IsLayoutCompatible: {
if (LhsT->isVariableArrayType() || RhsT->isVariableArrayType())
Self.Diag(KeyLoc, diag::err_vla_unsupported)
<< 1 << tok::kw___is_layout_compatible;
return Self.IsLayoutCompatible(LhsT, RhsT);
}
default: llvm_unreachable("not a BTT");
Expand Down
16 changes: 5 additions & 11 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//

#include "clang/AST/StmtOpenACC.h"
#include "clang/Sema/SemaOpenACC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Sema/Sema.h"

Expand All @@ -31,19 +31,14 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K,
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
if (!IsStmt)
return S.SemaRef.Diag(StartLoc, diag::err_acc_construct_appertainment)
<< K;
return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K;
break;
}
return false;
}
} // namespace

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

ASTContext &SemaOpenACC::getASTContext() const { return SemaRef.Context; }
DiagnosticsEngine &SemaOpenACC::getDiagnostics() const { return SemaRef.Diags; }
const LangOptions &SemaOpenACC::getLangOpts() const { return SemaRef.LangOpts; }
SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {}

bool SemaOpenACC::ActOnClause(OpenACCClauseKind ClauseKind,
SourceLocation StartLoc) {
Expand All @@ -53,8 +48,7 @@ bool SemaOpenACC::ActOnClause(OpenACCClauseKind ClauseKind,
// whatever it can do. This function will eventually need to start returning
// some sort of Clause AST type, but for now just return true/false based on
// success.
return SemaRef.Diag(StartLoc, diag::warn_acc_clause_unimplemented)
<< ClauseKind;
return Diag(StartLoc, diag::warn_acc_clause_unimplemented) << ClauseKind;
}
void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
SourceLocation StartLoc) {
Expand All @@ -72,7 +66,7 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
// here as these constructs do not take any arguments.
break;
default:
SemaRef.Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K;
Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K;
break;
}
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6354,6 +6354,7 @@ Sema::EvaluateConvertedConstantExpression(Expr *E, QualType T, APValue &Value,
// by this point.
assert(CE->getResultStorageKind() != ConstantResultStorageKind::None &&
"ConstantExpr has no value associated with it");
(void)CE;
} else {
E = ConstantExpr::Create(Context, Result.get(), Value);
}
Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -3890,15 +3890,14 @@ class TreeTransform {
FPOptionsOverride());

// Type-check the __builtin_shufflevector expression.
return SemaRef.SemaBuiltinShuffleVector(cast<CallExpr>(TheCall.get()));
return SemaRef.BuiltinShuffleVector(cast<CallExpr>(TheCall.get()));
}

/// Build a new convert vector expression.
ExprResult RebuildConvertVectorExpr(SourceLocation BuiltinLoc,
Expr *SrcExpr, TypeSourceInfo *DstTInfo,
SourceLocation RParenLoc) {
return SemaRef.SemaConvertVectorExpr(SrcExpr, DstTInfo,
BuiltinLoc, RParenLoc);
return SemaRef.ConvertVectorExpr(SrcExpr, DstTInfo, BuiltinLoc, RParenLoc);
}

/// Build a new template argument pack expansion.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
// was not consciously intended, and therefore it might have been unreachable.
//
// This checker uses eval::Call for modeling pure functions (functions without
// side effets), for which their `Summary' is a precise model. This avoids
// side effects), for which their `Summary' is a precise model. This avoids
// unnecessary invalidation passes. Conflicts with other checkers are unlikely
// because if the function has no other effects, other checkers would probably
// never want to improve upon the modeling done by this checker.
Expand Down
32 changes: 26 additions & 6 deletions clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
/// If true, evaluate special testing stream functions.
bool TestMode = false;

/// If true, generate failure branches for cases that are often not checked.
bool PedanticMode = false;

private:
CallDescriptionMap<FnDescription> FnDescriptions = {
{{{"fopen"}, 2}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
Expand Down Expand Up @@ -945,6 +948,10 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
}

// Add transition for the failed state.
// At write, add failure case only if "pedantic mode" is on.
if (!IsFread && !PedanticMode)
return;

NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>();
ProgramStateRef StateFailed =
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
Expand Down Expand Up @@ -1057,6 +1064,9 @@ void StreamChecker::evalFputx(const FnDescription *Desc, const CallEvent &Call,
C.addTransition(StateNotFailed);
}

if (!PedanticMode)
return;

// Add transition for the failed state. The resulting value of the file
// position indicator for the stream is indeterminate.
ProgramStateRef StateFailed = E.bindReturnValue(State, C, *EofVal);
Expand Down Expand Up @@ -1092,6 +1102,9 @@ void StreamChecker::evalFprintf(const FnDescription *Desc,
E.setStreamState(StateNotFailed, StreamState::getOpened(Desc));
C.addTransition(StateNotFailed);

if (!PedanticMode)
return;

// Add transition for the failed state. The resulting value of the file
// position indicator for the stream is indeterminate.
StateFailed = E.setStreamState(
Expand Down Expand Up @@ -1264,21 +1277,23 @@ void StreamChecker::evalFseek(const FnDescription *Desc, const CallEvent &Call,
if (!E.Init(Desc, Call, C, State))
return;

// Bifurcate the state into failed and non-failed.
// Return zero on success, -1 on error.
// Add success state.
ProgramStateRef StateNotFailed = E.bindReturnValue(State, C, 0);
ProgramStateRef StateFailed = E.bindReturnValue(State, C, -1);

// No failure: Reset the state to opened with no error.
StateNotFailed =
E.setStreamState(StateNotFailed, StreamState::getOpened(Desc));
C.addTransition(StateNotFailed);

if (!PedanticMode)
return;

// Add failure state.
// At error it is possible that fseek fails but sets none of the error flags.
// If fseek failed, assume that the file position becomes indeterminate in any
// case.
// It is allowed to set the position beyond the end of the file. EOF error
// should not occur.
ProgramStateRef StateFailed = E.bindReturnValue(State, C, -1);
StateFailed = E.setStreamState(
StateFailed, StreamState::getOpened(Desc, ErrorNone | ErrorFError, true));
C.addTransition(StateFailed, E.getFailureNoteTag(this, C));
Expand Down Expand Up @@ -1316,6 +1331,10 @@ void StreamChecker::evalFsetpos(const FnDescription *Desc,

StateNotFailed = E.setStreamState(
StateNotFailed, StreamState::getOpened(Desc, ErrorNone, false));
C.addTransition(StateNotFailed);

if (!PedanticMode)
return;

// At failure ferror could be set.
// The standards do not tell what happens with the file position at failure.
Expand All @@ -1324,7 +1343,6 @@ void StreamChecker::evalFsetpos(const FnDescription *Desc,
StateFailed = E.setStreamState(
StateFailed, StreamState::getOpened(Desc, ErrorNone | ErrorFError, true));

C.addTransition(StateNotFailed);
C.addTransition(StateFailed, E.getFailureNoteTag(this, C));
}

Expand Down Expand Up @@ -1794,7 +1812,9 @@ ProgramStateRef StreamChecker::checkPointerEscape(
//===----------------------------------------------------------------------===//

void ento::registerStreamChecker(CheckerManager &Mgr) {
Mgr.registerChecker<StreamChecker>();
auto *Checker = Mgr.registerChecker<StreamChecker>();
Checker->PedanticMode =
Mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "Pedantic");
}

bool ento::shouldRegisterStreamChecker(const CheckerManager &Mgr) {
Expand Down
1 change: 1 addition & 0 deletions clang/test/Analysis/analyzer-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtExec = 0x04
// CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtRead = 0x01
// CHECK-NEXT: alpha.security.taint.TaintPropagation:Config = ""
// CHECK-NEXT: alpha.unix.Stream:Pedantic = false
// CHECK-NEXT: apply-fixits = false
// CHECK-NEXT: assume-controlled-environment = false
// CHECK-NEXT: avoid-suppressing-null-argument-paths = false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Check the case when only the StreamChecker is enabled.
// RUN: %clang_analyze_cc1 %s \
// RUN: -analyzer-checker=core,alpha.unix.Stream \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -triple x86_64-unknown-linux \
Expand All @@ -19,6 +20,7 @@
// StdLibraryFunctionsChecker are enabled.
// RUN: %clang_analyze_cc1 %s \
// RUN: -analyzer-checker=core,alpha.unix.Stream \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true \
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
// RUN: -analyzer-config unix.StdCLibraryFunctions:DisplayLoadedSummaries=true \
// RUN: -analyzer-checker=debug.ExprInspection \
Expand Down
1 change: 1 addition & 0 deletions clang/test/Analysis/stream-errno-note.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core \
// RUN: -analyzer-checker=alpha.unix.Stream \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true \
// RUN: -analyzer-checker=unix.Errno \
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true \
Expand Down
1 change: 1 addition & 0 deletions clang/test/Analysis/stream-errno.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.Stream,unix.Errno,unix.StdCLibraryFunctions,debug.ExprInspection \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true -verify %s

#include "Inputs/system-header-simulator.h"
Expand Down
1 change: 1 addition & 0 deletions clang/test/Analysis/stream-error.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: %clang_analyze_cc1 -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=alpha.unix.Stream \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true \
// RUN: -analyzer-checker=debug.StreamTester \
// RUN: -analyzer-checker=debug.ExprInspection

Expand Down
2 changes: 2 additions & 0 deletions clang/test/Analysis/stream-note.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.Stream -analyzer-output text \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true \
// RUN: -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.Stream,unix.StdCLibraryFunctions -analyzer-output text \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true -verify=expected,stdargs %s

#include "Inputs/system-header-simulator.h"
Expand Down
95 changes: 95 additions & 0 deletions clang/test/Analysis/stream-pedantic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// RUN: %clang_analyze_cc1 -triple=x86_64-pc-linux-gnu -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=false -verify=nopedantic %s

// RUN: %clang_analyze_cc1 -triple=x86_64-pc-linux-gnu -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true -verify=pedantic %s

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

void clang_analyzer_eval(int);

void check_fwrite(void) {
char *Buf = "123456789";
FILE *Fp = tmpfile();
if (!Fp)
return;
size_t Ret = fwrite(Buf, 1, 10, Fp);
clang_analyzer_eval(Ret == 0); // nopedantic-warning {{FALSE}} \
// pedantic-warning {{FALSE}} \
// pedantic-warning {{TRUE}}
fputc('A', Fp); // pedantic-warning {{might be 'indeterminate'}}
fclose(Fp);
}

void check_fputc(void) {
FILE *Fp = tmpfile();
if (!Fp)
return;
int Ret = fputc('A', Fp);
clang_analyzer_eval(Ret == EOF); // nopedantic-warning {{FALSE}} \
// pedantic-warning {{FALSE}} \
// pedantic-warning {{TRUE}}
fputc('A', Fp); // pedantic-warning {{might be 'indeterminate'}}
fclose(Fp);
}

void check_fputs(void) {
FILE *Fp = tmpfile();
if (!Fp)
return;
int Ret = fputs("ABC", Fp);
clang_analyzer_eval(Ret == EOF); // nopedantic-warning {{FALSE}} \
// pedantic-warning {{FALSE}} \
// pedantic-warning {{TRUE}}
fputc('A', Fp); // pedantic-warning {{might be 'indeterminate'}}
fclose(Fp);
}

void check_fprintf(void) {
FILE *Fp = tmpfile();
if (!Fp)
return;
int Ret = fprintf(Fp, "ABC");
clang_analyzer_eval(Ret < 0); // nopedantic-warning {{FALSE}} \
// pedantic-warning {{FALSE}} \
// pedantic-warning {{TRUE}}
fputc('A', Fp); // pedantic-warning {{might be 'indeterminate'}}
fclose(Fp);
}

void check_fseek(void) {
FILE *Fp = tmpfile();
if (!Fp)
return;
int Ret = fseek(Fp, 0, 0);
clang_analyzer_eval(Ret == -1); // nopedantic-warning {{FALSE}} \
// pedantic-warning {{FALSE}} \
// pedantic-warning {{TRUE}}
fputc('A', Fp); // pedantic-warning {{might be 'indeterminate'}}
fclose(Fp);
}

void check_fseeko(void) {
FILE *Fp = tmpfile();
if (!Fp)
return;
int Ret = fseeko(Fp, 0, 0);
clang_analyzer_eval(Ret == -1); // nopedantic-warning {{FALSE}} \
// pedantic-warning {{FALSE}} \
// pedantic-warning {{TRUE}}
fputc('A', Fp); // pedantic-warning {{might be 'indeterminate'}}
fclose(Fp);
}

void check_fsetpos(void) {
FILE *Fp = tmpfile();
if (!Fp)
return;
fpos_t Pos;
int Ret = fsetpos(Fp, &Pos);
clang_analyzer_eval(Ret); // nopedantic-warning {{FALSE}} \
// pedantic-warning {{FALSE}} \
// pedantic-warning {{TRUE}}
fputc('A', Fp); // pedantic-warning {{might be 'indeterminate'}}
fclose(Fp);
}
3 changes: 3 additions & 0 deletions clang/test/Analysis/stream-stdlibraryfunctionargs.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.Stream,unix.StdCLibraryFunctions,debug.ExprInspection \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true -verify=stream,any %s

// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true -verify=stream,any %s

// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.StdCLibraryFunctions,debug.ExprInspection \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true -verify=stdfunc,any %s

#include "Inputs/system-header-simulator.h"
Expand Down
12 changes: 8 additions & 4 deletions clang/test/Analysis/stream.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// RUN: %clang_analyze_cc1 -triple=x86_64-pc-linux-gnu -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection -verify %s
// RUN: %clang_analyze_cc1 -triple=armv8-none-linux-eabi -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection -verify %s
// RUN: %clang_analyze_cc1 -triple=aarch64-linux-gnu -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection -verify %s
// RUN: %clang_analyze_cc1 -triple=hexagon -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection -verify %s
// RUN: %clang_analyze_cc1 -triple=x86_64-pc-linux-gnu -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true -verify %s
// RUN: %clang_analyze_cc1 -triple=armv8-none-linux-eabi -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true -verify %s
// RUN: %clang_analyze_cc1 -triple=aarch64-linux-gnu -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true -verify %s
// RUN: %clang_analyze_cc1 -triple=hexagon -analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection \
// RUN: -analyzer-config alpha.unix.Stream:Pedantic=true -verify %s

#include "Inputs/system-header-simulator.h"
#include "Inputs/system-header-simulator-for-malloc.h"
Expand Down
40 changes: 40 additions & 0 deletions clang/test/CXX/drs/dr392.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK

#if __cplusplus == 199711L
#define NOTHROW throw()
#else
#define NOTHROW noexcept(true)
#endif

namespace dr392 { // dr392: 2.8

struct A {
operator bool() NOTHROW;
};

class C {
public:
C() NOTHROW;
~C() NOTHROW;
A& get() NOTHROW { return p; }
private:
A p;
};

void f()
{
if (C().get()) {}
}

} // namespace dr392

// CHECK-LABEL: define {{.*}} void @dr392::f()()
// CHECK: call {{.*}} i1 @dr392::A::operator bool()
// CHECK: call void @dr392::C::~C()
// CHECK-LABEL: }
4 changes: 2 additions & 2 deletions clang/test/CXX/drs/dr3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,7 @@ namespace dr387 { // dr387: 2.8
}
}

// FIXME: dr388 needs codegen test
// FIXME: dr388 needs libc++abi test

namespace dr389 { // dr389: no
struct S {
Expand Down Expand Up @@ -1567,7 +1567,7 @@ namespace dr391 { // dr391: 2.8 c++11
const C<int> &c = fc();
}

// dr392 FIXME write codegen test
// dr392 is in dr392.cpp
// dr394: na

namespace dr395 { // dr395: 3.0
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CXX/drs/dr4xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ namespace dr460 { // dr460: yes
// dr464: na
// dr465: na

namespace dr466 { // dr466: no
namespace dr466 { // dr466: 2.8
typedef int I;
typedef const int CI;
typedef volatile int VI;
Expand All @@ -960,7 +960,7 @@ namespace dr466 { // dr466: no
a->CI::~CI();
a->VI::~VI();

a->CI::~VI(); // FIXME: This is invalid; CI and VI are not the same scalar type.
a->CI::~VI(); // allowed by changes to [expr.id.prim.qual]/2 introduced in P1131R2

b->~I();
b->~CI();
Expand Down
8 changes: 8 additions & 0 deletions clang/test/Driver/cuda-external-tools.cu
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@
// RUN: -Xcuda-fatbinary -bar1 -Xcuda-ptxas -foo2 -Xcuda-fatbinary -bar2 %s 2>&1 \
// RUN: | FileCheck -check-prefixes=CHECK,SM35,PTXAS-EXTRA,FATBINARY-EXTRA %s

// Check -Xcuda-ptxas with clang-cl
// RUN: %clang_cl -### -c -Xcuda-ptxas -foo1 \
// RUN: --offload-arch=sm_35 --cuda-path=%S/Inputs/CUDA/usr/local/cuda \
// RUN: -Xcuda-ptxas -foo2 %s 2>&1 \
// RUN: | FileCheck -check-prefixes=CHECK,SM35,PTXAS-EXTRA %s

// MacOS spot-checks
// RUN: %clang -### --target=x86_64-apple-macosx -O0 -c %s 2>&1 \
// RUN: --offload-arch=sm_35 --cuda-path=%S/Inputs/CUDA/usr/local/cuda \
Expand Down Expand Up @@ -140,6 +146,8 @@
// CHECK-SAME: "[[PTXFILE]]"
// PTXAS-EXTRA-SAME: "-foo1"
// PTXAS-EXTRA-SAME: "-foo2"
// CHECK-NOT: "-foo1"
// CHECK-NOT: "-foo2"
// RDC-SAME: "-c"
// CHECK-NOT: "-c"

Expand Down
30 changes: 15 additions & 15 deletions clang/test/Driver/riscv-profiles.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
// RVA20S64: "-target-feature" "+svade"
// RVA20S64: "-target-feature" "+svbare"

// RUN: %clang --target=riscv64 --target=riscv64 -### -c %s 2>&1 -march=rva22u64 \
// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rva22u64 \
// RUN: | FileCheck -check-prefix=RVA22U64 %s
// RVA22U64: "-target-feature" "+m"
// RVA22U64: "-target-feature" "+a"
Expand All @@ -76,7 +76,7 @@
// RVA22U64: "-target-feature" "+zbs"
// RVA22U64: "-target-feature" "+zkt"

// RUN: %clang --target=riscv64 --target=riscv64 -### -c %s 2>&1 -march=rva22s64 \
// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rva22s64 \
// RUN: | FileCheck -check-prefix=RVA22S64 %s
// RVA22S64: "-target-feature" "+m"
// RVA22S64: "-target-feature" "+a"
Expand Down Expand Up @@ -111,7 +111,7 @@
// RVA22S64: "-target-feature" "+svinval"
// RVA22S64: "-target-feature" "+svpbmt"

// RUN: %clang --target=riscv64 --target=riscv64 -### -c %s 2>&1 -march=rva23u64 -menable-experimental-extensions \
// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rva23u64 \
// RUN: | FileCheck -check-prefix=RVA23U64 %s
// RVA23U64: "-target-feature" "+m"
// RVA23U64: "-target-feature" "+a"
Expand All @@ -133,13 +133,13 @@
// RVA23U64: "-target-feature" "+zihintntl"
// RVA23U64: "-target-feature" "+zihintpause"
// RVA23U64: "-target-feature" "+zihpm"
// RVA23U64: "-target-feature" "+experimental-zimop"
// RVA23U64: "-target-feature" "+zimop"
// RVA23U64: "-target-feature" "+za64rs"
// RVA23U64: "-target-feature" "+zawrs"
// RVA23U64: "-target-feature" "+zfa"
// RVA23U64: "-target-feature" "+zfhmin"
// RVA23U64: "-target-feature" "+zcb"
// RVA23U64: "-target-feature" "+experimental-zcmop"
// RVA23U64: "-target-feature" "+zcmop"
// RVA23U64: "-target-feature" "+zba"
// RVA23U64: "-target-feature" "+zbb"
// RVA23U64: "-target-feature" "+zbs"
Expand Down Expand Up @@ -172,13 +172,13 @@
// RVA23S64: "-target-feature" "+zihintntl"
// RVA23S64: "-target-feature" "+zihintpause"
// RVA23S64: "-target-feature" "+zihpm"
// RVA23S64: "-target-feature" "+experimental-zimop"
// RVA23S64: "-target-feature" "+zimop"
// RVA23S64: "-target-feature" "+za64rs"
// RVA23S64: "-target-feature" "+zawrs"
// RVA23S64: "-target-feature" "+zfa"
// RVA23S64: "-target-feature" "+zfhmin"
// RVA23S64: "-target-feature" "+zcb"
// RVA23S64: "-target-feature" "+experimental-zcmop"
// RVA23S64: "-target-feature" "+zcmop"
// RVA23S64: "-target-feature" "+zba"
// RVA23S64: "-target-feature" "+zbb"
// RVA23S64: "-target-feature" "+zbs"
Expand Down Expand Up @@ -207,7 +207,7 @@
// RVA23S64: "-target-feature" "+svnapot"
// RVA23S64: "-target-feature" "+svpbmt"

// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rvb23u64 -menable-experimental-extensions \
// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rvb23u64 \
// RUN: | FileCheck -check-prefix=RVB23U64 %s
// RVB23U64: "-target-feature" "+m"
// RVB23U64: "-target-feature" "+a"
Expand All @@ -228,12 +228,12 @@
// RVB23U64: "-target-feature" "+zihintntl"
// RVB23U64: "-target-feature" "+zihintpause"
// RVB23U64: "-target-feature" "+zihpm"
// RVB23U64: "-target-feature" "+experimental-zimop"
// RVB23U64: "-target-feature" "+zimop"
// RVB23U64: "-target-feature" "+za64rs"
// RVB23U64: "-target-feature" "+zawrs"
// RVB23U64: "-target-feature" "+zfa"
// RVB23U64: "-target-feature" "+zcb"
// RVB23U64: "-target-feature" "+experimental-zcmop"
// RVB23U64: "-target-feature" "+zcmop"
// RVB23U64: "-target-feature" "+zba"
// RVB23U64: "-target-feature" "+zbb"
// RVB23U64: "-target-feature" "+zbs"
Expand Down Expand Up @@ -261,12 +261,12 @@
// RVB23S64: "-target-feature" "+zihintntl"
// RVB23S64: "-target-feature" "+zihintpause"
// RVB23S64: "-target-feature" "+zihpm"
// RVB23S64: "-target-feature" "+experimental-zimop"
// RVB23S64: "-target-feature" "+zimop"
// RVB23S64: "-target-feature" "+za64rs"
// RVB23S64: "-target-feature" "+zawrs"
// RVB23S64: "-target-feature" "+zfa"
// RVB23S64: "-target-feature" "+zcb"
// RVB23S64: "-target-feature" "+experimental-zcmop"
// RVB23S64: "-target-feature" "+zcmop"
// RVB23S64: "-target-feature" "+zba"
// RVB23S64: "-target-feature" "+zbb"
// RVB23S64: "-target-feature" "+zbs"
Expand All @@ -284,17 +284,17 @@
// RVB23S64: "-target-feature" "+svnapot"
// RVB23S64: "-target-feature" "+svpbmt"

// RUN: %clang --target=riscv32 -### -c %s 2>&1 -march=rvm23u32 -menable-experimental-extensions \
// RUN: %clang --target=riscv32 -### -c %s 2>&1 -march=rvm23u32 \
// RUN: | FileCheck -check-prefix=RVM23U32 %s
// RVM23U32: "-target-feature" "+m"
// RVM23U32: "-target-feature" "+zicbop"
// RVM23U32: "-target-feature" "+zicond"
// RVM23U32: "-target-feature" "+zicsr"
// RVM23U32: "-target-feature" "+zihintntl"
// RVM23U32: "-target-feature" "+zihintpause"
// RVM23U32: "-target-feature" "+experimental-zimop"
// RVM23U32: "-target-feature" "+zimop"
// RVM23U32: "-target-feature" "+zce"
// RVM23U32: "-target-feature" "+experimental-zcmop"
// RVM23U32: "-target-feature" "+zcmop"
// RVM23U32: "-target-feature" "+zba"
// RVM23U32: "-target-feature" "+zbb"
// RVM23U32: "-target-feature" "+zbs"
Expand Down
76 changes: 76 additions & 0 deletions clang/test/InstallAPI/binary-attributes.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
; RUN: rm -rf %t
; RUN: split-file %s %t
; RUN: mkdir -p %t/System/Library/Frameworks
; RUN: cp -r %S/Inputs/Simple/Simple.framework %t/System/Library/Frameworks/
; RUN: yaml2obj %S/Inputs/Simple/Simple.yaml -o %t/Simple

; RUN: not clang-installapi -target x86_64h-apple-macos10.12 \
; RUN: -install_name Simple -current_version 3 -compatibility_version 2 \
; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=ARCHITECTURE %s
; ARCHITECTURE: error: architectures do not match: 'x86_64h' (provided) vs 'x86_64' (found)

; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
; RUN: -install_name Simple -current_version 3 -compatibility_version 2 \
; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=INSTALL_NAME %s
; INSTALL_NAME: error: install_name does not match: 'Simple' (provided) vs '/System/Library/Frameworks/Simple.framework/Versions/A/Simple' (found)

; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
; RUN: -current_version 3 -compatibility_version 2 \
; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=CURRENT_VERSION %s
; CURRENT_VERSION: error: current_version does not match: '3' (provided) vs '1.2.3' (found)

; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
; RUN: -current_version 1.2.3 -compatibility_version 2 \
; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=COMPATIBILITY_VERSION %s
; COMPATIBILITY_VERSION: error: compatibility_version does not match: '2' (provided) vs '1' (found)

; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
; RUN: -current_version 1.2.3 -compatibility_version 1 -fapplication-extension \
; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=APPEXTSAFE %s
; APPEXTSAFE: error: ApplicationExtensionSafe flag does not match: 'true' (provided) vs 'false' (found)

; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
; RUN: -current_version 1.2.3 -compatibility_version 1 -not_for_dyld_shared_cache \
; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=SHARED_CACHE %s
; SHARED_CACHE: error: NotForDyldSharedCache flag does not match: 'true' (provided) vs 'false' (found)

; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
; RUN: -current_version 1.2.3 -compatibility_version 1 \
; RUN: -allowable_client Foo -allowable_client Bar \
; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=ALLOWABLE %s
; ALLOWABLE: error: allowable client missing from binary file: 'Foo [ x86_64 ]'

; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
; RUN: -current_version 1.2.3 -compatibility_version 1 -reexport_library %t/Foo.tbd \
; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=REEXPORT %s
; REEXPORT: error: re-exported library missing from binary file: 'Foo [ x86_64 ]'

; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
; RUN: -current_version 1.2.3 -compatibility_version 1 -umbrella Bogus \
; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=UMBRELLA %s
; UMBRELLA: error: parent umbrella missing from binary file: 'Bogus'

;--- Foo.tbd
{
"main_library": {
"install_names": [
{
"name": "Foo"
}
],
"target_info": [
{
"min_deployment": "13.0",
"target": "arm64-macos"
}
]
},
"tapi_tbd_version": 5
}
6 changes: 6 additions & 0 deletions clang/test/InstallAPI/driver-invalid-options.test
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@
// RUN: --verify-mode=Invalid -o tmp.tbd 2> %t
// RUN: FileCheck --check-prefix INVALID_VERIFY_MODE -input-file %t %s
// INVALID_VERIFY_MODE: error: invalid value 'Invalid' in '--verify-mode=Invalid'

/// Check that invalid sysroot is fatal.
// RUN: not clang-installapi -install_name Foo -target arm64-apple-ios13 \
// RUN: -isysroot /no/such/path -o tmp.tbd 2> %t
// RUN: FileCheck --check-prefix INVALID_ISYSROOT -input-file %t %s
// INVALID_ISYSROOT: error: no such sysroot directory: {{.*}}no/such/path'
638 changes: 638 additions & 0 deletions clang/test/InstallAPI/reexported-frameworks.test

Large diffs are not rendered by default.

663 changes: 663 additions & 0 deletions clang/test/InstallAPI/rpath.test

Large diffs are not rendered by default.

36 changes: 18 additions & 18 deletions clang/test/Preprocessor/riscv-target-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
// CHECK-NOT: __riscv_zcd {{.*$}}
// CHECK-NOT: __riscv_zce {{.*$}}
// CHECK-NOT: __riscv_zcf {{.*$}}
// CHECK-NOT: __riscv_zcmop {{.*$}}
// CHECK-NOT: __riscv_zcmp {{.*$}}
// CHECK-NOT: __riscv_zcmt {{.*$}}
// CHECK-NOT: __riscv_zdinx {{.*$}}
Expand All @@ -116,6 +117,7 @@
// CHECK-NOT: __riscv_zihintntl {{.*$}}
// CHECK-NOT: __riscv_zihintpause {{.*$}}
// CHECK-NOT: __riscv_zihpm {{.*$}}
// CHECK-NOT: __riscv_zimop {{.*$}}
// CHECK-NOT: __riscv_zk {{.*$}}
// CHECK-NOT: __riscv_zkn {{.*$}}
// CHECK-NOT: __riscv_zknd {{.*$}}
Expand Down Expand Up @@ -173,11 +175,9 @@
// CHECK-NOT: __riscv_zaamo {{.*$}}
// CHECK-NOT: __riscv_zalasr {{.*$}}
// CHECK-NOT: __riscv_zalrsc {{.*$}}
// CHECK-NOT: __riscv_zcmop {{.*$}}
// CHECK-NOT: __riscv_zfbfmin {{.*$}}
// CHECK-NOT: __riscv_zicfilp {{.*$}}
// CHECK-NOT: __riscv_zicfiss {{.*$}}
// CHECK-NOT: __riscv_zimop {{.*$}}
// CHECK-NOT: __riscv_ztso {{.*$}}
// CHECK-NOT: __riscv_zvfbfmin {{.*$}}
// CHECK-NOT: __riscv_zvfbfwma {{.*$}}
Expand Down Expand Up @@ -830,6 +830,14 @@
// RUN: -o - | FileCheck --check-prefix=CHECK-ZCF-EXT %s
// CHECK-ZCF-EXT: __riscv_zcf 1000000{{$}}

// RUN: %clang --target=riscv32-unknown-linux-gnu \
// RUN: -march=rv32i_zcmop1p0 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZCMOP-EXT %s
// RUN: %clang --target=riscv64-unknown-linux-gnu \
// RUN: -march=rv64i_zcmop1p0 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZCMOP-EXT %s
// CHECK-ZCMOP-EXT: __riscv_zcmop 1000000{{$}}

// RUN: %clang --target=riscv32-unknown-linux-gnu \
// RUN: -march=rv32izcmp1p0 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZCMP-EXT %s
Expand Down Expand Up @@ -1018,6 +1026,14 @@
// RUN: -o - | FileCheck --check-prefix=CHECK-ZIHPM-EXT %s
// CHECK-ZIHPM-EXT: __riscv_zihpm 2000000{{$}}

// RUN: %clang --target=riscv32-unknown-linux-gnu \
// RUN: -march=rv32i_zimop1p0 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZIMOP-EXT %s
// RUN: %clang --target=riscv64-unknown-linux-gnu \
// RUN: -march=rv64i_zimop1p0 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZIMOP-EXT %s
// CHECK-ZIMOP-EXT: __riscv_zimop 1000000{{$}}

// RUN: %clang --target=riscv32-unknown-linux-gnu \
// RUN: -march=rv32izk1p0 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZK-EXT %s
Expand Down Expand Up @@ -1561,22 +1577,6 @@
// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFILP-EXT %s
// CHECK-ZICFILP-EXT: __riscv_zicfilp 4000{{$}}

// RUN: %clang --target=riscv32 -menable-experimental-extensions \
// RUN: -march=rv32i_zimop0p1 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZIMOP-EXT %s
// RUN: %clang --target=riscv64 -menable-experimental-extensions \
// RUN: -march=rv64i_zimop0p1 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZIMOP-EXT %s
// CHECK-ZIMOP-EXT: __riscv_zimop 1000{{$}}

// RUN: %clang --target=riscv32 -menable-experimental-extensions \
// RUN: -march=rv32i_zcmop0p2 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZCMOP-EXT %s
// RUN: %clang --target=riscv64 -menable-experimental-extensions \
// RUN: -march=rv64i_zcmop0p2 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZCMOP-EXT %s
// CHECK-ZCMOP-EXT: __riscv_zcmop 2000{{$}}

// RUN: %clang --target=riscv32-unknown-linux-gnu -menable-experimental-extensions \
// RUN: -march=rv32iztso0p1 -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZTSO-EXT %s
Expand Down
10 changes: 6 additions & 4 deletions clang/test/SemaCXX/type-traits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ void is_bounded_array(int n) {
static_assert(!__is_bounded_array(cvoid *));

int t32[n];
(void)__is_bounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported for '__is_bounded_array'}}
(void)__is_bounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported in '__is_bounded_array'}}
}

void is_unbounded_array(int n) {
Expand Down Expand Up @@ -772,7 +772,7 @@ void is_unbounded_array(int n) {
static_assert(!__is_unbounded_array(cvoid *));

int t32[n];
(void)__is_unbounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported for '__is_unbounded_array'}}
(void)__is_unbounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported in '__is_unbounded_array'}}
}

void is_referenceable() {
Expand Down Expand Up @@ -1741,8 +1741,10 @@ void is_layout_compatible(int n)
static_assert(!__is_layout_compatible(unsigned char, signed char));
static_assert(__is_layout_compatible(int[], int[]));
static_assert(__is_layout_compatible(int[2], int[2]));
static_assert(!__is_layout_compatible(int[n], int[2])); // FIXME: VLAs should be rejected
static_assert(!__is_layout_compatible(int[n], int[n])); // FIXME: VLAs should be rejected
static_assert(!__is_layout_compatible(int[n], int[2]));
// expected-error@-1 {{variable length arrays are not supported in '__is_layout_compatible'}}
static_assert(!__is_layout_compatible(int[n], int[n]));
// expected-error@-1 {{variable length arrays are not supported in '__is_layout_compatible'}}
static_assert(__is_layout_compatible(int&, int&));
static_assert(!__is_layout_compatible(int&, char&));
static_assert(__is_layout_compatible(void(int), void(int)));
Expand Down
1 change: 1 addition & 0 deletions clang/tools/clang-installapi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
BinaryFormat
Support
TargetParser
TextAPI
Expand Down
27 changes: 26 additions & 1 deletion clang/tools/clang-installapi/ClangInstallAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,24 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
if (Diag->hasErrorOccurred())
return EXIT_FAILURE;

if (!Opts.DriverOpts.DylibToVerify.empty()) {
TargetList Targets;
llvm::for_each(Opts.DriverOpts.Targets,
[&](const auto &T) { Targets.push_back(T.first); });
if (!Ctx.Verifier->verifyBinaryAttrs(Targets, Ctx.BA, Ctx.Reexports,
Opts.LinkerOpts.AllowableClients,
Opts.LinkerOpts.RPaths, Ctx.FT))
return EXIT_FAILURE;
};

// Set up compilation.
std::unique_ptr<CompilerInstance> CI(new CompilerInstance());
CI->setFileManager(FM.get());
CI->createDiagnostics();
if (!CI->hasDiagnostics())
return EXIT_FAILURE;

// Execute and gather AST results.
// Execute, verify and gather AST results.
// An invocation is ran for each unique target triple and for each header
// access level.
for (const auto &[Targ, Trip] : Opts.DriverOpts.Targets) {
Expand Down Expand Up @@ -136,10 +146,25 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {

// Assign attributes for serialization.
InterfaceFile IF(Ctx.Verifier->getExports());
// Assign attributes that are the same per slice first.
for (const auto &TargetInfo : Opts.DriverOpts.Targets) {
IF.addTarget(TargetInfo.first);
IF.setFromBinaryAttrs(Ctx.BA, TargetInfo.first);
}
// Then assign potentially different attributes per slice after.
auto assignLibAttrs =
[&IF](
const auto &Attrs,
std::function<void(InterfaceFile *, StringRef, const Target &)> Add) {
for (const auto &Lib : Attrs)
for (const auto &T : IF.targets(Lib.getValue()))
Add(&IF, Lib.getKey(), T);
};

assignLibAttrs(Opts.LinkerOpts.AllowableClients,
&InterfaceFile::addAllowableClient);
assignLibAttrs(Opts.LinkerOpts.RPaths, &InterfaceFile::addRPath);
assignLibAttrs(Ctx.Reexports, &InterfaceFile::addReexportedLibrary);

// Write output file and perform CI cleanup.
if (auto Err = TextAPIWriter::writeToStream(*Out, IF, Ctx.FT)) {
Expand Down
40 changes: 37 additions & 3 deletions clang/tools/clang-installapi/InstallAPIOpts.td
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,23 @@ include "llvm/Option/OptParser.td"
/////////
// Options

// TextAPI options.
//
/// TextAPI options.
//
def filetype : Joined<["--"], "filetype=">,
HelpText<"Specify the output file type (tbd-v4 or tbd-v5)">;
def not_for_dyld_shared_cache : Joined<["-"], "not_for_dyld_shared_cache">,
HelpText<"Mark library as shared cache ineligible">;

//
/// Debugging or logging options.
//
def t: Flag<["-"], "t">,
HelpText<"Logs each dylib loaded for InstallAPI. Useful for debugging problems with search paths where the wrong library is loaded.">;

// Verification options.
//
/// Verification options.
//
def verify_against : Separate<["-"], "verify-against">,
HelpText<"Verify the specified dynamic library/framework against the headers">;
def verify_against_EQ : Joined<["--"], "verify-against=">, Alias<verify_against>;
Expand All @@ -32,7 +44,9 @@ def demangle : Flag<["--", "-"], "demangle">,
def dsym: Joined<["--"], "dsym=">,
MetaVarName<"<path>">, HelpText<"Specify dSYM path for enriched diagnostics.">;

// Additional input options.
//
/// Additional input options.
//
def extra_project_header : Separate<["-"], "extra-project-header">,
MetaVarName<"<path>">,
HelpText<"Add additional project header location for parsing">;
Expand Down Expand Up @@ -75,3 +89,23 @@ def project_umbrella_header : Separate<["-"], "project-umbrella-header">,
MetaVarName<"<path>">, HelpText<"Specify the project umbrella header location">;
def project_umbrella_header_EQ : Joined<["--"], "project-umbrella-header=">,
Alias<project_umbrella_header>;

//
/// Overidden clang options for different behavior.
//

// Clang's Xarch does not support options that require arguments.
// But is supported for InstallAPI generation.
def Xarch__ : Joined<["-"], "Xarch_">;
def allowable_client : Separate<["-"], "allowable_client">,
HelpText<"Restricts what can link against the dynamic library being created">;
def rpath: Separate<["-"], "rpath">,
HelpText<"Add path to the runpath search path list for the dynamic library being created.">;
def reexport_l : Joined<["-"], "reexport-l">,
HelpText<"Re-export the specified library">;
def reexport_library : Separate<["-"], "reexport_library">, MetaVarName<"<path>">,
HelpText<"Re-export the specified library">;
def reexport_framework : Separate<["-"], "reexport_framework">,
HelpText<"Re-export the specified framework">;


277 changes: 271 additions & 6 deletions clang/tools/clang-installapi/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
//===----------------------------------------------------------------------===//

#include "Options.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Driver/Driver.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/InstallAPI/FileList.h"
#include "clang/InstallAPI/HeaderFile.h"
#include "clang/InstallAPI/InstallAPIDiagnostic.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Support/Program.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TextAPI/DylibReader.h"
#include "llvm/TextAPI/TextAPIError.h"
#include "llvm/TextAPI/TextAPIReader.h"
#include "llvm/TextAPI/TextAPIWriter.h"

using namespace llvm;
Expand Down Expand Up @@ -137,6 +140,56 @@ bool Options::processDriverOptions(InputArgList &Args) {
return true;
}

bool Options::processInstallAPIXOptions(InputArgList &Args) {
for (arg_iterator It = Args.begin(), End = Args.end(); It != End; ++It) {
if ((*It)->getOption().matches(OPT_Xarch__)) {
if (!processXarchOption(Args, It))
return false;
}
}
// TODO: Add support for the all of the X* options installapi supports.

return true;
}

bool Options::processXarchOption(InputArgList &Args, arg_iterator Curr) {
Arg *CurrArg = *Curr;
Architecture Arch = getArchitectureFromName(CurrArg->getValue(0));
if (Arch == AK_unknown) {
Diags->Report(diag::err_drv_invalid_arch_name)
<< CurrArg->getAsString(Args);
return false;
}

auto NextIt = std::next(Curr);
if (NextIt == Args.end()) {
Diags->Report(diag::err_drv_missing_argument)
<< CurrArg->getAsString(Args) << 1;
return false;
}

// InstallAPI has a limited understanding of supported Xarch options.
// Currently this is restricted to linker inputs.
const Arg *NextArg = *NextIt;
switch (NextArg->getOption().getID()) {
case OPT_allowable_client:
case OPT_reexport_l:
case OPT_reexport_framework:
case OPT_reexport_library:
case OPT_rpath:
break;
default:
Diags->Report(diag::err_drv_invalid_argument_to_option)
<< NextArg->getAsString(Args) << CurrArg->getAsString(Args);
return false;
}

ArgToArchMap[NextArg] = Arch;
CurrArg->claim();

return true;
}

bool Options::processLinkerOptions(InputArgList &Args) {
// Handle required arguments.
if (const Arg *A = Args.getLastArg(drv::OPT_install__name))
Expand All @@ -153,6 +206,12 @@ bool Options::processLinkerOptions(InputArgList &Args) {
if (auto *Arg = Args.getLastArg(drv::OPT_compatibility__version))
LinkerOpts.CompatVersion.parse64(Arg->getValue());

if (auto *Arg = Args.getLastArg(drv::OPT_compatibility__version))
LinkerOpts.CompatVersion.parse64(Arg->getValue());

if (auto *Arg = Args.getLastArg(drv::OPT_umbrella))
LinkerOpts.ParentUmbrella = Arg->getValue();

LinkerOpts.IsDylib = Args.hasArg(drv::OPT_dynamiclib);

LinkerOpts.AppExtensionSafe = Args.hasFlag(
Expand All @@ -164,12 +223,24 @@ bool Options::processLinkerOptions(InputArgList &Args) {

if (::getenv("LD_APPLICATION_EXTENSION_SAFE") != nullptr)
LinkerOpts.AppExtensionSafe = true;

// Capture library paths.
PathSeq LibraryPaths;
for (const Arg *A : Args.filtered(drv::OPT_L)) {
LibraryPaths.emplace_back(A->getValue());
A->claim();
}

if (!LibraryPaths.empty())
LinkerOpts.LibPaths = std::move(LibraryPaths);

return true;
}

// NOTE: Do not claim any arguments, as they will be passed along for CC1
// invocations.
bool Options::processFrontendOptions(InputArgList &Args) {
// Do not claim any arguments, as they will be passed along for CC1
// invocations.
// Capture language mode.
if (auto *A = Args.getLastArgNoClaim(drv::OPT_x)) {
FEOpts.LangMode = llvm::StringSwitch<clang::Language>(A->getValue())
.Case("c", clang::Language::C)
Expand All @@ -191,6 +262,54 @@ bool Options::processFrontendOptions(InputArgList &Args) {
FEOpts.LangMode = clang::Language::ObjCXX;
}

// Capture Sysroot.
if (const Arg *A = Args.getLastArgNoClaim(drv::OPT_isysroot)) {
SmallString<PATH_MAX> Path(A->getValue());
FM->makeAbsolutePath(Path);
if (!FM->getOptionalDirectoryRef(Path)) {
Diags->Report(diag::err_missing_sysroot) << Path;
return false;
}
FEOpts.ISysroot = std::string(Path);
} else if (FEOpts.ISysroot.empty()) {
// Mirror CLANG and obtain the isysroot from the SDKROOT environment
// variable, if it wasn't defined by the command line.
if (auto *Env = ::getenv("SDKROOT")) {
if (StringRef(Env) != "/" && llvm::sys::path::is_absolute(Env) &&
FM->getOptionalFileRef(Env))
FEOpts.ISysroot = Env;
}
}

// Capture system frameworks.
// TODO: Support passing framework paths per platform.
for (const Arg *A : Args.filtered(drv::OPT_iframework))
FEOpts.SystemFwkPaths.emplace_back(A->getValue());

// Capture framework paths.
PathSeq FrameworkPaths;
for (const Arg *A : Args.filtered(drv::OPT_F))
FrameworkPaths.emplace_back(A->getValue());

if (!FrameworkPaths.empty())
FEOpts.FwkPaths = std::move(FrameworkPaths);

// Add default framework/library paths.
PathSeq DefaultLibraryPaths = {"/usr/lib", "/usr/local/lib"};
PathSeq DefaultFrameworkPaths = {"/Library/Frameworks",
"/System/Library/Frameworks"};

for (const StringRef LibPath : DefaultLibraryPaths) {
SmallString<PATH_MAX> Path(FEOpts.ISysroot);
sys::path::append(Path, LibPath);
LinkerOpts.LibPaths.emplace_back(Path.str());
}
for (const StringRef FwkPath : DefaultFrameworkPaths) {
SmallString<PATH_MAX> Path(FEOpts.ISysroot);
sys::path::append(Path, FwkPath);
FEOpts.SystemFwkPaths.emplace_back(Path.str());
}

return true;
}

Expand Down Expand Up @@ -224,6 +343,9 @@ Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
MissingArgCount, Visibility());

// Capture InstallAPI only driver options.
if (!processInstallAPIXOptions(ParsedArgs))
return {};

DriverOpts.Demangle = ParsedArgs.hasArg(OPT_demangle);

if (auto *A = ParsedArgs.getLastArg(OPT_filetype)) {
Expand Down Expand Up @@ -256,6 +378,42 @@ Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
if (const Arg *A = ParsedArgs.getLastArg(OPT_dsym))
DriverOpts.DSYMPath = A->getValue();

DriverOpts.TraceLibraryLocation = ParsedArgs.hasArg(OPT_t);

// Linker options not handled by clang driver.
LinkerOpts.OSLibNotForSharedCache =
ParsedArgs.hasArg(OPT_not_for_dyld_shared_cache);

for (const Arg *A : ParsedArgs.filtered(OPT_allowable_client)) {
LinkerOpts.AllowableClients[A->getValue()] =
ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
A->claim();
}

for (const Arg *A : ParsedArgs.filtered(OPT_reexport_l)) {
LinkerOpts.ReexportedLibraries[A->getValue()] =
ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
A->claim();
}

for (const Arg *A : ParsedArgs.filtered(OPT_reexport_library)) {
LinkerOpts.ReexportedLibraryPaths[A->getValue()] =
ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
A->claim();
}

for (const Arg *A : ParsedArgs.filtered(OPT_reexport_framework)) {
LinkerOpts.ReexportedFrameworks[A->getValue()] =
ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
A->claim();
}

for (const Arg *A : ParsedArgs.filtered(OPT_rpath)) {
LinkerOpts.RPaths[A->getValue()] =
ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
A->claim();
}

// Handle exclude & extra header directories or files.
auto handleAdditionalInputArgs = [&](PathSeq &Headers,
clang::installapi::ID OptID) {
Expand Down Expand Up @@ -336,6 +494,22 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
if (!processFrontendOptions(ArgList))
return;

// After all InstallAPI necessary arguments have been collected. Go back and
// assign values that were unknown before the clang driver opt table was used.
ArchitectureSet AllArchs;
llvm::for_each(DriverOpts.Targets,
[&AllArchs](const auto &T) { AllArchs.set(T.first.Arch); });
auto assignDefaultLibAttrs = [&AllArchs](LibAttrs &Attrs) {
for (StringMapEntry<ArchitectureSet> &Entry : Attrs)
if (Entry.getValue().empty())
Entry.setValue(AllArchs);
};
assignDefaultLibAttrs(LinkerOpts.AllowableClients);
assignDefaultLibAttrs(LinkerOpts.ReexportedFrameworks);
assignDefaultLibAttrs(LinkerOpts.ReexportedLibraries);
assignDefaultLibAttrs(LinkerOpts.ReexportedLibraryPaths);
assignDefaultLibAttrs(LinkerOpts.RPaths);

/// Force cc1 options that should always be on.
FrontendArgs = {"-fsyntax-only", "-Wprivate-extern"};

Expand All @@ -357,6 +531,89 @@ static StringRef getFrameworkNameFromInstallName(StringRef InstallName) {
return Match.back();
}

static Expected<std::unique_ptr<InterfaceFile>>
getInterfaceFile(const StringRef Filename) {
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
MemoryBuffer::getFile(Filename);
if (auto Err = BufferOrErr.getError())
return errorCodeToError(std::move(Err));

auto Buffer = std::move(*BufferOrErr);
std::unique_ptr<InterfaceFile> IF;
switch (identify_magic(Buffer->getBuffer())) {
case file_magic::macho_dynamically_linked_shared_lib:
LLVM_FALLTHROUGH;
case file_magic::macho_dynamically_linked_shared_lib_stub:
LLVM_FALLTHROUGH;
case file_magic::macho_universal_binary:
return DylibReader::get(Buffer->getMemBufferRef());
break;
case file_magic::tapi_file:
return TextAPIReader::get(Buffer->getMemBufferRef());
default:
return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat,
"unsupported library file format");
}
llvm_unreachable("unexpected failure in getInterface");
}

std::pair<LibAttrs, ReexportedInterfaces> Options::getReexportedLibraries() {
LibAttrs Reexports;
ReexportedInterfaces ReexportIFs;
auto AccumulateReexports = [&](StringRef Path, const ArchitectureSet &Archs) {
auto ReexportIFOrErr = getInterfaceFile(Path);
if (!ReexportIFOrErr)
return false;
std::unique_ptr<InterfaceFile> Reexport = std::move(*ReexportIFOrErr);
StringRef InstallName = Reexport->getInstallName();
assert(!InstallName.empty() && "Parse error for install name");
Reexports.insert({InstallName, Archs});
ReexportIFs.emplace_back(std::move(*Reexport));
return true;
};

// Populate search paths by looking at user paths before system ones.
PathSeq FwkSearchPaths(FEOpts.FwkPaths.begin(), FEOpts.FwkPaths.end());
// FIXME: System framework paths need to reset if installapi is invoked with
// different platforms.
FwkSearchPaths.insert(FwkSearchPaths.end(), FEOpts.SystemFwkPaths.begin(),
FEOpts.SystemFwkPaths.end());

for (const StringMapEntry<ArchitectureSet> &Lib :
LinkerOpts.ReexportedLibraries) {
std::string Name = "lib" + Lib.getKey().str() + ".dylib";
std::string Path = findLibrary(Name, *FM, {}, LinkerOpts.LibPaths, {});
if (Path.empty()) {
Diags->Report(diag::err_cannot_find_reexport) << true << Lib.getKey();
return {};
}
if (DriverOpts.TraceLibraryLocation)
errs() << Path << "\n";

AccumulateReexports(Path, Lib.getValue());
}

for (const StringMapEntry<ArchitectureSet> &Lib :
LinkerOpts.ReexportedLibraryPaths)
AccumulateReexports(Lib.getKey(), Lib.getValue());

for (const StringMapEntry<ArchitectureSet> &Lib :
LinkerOpts.ReexportedFrameworks) {
std::string Name = (Lib.getKey() + ".framework/" + Lib.getKey()).str();
std::string Path = findLibrary(Name, *FM, FwkSearchPaths, {}, {});
if (Path.empty()) {
Diags->Report(diag::err_cannot_find_reexport) << false << Lib.getKey();
return {};
}
if (DriverOpts.TraceLibraryLocation)
errs() << Path << "\n";

AccumulateReexports(Path, Lib.getValue());
}

return {std::move(Reexports), std::move(ReexportIFs)};
}

InstallAPIContext Options::createContext() {
InstallAPIContext Ctx;
Ctx.FM = FM;
Expand All @@ -369,10 +626,17 @@ InstallAPIContext Options::createContext() {
Ctx.BA.CurrentVersion = LinkerOpts.CurrentVersion;
Ctx.BA.CompatVersion = LinkerOpts.CompatVersion;
Ctx.BA.AppExtensionSafe = LinkerOpts.AppExtensionSafe;
Ctx.BA.ParentUmbrella = LinkerOpts.ParentUmbrella;
Ctx.BA.OSLibNotForSharedCache = LinkerOpts.OSLibNotForSharedCache;
Ctx.FT = DriverOpts.OutFT;
Ctx.OutputLoc = DriverOpts.OutputPath;
Ctx.LangMode = FEOpts.LangMode;

auto [Reexports, ReexportedIFs] = getReexportedLibraries();
if (Diags->hasErrorOccurred())
return Ctx;
Ctx.Reexports = Reexports;

// Attempt to find umbrella headers by capturing framework name.
StringRef FrameworkName;
if (!LinkerOpts.IsDylib)
Expand Down Expand Up @@ -532,13 +796,14 @@ InstallAPIContext Options::createContext() {
Expected<Records> Slices =
DylibReader::readFile((*Buffer)->getMemBufferRef(), PO);
if (auto Err = Slices.takeError()) {
Diags->Report(diag::err_cannot_open_file) << DriverOpts.DylibToVerify;
Diags->Report(diag::err_cannot_open_file)
<< DriverOpts.DylibToVerify << std::move(Err);
return Ctx;
}

Ctx.Verifier = std::make_unique<DylibVerifier>(
std::move(*Slices), Diags, DriverOpts.VerifyMode, DriverOpts.Demangle,
DriverOpts.DSYMPath);
std::move(*Slices), std::move(ReexportedIFs), Diags,
DriverOpts.VerifyMode, DriverOpts.Demangle, DriverOpts.DSYMPath);
return Ctx;
}

Expand Down
43 changes: 42 additions & 1 deletion clang/tools/clang-installapi/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include "llvm/Option/Option.h"
#include "llvm/Support/Program.h"
#include "llvm/TargetParser/Triple.h"
#include <set>
#include <string>
#include <vector>

Expand Down Expand Up @@ -81,9 +80,30 @@ struct DriverOptions {

/// \brief Print verbose output.
bool Verbose = false;

/// \brief Log libraries loaded.
bool TraceLibraryLocation = false;
};

struct LinkerOptions {
/// \brief List of allowable clients to use for the dynamic library.
LibAttrs AllowableClients;

/// \brief List of reexported libraries to use for the dynamic library.
LibAttrs ReexportedLibraries;

/// \brief List of reexported libraries to use for the dynamic library.
LibAttrs ReexportedLibraryPaths;

/// \brief List of reexported frameworks to use for the dynamic library.
LibAttrs ReexportedFrameworks;

/// \brief List of rpaths to use for the dynamic library.
LibAttrs RPaths;

/// \brief Additional library search paths.
PathSeq LibPaths;

/// \brief The install name to use for the dynamic library.
std::string InstallName;

Expand All @@ -93,25 +113,43 @@ struct LinkerOptions {
/// \brief The compatibility version to use for the dynamic library.
PackedVersion CompatVersion;

/// \brief Name of the umbrella library.
std::string ParentUmbrella;

/// \brief Is application extension safe.
bool AppExtensionSafe = false;

/// \brief Set if we should scan for a dynamic library and not a framework.
bool IsDylib = false;

/// \brief Is an OS library that is not shared cache eligible.
bool OSLibNotForSharedCache = false;
};

struct FrontendOptions {
/// \brief The language mode to parse headers in.
Language LangMode = Language::ObjC;

/// \brief The sysroot to search for SDK headers or libraries.
std::string ISysroot;

/// \brief Additional framework search paths.
PathSeq FwkPaths;

/// \brief Additional SYSTEM framework search paths.
PathSeq SystemFwkPaths;
};

using arg_iterator = llvm::opt::arg_iterator<llvm::opt::Arg **>;
class Options {
private:
bool processDriverOptions(llvm::opt::InputArgList &Args);
bool processLinkerOptions(llvm::opt::InputArgList &Args);
bool processFrontendOptions(llvm::opt::InputArgList &Args);
std::vector<const char *>
processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args);
bool processInstallAPIXOptions(llvm::opt::InputArgList &Args);
bool processXarchOption(llvm::opt::InputArgList &Args, arg_iterator Curr);

public:
/// The various options grouped together.
Expand All @@ -136,9 +174,12 @@ class Options {
bool addFilePaths(llvm::opt::InputArgList &Args, PathSeq &Headers,
llvm::opt::OptSpecifier ID);

std::pair<LibAttrs, ReexportedInterfaces> getReexportedLibraries();

DiagnosticsEngine *Diags;
FileManager *FM;
std::vector<std::string> FrontendArgs;
llvm::DenseMap<const llvm::opt::Arg *, Architecture> ArgToArchMap;
};

enum ID {
Expand Down
1 change: 1 addition & 0 deletions clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, const ArgList &Args) {
StringRef OptLevel = Args.getLastArgValue(OPT_opt_level, "O2");
SmallVector<StringRef, 16> CmdArgs{
*ClangPath,
"--no-default-config",
"-o",
*TempFileOrErr,
Args.MakeArgString("--target=" + Triple.getTriple()),
Expand Down
10 changes: 10 additions & 0 deletions clang/unittests/Format/FormatTestTableGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,16 @@ TEST_F(FormatTestTableGen, MultiClass) {
"}\n");
}

TEST_F(FormatTestTableGen, MultiClassesWithPasteOperator) {
// This is a sensitive example for the handling of the paste operators in
// brace type calculation.
verifyFormat("multiclass MultiClass1<int i> {\n"
" def : Def#x<i>;\n"
" def : Def#y<i>;\n"
"}\n"
"multiclass MultiClass2<int i> { def : Def#x<i>; }\n");
}

TEST_F(FormatTestTableGen, Defm) {
verifyFormat("defm : Multiclass<0>;\n");

Expand Down
2 changes: 1 addition & 1 deletion clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

#include <system_error>

#if defined(_AIX)
#if defined(_AIX) || defined(__MVS__)
#define CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
#endif

Expand Down
7 changes: 3 additions & 4 deletions clang/utils/TableGen/MveEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@ class ACLEIntrinsic {
llvm::APInt ArgTypeRange = llvm::APInt::getMaxValue(ArgTypeBits).zext(128);
llvm::APInt ActualRange = (hi-lo).trunc(64).sext(128);
if (ActualRange.ult(ArgTypeRange))
SemaChecks.push_back("SemaBuiltinConstantArgRange(TheCall, " + Index +
SemaChecks.push_back("BuiltinConstantArgRange(TheCall, " + Index +
", " + signedHexLiteral(lo) + ", " +
signedHexLiteral(hi) + ")");

Expand All @@ -942,9 +942,8 @@ class ACLEIntrinsic {
}
Suffix = (Twine(", ") + Arg).str();
}
SemaChecks.push_back((Twine("SemaBuiltinConstantArg") +
IA.ExtraCheckType + "(TheCall, " + Index +
Suffix + ")")
SemaChecks.push_back((Twine("BuiltinConstantArg") + IA.ExtraCheckType +
"(TheCall, " + Index + Suffix + ")")
.str());
}

Expand Down
4 changes: 2 additions & 2 deletions clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -2392,7 +2392,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/392.html">392</a></td>
<td>CD1</td>
<td>Use of full expression lvalue before temporary destruction</td>
<td class="unknown" align="center">Unknown</td>
<td class="full" align="center">Clang 2.8</td>
</tr>
<tr id="393">
<td><a href="https://cplusplus.github.io/CWG/issues/393.html">393</a></td>
Expand Down Expand Up @@ -2836,7 +2836,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/466.html">466</a></td>
<td>CD1</td>
<td>cv-qualifiers on pseudo-destructor type</td>
<td class="none" align="center">No</td>
<td class="full" align="center">Clang 2.8</td>
</tr>
<tr id="467">
<td><a href="https://cplusplus.github.io/CWG/issues/467.html">467</a></td>
Expand Down
8 changes: 4 additions & 4 deletions compiler-rt/lib/scudo/standalone/report_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ namespace scudo {
// Fatal internal map() error (potentially OOM related).
void NORETURN reportMapError(uptr SizeIfOOM) {
ScopedString Error;
Error.append("Scudo ERROR: internal map failure");
if (SizeIfOOM) {
Error.append(" (NO MEMORY) requesting %zuKB", SizeIfOOM >> 10);
}
Error.append("Scudo ERROR: internal map failure (error desc=%s)",
strerror(errno));
if (SizeIfOOM)
Error.append(" requesting %zuKB", SizeIfOOM >> 10);
Error.append("\n");
reportRawError(Error.data());
}
Expand Down
25 changes: 25 additions & 0 deletions compiler-rt/lib/scudo/standalone/tests/report_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,28 @@ TEST(ScudoReportDeathTest, CSpecific) {
EXPECT_DEATH(scudo::reportInvalidAlignedAllocAlignment(123, 456),
"Scudo ERROR.*123.*456");
}

#if SCUDO_LINUX || SCUDO_TRUSTY || SCUDO_ANDROID
#include "report_linux.h"

#include <errno.h>
#include <sys/mman.h>

TEST(ScudoReportDeathTest, Linux) {
errno = ENOMEM;
EXPECT_DEATH(scudo::reportMapError(),
"Scudo ERROR:.*internal map failure \\(error desc=.*\\)\\s*$");
errno = ENOMEM;
EXPECT_DEATH(scudo::reportMapError(1024U),
"Scudo ERROR:.*internal map failure \\(error desc=.*\\) "
"requesting 1KB\\s*$");
errno = ENOMEM;
EXPECT_DEATH(scudo::reportUnmapError(0x1000U, 100U),
"Scudo ERROR:.*internal unmap failure \\(error desc=.*\\) Addr "
"0x1000 Size 100\\s*$");
errno = ENOMEM;
EXPECT_DEATH(scudo::reportProtectError(0x1000U, 100U, PROT_READ),
"Scudo ERROR:.*internal protect failure \\(error desc=.*\\) "
"Addr 0x1000 Size 100 Prot 1\\s*$");
}
#endif
5 changes: 5 additions & 0 deletions compiler-rt/test/fuzzer/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True, msan_enabled=False):
if "windows" in config.available_features:
extra_cmd = extra_cmd + " -D_DISABLE_VECTOR_ANNOTATION -D_DISABLE_STRING_ANNOTATION"

if "darwin" in config.available_features and getattr(
config, "darwin_linker_version", None
):
extra_cmd = extra_cmd + " -mlinker-version=" + config.darwin_linker_version

return " ".join(
[
compiler_cmd,
Expand Down
18 changes: 10 additions & 8 deletions flang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,13 @@ if (FLANG_STANDALONE_BUILD)
mark_as_advanced(LLVM_ENABLE_ASSERTIONS)
endif()

# We need a pre-built/installed version of LLVM.
find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}")
# If the user specifies a relative path to LLVM_DIR, the calls to include
# LLVM modules fail. Append the absolute path to LLVM_DIR instead.
get_filename_component(LLVM_DIR_ABSOLUTE ${LLVM_DIR} REALPATH)
get_filename_component(LLVM_DIR_ABSOLUTE ${LLVM_DIR}
REALPATH BASE_DIR ${CMAKE_CURRENT_BINARY_DIR})
list(APPEND CMAKE_MODULE_PATH ${LLVM_DIR_ABSOLUTE})
# We need a pre-built/installed version of LLVM.
find_package(LLVM REQUIRED HINTS "${LLVM_DIR_ABSOLUTE}")

# Users might specify a path to CLANG_DIR that's:
# * a full path, or
Expand All @@ -97,7 +98,7 @@ if (FLANG_STANDALONE_BUILD)
CLANG_DIR_ABSOLUTE
${CLANG_DIR}
REALPATH
${CMAKE_CURRENT_SOURCE_DIR})
BASE_DIR ${CMAKE_CURRENT_BINARY_DIR})
list(APPEND CMAKE_MODULE_PATH ${CLANG_DIR_ABSOLUTE})

# TODO: Remove when libclangDriver is lifted out of Clang
Expand All @@ -124,13 +125,14 @@ if (FLANG_STANDALONE_BUILD)
include(AddClang)

include(TableGen)
find_package(MLIR REQUIRED CONFIG)
# Use SYSTEM for the same reasons as for LLVM includes
include_directories(SYSTEM ${MLIR_INCLUDE_DIRS})
# If the user specifies a relative path to MLIR_DIR, the calls to include
# MLIR modules fail. Append the absolute path to MLIR_DIR instead.
get_filename_component(MLIR_DIR_ABSOLUTE ${MLIR_DIR} REALPATH)
get_filename_component(MLIR_DIR_ABSOLUTE ${MLIR_DIR}
REALPATH BASE_DIR ${CMAKE_CURRENT_BINARY_DIR})
list(APPEND CMAKE_MODULE_PATH ${MLIR_DIR_ABSOLUTE})
find_package(MLIR REQUIRED CONFIG HINTS ${MLIR_DIR_ABSOLUTE})
# Use SYSTEM for the same reasons as for LLVM includes
include_directories(SYSTEM ${MLIR_INCLUDE_DIRS})
include(AddMLIR)
find_program(MLIR_TABLEGEN_EXE "mlir-tblgen" ${LLVM_TOOLS_BINARY_DIR}
NO_DEFAULT_PATH)
Expand Down
132 changes: 132 additions & 0 deletions flang/cmake/modules/AddFlangOffloadRuntime.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
option(FLANG_EXPERIMENTAL_CUDA_RUNTIME
"Compile Fortran runtime as CUDA sources (experimental)" OFF
)

set(FLANG_LIBCUDACXX_PATH "" CACHE PATH "Path to libcu++ package installation")

set(FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD "off" CACHE STRING
"Compile Fortran runtime as OpenMP target offload sources (experimental). Valid options are 'off', 'host_device', 'nohost'")

set(FLANG_OMP_DEVICE_ARCHITECTURES "all" CACHE STRING
"List of OpenMP device architectures to be used to compile the Fortran runtime (e.g. 'gfx1103;sm_90')")

macro(enable_cuda_compilation files)
if (FLANG_EXPERIMENTAL_CUDA_RUNTIME)
if (BUILD_SHARED_LIBS)
message(FATAL_ERROR
"BUILD_SHARED_LIBS is not supported for CUDA build of Fortran runtime"
)
endif()

enable_language(CUDA)

# TODO: figure out how to make target property CUDA_SEPARABLE_COMPILATION
# work, and avoid setting CMAKE_CUDA_SEPARABLE_COMPILATION.
set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)

# Treat all supported sources as CUDA files.
set_source_files_properties(${files} PROPERTIES LANGUAGE CUDA)
set(CUDA_COMPILE_OPTIONS)
if ("${CMAKE_CUDA_COMPILER_ID}" MATCHES "Clang")
# Allow varargs.
set(CUDA_COMPILE_OPTIONS
-Xclang -fcuda-allow-variadic-functions
)
endif()
if ("${CMAKE_CUDA_COMPILER_ID}" MATCHES "NVIDIA")
set(CUDA_COMPILE_OPTIONS
--expt-relaxed-constexpr
# Disable these warnings:
# 'long double' is treated as 'double' in device code
-Xcudafe --diag_suppress=20208
-Xcudafe --display_error_number
)
endif()
set_source_files_properties(${files} PROPERTIES COMPILE_OPTIONS
"${CUDA_COMPILE_OPTIONS}"
)

if (EXISTS "${FLANG_LIBCUDACXX_PATH}/include")
# When using libcudacxx headers files, we have to use them
# for all files of F18 runtime.
include_directories(AFTER ${FLANG_LIBCUDACXX_PATH}/include)
add_compile_definitions(RT_USE_LIBCUDACXX=1)
endif()
endif()
endmacro()

macro(enable_omp_offload_compilation files)
if (NOT FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD STREQUAL "off")
# 'host_device' build only works with Clang compiler currently.
# The build is done with the CMAKE_C/CXX_COMPILER, i.e. it does not use
# the in-tree built Clang. We may have a mode that would use the in-tree
# built Clang.
#
# 'nohost' is supposed to produce an LLVM Bitcode library,
# and it has to be done with a C/C++ compiler producing LLVM Bitcode
# compatible with the LLVM toolchain version distributed with the Flang
# compiler.
# In general, the in-tree built Clang should be used for 'nohost' build.
# Note that 'nohost' build does not produce the host version of Flang
# runtime library, so there will be two separate distributable objects.
# 'nohost' build is a TODO.

if (NOT FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD STREQUAL "host_device")
message(FATAL_ERROR "Unsupported OpenMP offload build of Flang runtime")
endif()
if (BUILD_SHARED_LIBS)
message(FATAL_ERROR
"BUILD_SHARED_LIBS is not supported for OpenMP offload build of Fortran runtime"
)
endif()

if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND
"${CMAKE_C_COMPILER_ID}" MATCHES "Clang")

set(all_amdgpu_architectures
"gfx700;gfx701;gfx801;gfx803;gfx900;gfx902;gfx906"
"gfx908;gfx90a;gfx90c;gfx940;gfx1010;gfx1030"
"gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036"
"gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151"
)
set(all_nvptx_architectures
"sm_35;sm_37;sm_50;sm_52;sm_53;sm_60;sm_61;sm_62"
"sm_70;sm_72;sm_75;sm_80;sm_86;sm_89;sm_90"
)
set(all_gpu_architectures
"${all_amdgpu_architectures};${all_nvptx_architectures}"
)
# TODO: support auto detection on the build system.
if (FLANG_OMP_DEVICE_ARCHITECTURES STREQUAL "all")
set(FLANG_OMP_DEVICE_ARCHITECTURES ${all_gpu_architectures})
endif()
list(REMOVE_DUPLICATES FLANG_OMP_DEVICE_ARCHITECTURES)

string(REPLACE ";" "," compile_for_architectures
"${FLANG_OMP_DEVICE_ARCHITECTURES}"
)

set(OMP_COMPILE_OPTIONS
-fopenmp
-fvisibility=hidden
-fopenmp-cuda-mode
--offload-arch=${compile_for_architectures}
# Force LTO for the device part.
-foffload-lto
)
set_source_files_properties(${files} PROPERTIES COMPILE_OPTIONS
"${OMP_COMPILE_OPTIONS}"
)

# Enable "declare target" in the source code.
set_source_files_properties(${files}
PROPERTIES COMPILE_DEFINITIONS OMP_OFFLOAD_BUILD
)
else()
message(FATAL_ERROR
"Flang runtime build is not supported for these compilers:\n"
"CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}\n"
"CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}")
endif()
endif()
endmacro()
4 changes: 3 additions & 1 deletion flang/docs/Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@ end
converted. BOZ literals are interpreted as default INTEGER only
when they appear as the first items of array constructors with no
explicit type. Otherwise, they generally cannot be used if the type would
not be known (e.g., `IAND(X'1',X'2')`).
not be known (e.g., `IAND(X'1',X'2')`, or as arguments of `DIM`, `MOD`,
`MODULO`, and `SIGN`. Note that while other compilers may accept such usages,
the type resolution of such BOZ literals usages is highly non portable).
* BOZ literals can also be used as REAL values in some contexts where the
type is unambiguous, such as initializations of REAL parameters.
* EQUIVALENCE of numeric and character sequences (a ubiquitous extension),
Expand Down
16 changes: 11 additions & 5 deletions flang/include/flang/Evaluate/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -1227,18 +1227,24 @@ bool CheckForCoindexedObject(parser::ContextualMessages &,
const std::optional<ActualArgument> &, const std::string &procName,
const std::string &argName);

/// Check if any of the symbols part of the expression has a cuda data
/// attribute.
inline bool HasCUDAAttrs(const Expr<SomeType> &expr) {
// Get the number of distinct symbols with CUDA attribute in the expression.
template <typename A> inline int GetNbOfCUDASymbols(const A &expr) {
semantics::UnorderedSymbolSet symbols;
for (const Symbol &sym : CollectSymbols(expr)) {
if (const auto *details =
sym.GetUltimate().detailsIf<semantics::ObjectEntityDetails>()) {
if (details->cudaDataAttr()) {
return true;
symbols.insert(sym);
}
}
}
return false;
return symbols.size();
}

// Check if any of the symbols part of the expression has a CUDA data
// attribute.
template <typename A> inline bool HasCUDAAttrs(const A &expr) {
return GetNbOfCUDASymbols(expr) > 0;
}

/// Check if the expression is a mix of host and device variables that require
Expand Down
13 changes: 13 additions & 0 deletions flang/include/flang/Optimizer/Builder/FIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,22 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
mlir::Value createNullConstant(mlir::Location loc, mlir::Type ptrType = {});

/// Create an integer constant of type \p type and value \p i.
/// Should not be used with negative values with integer types of more
/// than 64 bits.
mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType,
std::int64_t i);

/// Create an integer of \p integerType where all the bits have been set to
/// ones. Safe to use regardless of integerType bitwidth.
mlir::Value createAllOnesInteger(mlir::Location loc, mlir::Type integerType);

/// Create -1 constant of \p integerType. Safe to use regardless of
/// integerType bitwidth.
mlir::Value createMinusOneInteger(mlir::Location loc,
mlir::Type integerType) {
return createAllOnesInteger(loc, integerType);
}

/// Create a real constant from an integer value.
mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType,
llvm::APFloat::integerPart val);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- runtime/freestanding-tools.h ----------------------------*- C++ -*-===//
//===-- include/flang/Runtime/freestanding-tools.h --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
10 changes: 8 additions & 2 deletions flang/lib/Decimal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,17 @@ endif()
# avoid an unwanted dependency on libstdc++.so.
add_definitions(-U_GLIBCXX_ASSERTIONS)

add_flang_library(FortranDecimal INSTALL_WITH_TOOLCHAIN
set(sources
binary-to-decimal.cpp
decimal-to-binary.cpp
)

include(AddFlangOffloadRuntime)
enable_cuda_compilation("${sources}")
enable_omp_offload_compilation("${sources}")

add_flang_library(FortranDecimal INSTALL_WITH_TOOLCHAIN ${sources})

if (DEFINED MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
add_flang_library(FortranDecimal.static INSTALL_WITH_TOOLCHAIN
Expand All @@ -77,4 +83,4 @@ if (DEFINED MSVC)
)
add_dependencies(FortranDecimal FortranDecimal.static FortranDecimal.dynamic
FortranDecimal.static_dbg FortranDecimal.dynamic_dbg)
endif()
endif()
69 changes: 38 additions & 31 deletions flang/lib/Decimal/big-radix-floating-point.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#include <limits>
#include <type_traits>

// Some environments, viz. glibc 2.17, allow the macro HUGE
// to leak out of <math.h>.
#undef HUGE

namespace Fortran::decimal {

static constexpr std::uint64_t TenToThe(int power) {
Expand Down Expand Up @@ -64,30 +68,30 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
static constexpr int maxDigits{3 - minLog2AnyBit / log10Radix};

public:
explicit BigRadixFloatingPointNumber(
explicit RT_API_ATTRS BigRadixFloatingPointNumber(
enum FortranRounding rounding = RoundNearest)
: rounding_{rounding} {}

// Converts a binary floating point value.
explicit BigRadixFloatingPointNumber(
explicit RT_API_ATTRS BigRadixFloatingPointNumber(
Real, enum FortranRounding = RoundNearest);

BigRadixFloatingPointNumber &SetToZero() {
RT_API_ATTRS BigRadixFloatingPointNumber &SetToZero() {
isNegative_ = false;
digits_ = 0;
exponent_ = 0;
return *this;
}

// Converts decimal floating-point to binary.
ConversionToBinaryResult<PREC> ConvertToBinary();
RT_API_ATTRS ConversionToBinaryResult<PREC> ConvertToBinary();

// Parses and converts to binary. Handles leading spaces,
// "NaN", & optionally-signed "Inf". Does not skip internal
// spaces.
// The argument is a reference to a pointer that is left
// pointing to the first character that wasn't parsed.
ConversionToBinaryResult<PREC> ConvertToBinary(
RT_API_ATTRS ConversionToBinaryResult<PREC> ConvertToBinary(
const char *&, const char *end = nullptr);

// Formats a decimal floating-point number to a user buffer.
Expand All @@ -96,7 +100,7 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
// after the last digit; the effective decimal exponent is
// returned as part of the result structure so that it can be
// formatted by the client.
ConversionToDecimalResult ConvertToDecimal(
RT_API_ATTRS ConversionToDecimalResult ConvertToDecimal(
char *, std::size_t, enum DecimalConversionFlags, int digits) const;

// Discard decimal digits not needed to distinguish this value
Expand All @@ -108,21 +112,22 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
// This minimization necessarily assumes that the value will be
// emitted and read back into the same (or less precise) format
// with default rounding to the nearest value.
void Minimize(
RT_API_ATTRS void Minimize(
BigRadixFloatingPointNumber &&less, BigRadixFloatingPointNumber &&more);

template <typename STREAM> STREAM &Dump(STREAM &) const;

private:
BigRadixFloatingPointNumber(const BigRadixFloatingPointNumber &that)
RT_API_ATTRS BigRadixFloatingPointNumber(
const BigRadixFloatingPointNumber &that)
: digits_{that.digits_}, exponent_{that.exponent_},
isNegative_{that.isNegative_}, rounding_{that.rounding_} {
for (int j{0}; j < digits_; ++j) {
digit_[j] = that.digit_[j];
}
}

bool IsZero() const {
RT_API_ATTRS bool IsZero() const {
// Don't assume normalization.
for (int j{0}; j < digits_; ++j) {
if (digit_[j] != 0) {
Expand All @@ -136,13 +141,13 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
// (When this happens during decimal-to-binary conversion,
// there are more digits in the input string than can be
// represented precisely.)
bool IsFull() const {
RT_API_ATTRS bool IsFull() const {
return digits_ == digitLimit_ && digit_[digits_ - 1] >= radix / 10;
}

// Sets *this to an unsigned integer value.
// Returns any remainder.
template <typename UINT> UINT SetTo(UINT n) {
template <typename UINT> RT_API_ATTRS UINT SetTo(UINT n) {
static_assert(
std::is_same_v<UINT, common::uint128_t> || std::is_unsigned_v<UINT>);
SetToZero();
Expand All @@ -169,7 +174,7 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
}
}

int RemoveLeastOrderZeroDigits() {
RT_API_ATTRS int RemoveLeastOrderZeroDigits() {
int remove{0};
if (digits_ > 0 && digit_[0] == 0) {
while (remove < digits_ && digit_[remove] == 0) {
Expand All @@ -193,25 +198,25 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
return remove;
}

void RemoveLeadingZeroDigits() {
RT_API_ATTRS void RemoveLeadingZeroDigits() {
while (digits_ > 0 && digit_[digits_ - 1] == 0) {
--digits_;
}
}

void Normalize() {
RT_API_ATTRS void Normalize() {
RemoveLeadingZeroDigits();
exponent_ += RemoveLeastOrderZeroDigits() * log10Radix;
}

// This limited divisibility test only works for even divisors of the radix,
// which is fine since it's only ever used with 2 and 5.
template <int N> bool IsDivisibleBy() const {
template <int N> RT_API_ATTRS bool IsDivisibleBy() const {
static_assert(N > 1 && radix % N == 0, "bad modulus");
return digits_ == 0 || (digit_[0] % N) == 0;
}

template <unsigned DIVISOR> int DivideBy() {
template <unsigned DIVISOR> RT_API_ATTRS int DivideBy() {
Digit remainder{0};
for (int j{digits_ - 1}; j >= 0; --j) {
Digit q{digit_[j] / DIVISOR};
Expand All @@ -222,7 +227,7 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
return remainder;
}

void DivideByPowerOfTwo(int twoPow) { // twoPow <= log10Radix
RT_API_ATTRS void DivideByPowerOfTwo(int twoPow) { // twoPow <= log10Radix
Digit remainder{0};
auto mask{(Digit{1} << twoPow) - 1};
auto coeff{radix >> twoPow};
Expand All @@ -234,7 +239,7 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
}

// Returns true on overflow
bool DivideByPowerOfTwoInPlace(int twoPow) {
RT_API_ATTRS bool DivideByPowerOfTwoInPlace(int twoPow) {
if (digits_ > 0) {
while (twoPow > 0) {
int chunk{twoPow > log10Radix ? log10Radix : twoPow};
Expand Down Expand Up @@ -264,7 +269,7 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
return false; // no overflow
}

int AddCarry(int position = 0, int carry = 1) {
RT_API_ATTRS int AddCarry(int position = 0, int carry = 1) {
for (; position < digits_; ++position) {
Digit v{digit_[position] + carry};
if (v < radix) {
Expand All @@ -286,13 +291,13 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
return carry;
}

void Decrement() {
RT_API_ATTRS void Decrement() {
for (int j{0}; digit_[j]-- == 0; ++j) {
digit_[j] = radix - 1;
}
}

template <int N> int MultiplyByHelper(int carry = 0) {
template <int N> RT_API_ATTRS int MultiplyByHelper(int carry = 0) {
for (int j{0}; j < digits_; ++j) {
auto v{N * digit_[j] + carry};
carry = v / radix;
Expand All @@ -301,15 +306,15 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
return carry;
}

template <int N> int MultiplyBy(int carry = 0) {
template <int N> RT_API_ATTRS int MultiplyBy(int carry = 0) {
if (int newCarry{MultiplyByHelper<N>(carry)}) {
return AddCarry(digits_, newCarry);
} else {
return 0;
}
}

template <int N> int MultiplyWithoutNormalization() {
template <int N> RT_API_ATTRS int MultiplyWithoutNormalization() {
if (int carry{MultiplyByHelper<N>(0)}) {
if (digits_ < digitLimit_) {
digit_[digits_++] = carry;
Expand All @@ -322,9 +327,9 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
}
}

void LoseLeastSignificantDigit(); // with rounding
RT_API_ATTRS void LoseLeastSignificantDigit(); // with rounding

void PushCarry(int carry) {
RT_API_ATTRS void PushCarry(int carry) {
if (digits_ == maxDigits && RemoveLeastOrderZeroDigits() == 0) {
LoseLeastSignificantDigit();
digit_[digits_ - 1] += carry;
Expand All @@ -336,18 +341,20 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
// Adds another number and then divides by two.
// Assumes same exponent and sign.
// Returns true when the result has effectively been rounded down.
bool Mean(const BigRadixFloatingPointNumber &);
RT_API_ATTRS bool Mean(const BigRadixFloatingPointNumber &);

// Parses a floating-point number; leaves the pointer reference
// argument pointing at the next character after what was recognized.
// The "end" argument can be left null if the caller is sure that the
// string is properly terminated with an addressable character that
// can't be in a valid floating-point character.
bool ParseNumber(const char *&, bool &inexact, const char *end);
RT_API_ATTRS bool ParseNumber(const char *&, bool &inexact, const char *end);

using Raw = typename Real::RawType;
constexpr Raw SignBit() const { return Raw{isNegative_} << (Real::bits - 1); }
constexpr Raw Infinity() const {
constexpr RT_API_ATTRS Raw SignBit() const {
return Raw{isNegative_} << (Real::bits - 1);
}
constexpr RT_API_ATTRS Raw Infinity() const {
Raw result{static_cast<Raw>(Real::maxExponent)};
result <<= Real::significandBits;
result |= SignBit();
Expand All @@ -356,7 +363,7 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
}
return result;
}
constexpr Raw NaN(bool isQuiet = true) {
constexpr RT_API_ATTRS Raw NaN(bool isQuiet = true) {
Raw result{Real::maxExponent};
result <<= Real::significandBits;
result |= SignBit();
Expand All @@ -369,7 +376,7 @@ template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
}
return result;
}
constexpr Raw HUGE() const {
constexpr RT_API_ATTRS Raw HUGE() const {
Raw result{static_cast<Raw>(Real::maxExponent)};
result <<= Real::significandBits;
result |= SignBit();
Expand Down
6 changes: 5 additions & 1 deletion flang/lib/Decimal/binary-to-decimal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ template ConversionToDecimalResult ConvertToDecimal<113>(char *, std::size_t,
BinaryFloatingPointNumber<113>);

extern "C" {
RT_EXT_API_GROUP_BEGIN

ConversionToDecimalResult ConvertFloatToDecimal(char *buffer, std::size_t size,
enum DecimalConversionFlags flags, int digits,
enum FortranRounding rounding, float x) {
Expand Down Expand Up @@ -365,7 +367,9 @@ ConversionToDecimalResult ConvertLongDoubleToDecimal(char *buffer,
rounding, Fortran::decimal::BinaryFloatingPointNumber<113>(x));
}
#endif
}

RT_EXT_API_GROUP_END
} // extern "C"

template <int PREC, int LOG10RADIX>
template <typename STREAM>
Expand Down
22 changes: 13 additions & 9 deletions flang/lib/Decimal/decimal-to-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,12 @@ template <int PREC> class IntermediateFloat {
static constexpr IntType topBit{IntType{1} << (precision - 1)};
static constexpr IntType mask{topBit + (topBit - 1)};

IntermediateFloat() {}
RT_API_ATTRS IntermediateFloat() {}
IntermediateFloat(const IntermediateFloat &) = default;

// Assumes that exponent_ is valid on entry, and may increment it.
// Returns the number of guard_ bits that have been determined.
template <typename UINT> bool SetTo(UINT n) {
template <typename UINT> RT_API_ATTRS bool SetTo(UINT n) {
static constexpr int nBits{CHAR_BIT * sizeof n};
if constexpr (precision >= nBits) {
value_ = n;
Expand All @@ -218,14 +218,14 @@ template <int PREC> class IntermediateFloat {
}
}

void ShiftIn(int bit = 0) { value_ = value_ + value_ + bit; }
bool IsFull() const { return value_ >= topBit; }
void AdjustExponent(int by) { exponent_ += by; }
void SetGuard(int g) {
RT_API_ATTRS void ShiftIn(int bit = 0) { value_ = value_ + value_ + bit; }
RT_API_ATTRS bool IsFull() const { return value_ >= topBit; }
RT_API_ATTRS void AdjustExponent(int by) { exponent_ += by; }
RT_API_ATTRS void SetGuard(int g) {
guard_ |= (static_cast<GuardType>(g & 6) << (guardBits - 3)) | (g & 1);
}

ConversionToBinaryResult<PREC> ToBinary(
RT_API_ATTRS ConversionToBinaryResult<PREC> ToBinary(
bool isNegative, FortranRounding) const;

private:
Expand All @@ -241,7 +241,7 @@ template <int PREC> class IntermediateFloat {
// The standard says that these overflow cases round to "representable"
// numbers, and some popular compilers interpret that to mean +/-HUGE()
// rather than +/-Inf.
static inline constexpr bool RoundOverflowToHuge(
static inline RT_API_ATTRS constexpr bool RoundOverflowToHuge(
enum FortranRounding rounding, bool isNegative) {
return rounding == RoundToZero || (!isNegative && rounding == RoundDown) ||
(isNegative && rounding == RoundUp);
Expand Down Expand Up @@ -531,6 +531,8 @@ template ConversionToBinaryResult<113> ConvertToBinary<113>(
const char *&, enum FortranRounding, const char *end);

extern "C" {
RT_EXT_API_GROUP_BEGIN

enum ConversionResultFlags ConvertDecimalToFloat(
const char **p, float *f, enum FortranRounding rounding) {
auto result{Fortran::decimal::ConvertToBinary<24>(*p, rounding)};
Expand All @@ -552,5 +554,7 @@ enum ConversionResultFlags ConvertDecimalToLongDouble(
reinterpret_cast<const void *>(&result.binary), sizeof *ld);
return result.flags;
}
}

RT_EXT_API_GROUP_END
} // extern "C"
} // namespace Fortran::decimal
8 changes: 5 additions & 3 deletions flang/lib/Lower/Allocatable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,13 +588,15 @@ class AllocateStmtHelper {
TODO(loc, "coarray: allocation of a coarray object");
// Set length of the allocate object if it has. Otherwise, get the length
// from source for the deferred length parameter.
if (lenParams.empty() && box.isCharacter() &&
!box.hasNonDeferredLenParams())
const bool isDeferredLengthCharacter =
box.isCharacter() && !box.hasNonDeferredLenParams();
if (lenParams.empty() && isDeferredLengthCharacter)
lenParams.push_back(fir::factory::readCharLen(builder, loc, exv));
if (!isSource || alloc.type.IsPolymorphic())
genRuntimeAllocateApplyMold(builder, loc, box, exv,
alloc.getSymbol().Rank());
genSetDeferredLengthParameters(alloc, box);
if (isDeferredLengthCharacter)
genSetDeferredLengthParameters(alloc, box);
genAllocateObjectBounds(alloc, box);
mlir::Value stat;
if (isSource)
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3772,7 +3772,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
localSymbols.pushScope();
auto transferKindAttr = fir::CUDADataTransferKindAttr::get(
builder.getContext(), fir::CUDADataTransferKind::DeviceHost);
unsigned nbDeviceResidentObject = 0;
[[maybe_unused]] unsigned nbDeviceResidentObject = 0;
for (const Fortran::semantics::Symbol &sym :
Fortran::evaluate::CollectSymbols(assign.rhs)) {
if (const auto *details =
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Lower/ConvertVariable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1469,7 +1469,7 @@ static void lowerExplicitLowerBounds(
/// CFI_desc_t requirements in 18.5.3 point 5.).
static mlir::Value getAssumedSizeExtent(mlir::Location loc,
fir::FirOpBuilder &builder) {
return builder.createIntegerConstant(loc, builder.getIndexType(), -1);
return builder.createMinusOneInteger(loc, builder.getIndexType());
}

/// Lower explicit extents into \p result if this is an explicit-shape or
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Lower/DirectivesCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ genBoundsOpsFromBox(fir::FirOpBuilder &builder, mlir::Location loc,
// Box is not present. Populate bound values with default values.
llvm::SmallVector<mlir::Value> boundValues;
mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
mlir::Value mOne = builder.createIntegerConstant(loc, idxTy, -1);
mlir::Value mOne = builder.createMinusOneInteger(loc, idxTy);
for (unsigned dim = 0; dim < dataExv.rank(); ++dim) {
boundValues.push_back(zero); // lb
boundValues.push_back(mOne); // ub
Expand Down
22 changes: 17 additions & 5 deletions flang/lib/Lower/OpenMP/ReductionProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
#include "ReductionProcessor.h"

#include "flang/Lower/AbstractConverter.h"
#include "flang/Lower/ConvertType.h"
#include "flang/Lower/SymbolMap.h"
#include "flang/Optimizer/Builder/Complex.h"
#include "flang/Optimizer/Builder/HLFIRTools.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/Dialect/FIRType.h"
Expand Down Expand Up @@ -131,7 +133,7 @@ ReductionProcessor::getReductionInitValue(mlir::Location loc, mlir::Type type,
fir::FirOpBuilder &builder) {
type = fir::unwrapRefType(type);
if (!fir::isa_integer(type) && !fir::isa_real(type) &&
!mlir::isa<fir::LogicalType>(type))
!fir::isa_complex(type) && !mlir::isa<fir::LogicalType>(type))
TODO(loc, "Reduction of some types is not supported");
switch (redId) {
case ReductionIdentifier::MAX: {
Expand Down Expand Up @@ -175,6 +177,16 @@ ReductionProcessor::getReductionInitValue(mlir::Location loc, mlir::Type type,
case ReductionIdentifier::OR:
case ReductionIdentifier::EQV:
case ReductionIdentifier::NEQV:
if (auto cplxTy = mlir::dyn_cast<fir::ComplexType>(type)) {
mlir::Type realTy =
Fortran::lower::convertReal(builder.getContext(), cplxTy.getFKind());
mlir::Value initRe = builder.createRealConstant(
loc, realTy, getOperationIdentity(redId, loc));
mlir::Value initIm = builder.createRealConstant(loc, realTy, 0);

return fir::factory::Complex{builder, loc}.createComplex(type, initRe,
initIm);
}
if (type.isa<mlir::FloatType>())
return builder.create<mlir::arith::ConstantOp>(
loc, type,
Expand Down Expand Up @@ -229,13 +241,13 @@ mlir::Value ReductionProcessor::createScalarCombiner(
break;
case ReductionIdentifier::ADD:
reductionOp =
getReductionOperation<mlir::arith::AddFOp, mlir::arith::AddIOp>(
builder, type, loc, op1, op2);
getReductionOperation<mlir::arith::AddFOp, mlir::arith::AddIOp,
fir::AddcOp>(builder, type, loc, op1, op2);
break;
case ReductionIdentifier::MULTIPLY:
reductionOp =
getReductionOperation<mlir::arith::MulFOp, mlir::arith::MulIOp>(
builder, type, loc, op1, op2);
getReductionOperation<mlir::arith::MulFOp, mlir::arith::MulIOp,
fir::MulcOp>(builder, type, loc, op1, op2);
break;
case ReductionIdentifier::AND: {
mlir::Value op1I1 = builder.createConvert(loc, builder.getI1Type(), op1);
Expand Down
21 changes: 20 additions & 1 deletion flang/lib/Lower/OpenMP/ReductionProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ class ReductionProcessor {
fir::FirOpBuilder &builder);

template <typename FloatOp, typename IntegerOp>
static mlir::Value getReductionOperation(fir::FirOpBuilder &builder,
mlir::Type type, mlir::Location loc,
mlir::Value op1, mlir::Value op2);
template <typename FloatOp, typename IntegerOp, typename ComplexOp>
static mlir::Value getReductionOperation(fir::FirOpBuilder &builder,
mlir::Type type, mlir::Location loc,
mlir::Value op1, mlir::Value op2);
Expand Down Expand Up @@ -136,12 +140,27 @@ ReductionProcessor::getReductionOperation(fir::FirOpBuilder &builder,
mlir::Value op1, mlir::Value op2) {
type = fir::unwrapRefType(type);
assert(type.isIntOrIndexOrFloat() &&
"only integer and float types are currently supported");
"only integer, float and complex types are currently supported");
if (type.isIntOrIndex())
return builder.create<IntegerOp>(loc, op1, op2);
return builder.create<FloatOp>(loc, op1, op2);
}

template <typename FloatOp, typename IntegerOp, typename ComplexOp>
mlir::Value
ReductionProcessor::getReductionOperation(fir::FirOpBuilder &builder,
mlir::Type type, mlir::Location loc,
mlir::Value op1, mlir::Value op2) {
assert(type.isIntOrIndexOrFloat() ||
fir::isa_complex(type) &&
"only integer, float and complex types are currently supported");
if (type.isIntOrIndex())
return builder.create<IntegerOp>(loc, op1, op2);
if (fir::isa_real(type))
return builder.create<FloatOp>(loc, op1, op2);
return builder.create<ComplexOp>(loc, op1, op2);
}

} // namespace omp
} // namespace lower
} // namespace Fortran
Expand Down
12 changes: 12 additions & 0 deletions flang/lib/Optimizer/Builder/FIRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,21 @@ mlir::Value fir::FirOpBuilder::createNullConstant(mlir::Location loc,
mlir::Value fir::FirOpBuilder::createIntegerConstant(mlir::Location loc,
mlir::Type ty,
std::int64_t cst) {
assert((cst >= 0 || mlir::isa<mlir::IndexType>(ty) ||
mlir::cast<mlir::IntegerType>(ty).getWidth() <= 64) &&
"must use APint");
return create<mlir::arith::ConstantOp>(loc, ty, getIntegerAttr(ty, cst));
}

mlir::Value fir::FirOpBuilder::createAllOnesInteger(mlir::Location loc,
mlir::Type ty) {
if (mlir::isa<mlir::IndexType>(ty))
return createIntegerConstant(loc, ty, -1);
llvm::APInt allOnes =
llvm::APInt::getAllOnes(mlir::cast<mlir::IntegerType>(ty).getWidth());
return create<mlir::arith::ConstantOp>(loc, ty, getIntegerAttr(ty, allOnes));
}

mlir::Value
fir::FirOpBuilder::createRealConstant(mlir::Location loc, mlir::Type fltTy,
llvm::APFloat::integerPart val) {
Expand Down
Loading