forked from OSchip/llvm-project
Reverting r321223 and its follow-up commit because of failing bots due to Misc/ast-dump-color.cpp.
llvm-svn: 321229
This commit is contained in:
parent
67ebbf2e36
commit
9d6501f6cd
|
@ -976,14 +976,16 @@ public:
|
|||
return LHS.Value != RHS.Value;
|
||||
}
|
||||
|
||||
static std::string getAsString(SplitQualType split,
|
||||
const PrintingPolicy &Policy) {
|
||||
return getAsString(split.Ty, split.Quals, Policy);
|
||||
std::string getAsString() const {
|
||||
return getAsString(split());
|
||||
}
|
||||
static std::string getAsString(const Type *ty, Qualifiers qs,
|
||||
const PrintingPolicy &Policy);
|
||||
|
||||
std::string getAsString() const;
|
||||
static std::string getAsString(SplitQualType split) {
|
||||
return getAsString(split.Ty, split.Quals);
|
||||
}
|
||||
|
||||
static std::string getAsString(const Type *ty, Qualifiers qs);
|
||||
|
||||
std::string getAsString(const PrintingPolicy &Policy) const;
|
||||
|
||||
void print(raw_ostream &OS, const PrintingPolicy &Policy,
|
||||
|
|
|
@ -99,9 +99,6 @@ namespace {
|
|||
const CommandTraits *Traits;
|
||||
const SourceManager *SM;
|
||||
|
||||
/// The policy to use for printing; can be defaulted.
|
||||
PrintingPolicy PrintPolicy;
|
||||
|
||||
/// Pending[i] is an action to dump an entity at level i.
|
||||
llvm::SmallVector<std::function<void(bool isLastChild)>, 32> Pending;
|
||||
|
||||
|
@ -210,17 +207,12 @@ namespace {
|
|||
public:
|
||||
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
|
||||
const SourceManager *SM)
|
||||
: ASTDumper(OS, Traits, SM,
|
||||
SM && SM->getDiagnostics().getShowColors()) {}
|
||||
: OS(OS), Traits(Traits), SM(SM),
|
||||
ShowColors(SM && SM->getDiagnostics().getShowColors()) { }
|
||||
|
||||
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
|
||||
const SourceManager *SM, bool ShowColors)
|
||||
: ASTDumper(OS, Traits, SM, ShowColors, LangOptions()) {}
|
||||
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
|
||||
const SourceManager *SM, bool ShowColors,
|
||||
const PrintingPolicy &PrintPolicy)
|
||||
: OS(OS), Traits(Traits), SM(SM), PrintPolicy(PrintPolicy),
|
||||
ShowColors(ShowColors) {}
|
||||
: OS(OS), Traits(Traits), SM(SM), ShowColors(ShowColors) {}
|
||||
|
||||
void setDeserialize(bool D) { Deserialize = D; }
|
||||
|
||||
|
@ -654,13 +646,13 @@ void ASTDumper::dumpBareType(QualType T, bool Desugar) {
|
|||
ColorScope Color(*this, TypeColor);
|
||||
|
||||
SplitQualType T_split = T.split();
|
||||
OS << "'" << QualType::getAsString(T_split, PrintPolicy) << "'";
|
||||
OS << "'" << QualType::getAsString(T_split) << "'";
|
||||
|
||||
if (Desugar && !T.isNull()) {
|
||||
// If the type is sugared, also dump a (shallow) desugared type.
|
||||
SplitQualType D_split = T.getSplitDesugaredType();
|
||||
if (T_split != D_split)
|
||||
OS << ":'" << QualType::getAsString(D_split, PrintPolicy) << "'";
|
||||
OS << ":'" << QualType::getAsString(D_split) << "'";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1195,12 +1187,12 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
|
|||
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
|
||||
if (MD->size_overridden_methods() != 0) {
|
||||
auto dumpOverride = [=](const CXXMethodDecl *D) {
|
||||
SplitQualType T_split = D->getType().split();
|
||||
OS << D << " " << D->getParent()->getName()
|
||||
<< "::" << D->getNameAsString() << " '"
|
||||
<< QualType::getAsString(T_split, PrintPolicy) << "'";
|
||||
};
|
||||
auto dumpOverride =
|
||||
[=](const CXXMethodDecl *D) {
|
||||
SplitQualType T_split = D->getType().split();
|
||||
OS << D << " " << D->getParent()->getName() << "::"
|
||||
<< D->getNameAsString() << " '" << QualType::getAsString(T_split) << "'";
|
||||
};
|
||||
|
||||
dumpChild([=] {
|
||||
auto Overrides = MD->overridden_methods();
|
||||
|
@ -2690,18 +2682,15 @@ LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS) const {
|
|||
LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }
|
||||
|
||||
LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize) const {
|
||||
const ASTContext &Ctx = getASTContext();
|
||||
ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager(),
|
||||
false, Ctx.getPrintingPolicy());
|
||||
ASTDumper P(OS, &getASTContext().getCommentCommandTraits(),
|
||||
&getASTContext().getSourceManager());
|
||||
P.setDeserialize(Deserialize);
|
||||
P.dumpDecl(this);
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD void Decl::dumpColor() const {
|
||||
const ASTContext &Ctx = getASTContext();
|
||||
ASTDumper P(llvm::errs(), &Ctx.getCommentCommandTraits(),
|
||||
&Ctx.getSourceManager(), /*ShowColors*/ true,
|
||||
Ctx.getPrintingPolicy());
|
||||
ASTDumper P(llvm::errs(), &getASTContext().getCommentCommandTraits(),
|
||||
&getASTContext().getSourceManager(), /*ShowColors*/true);
|
||||
P.dumpDecl(this);
|
||||
}
|
||||
|
||||
|
@ -2716,8 +2705,7 @@ LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS,
|
|||
while (!DC->isTranslationUnit())
|
||||
DC = DC->getParent();
|
||||
ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
|
||||
ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager(),
|
||||
false, Ctx.getPrintingPolicy());
|
||||
ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager());
|
||||
P.setDeserialize(Deserialize);
|
||||
P.dumpLookups(this, DumpDecls);
|
||||
}
|
||||
|
|
|
@ -1712,20 +1712,16 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
|
|||
OS << ' ';
|
||||
}
|
||||
|
||||
std::string QualType::getAsString() const {
|
||||
return getAsString(split(), LangOptions());
|
||||
}
|
||||
|
||||
std::string QualType::getAsString(const PrintingPolicy &Policy) const {
|
||||
std::string S;
|
||||
getAsStringInternal(S, Policy);
|
||||
return S;
|
||||
}
|
||||
|
||||
std::string QualType::getAsString(const Type *ty, Qualifiers qs,
|
||||
const PrintingPolicy &Policy) {
|
||||
std::string QualType::getAsString(const Type *ty, Qualifiers qs) {
|
||||
std::string buffer;
|
||||
getAsStringInternal(ty, qs, buffer, Policy);
|
||||
LangOptions options;
|
||||
getAsStringInternal(ty, qs, buffer, PrintingPolicy(options));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,330 +1,328 @@
|
|||
//=======- PaddingChecker.cpp ------------------------------------*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a checker that checks for padding that could be
|
||||
// removed by re-ordering members.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangSACheckers.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/RecordLayout.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <numeric>
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class PaddingChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
|
||||
private:
|
||||
mutable std::unique_ptr<BugType> PaddingBug;
|
||||
mutable int64_t AllowedPad;
|
||||
mutable BugReporter *BR;
|
||||
|
||||
public:
|
||||
void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
|
||||
BugReporter &BRArg) const {
|
||||
BR = &BRArg;
|
||||
AllowedPad =
|
||||
MGR.getAnalyzerOptions().getOptionAsInteger("AllowedPad", 24, this);
|
||||
assert(AllowedPad >= 0 && "AllowedPad option should be non-negative");
|
||||
|
||||
// The calls to checkAST* from AnalysisConsumer don't
|
||||
// visit template instantiations or lambda classes. We
|
||||
// want to visit those, so we make our own RecursiveASTVisitor.
|
||||
struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
|
||||
const PaddingChecker *Checker;
|
||||
bool shouldVisitTemplateInstantiations() const { return true; }
|
||||
bool shouldVisitImplicitCode() const { return true; }
|
||||
explicit LocalVisitor(const PaddingChecker *Checker) : Checker(Checker) {}
|
||||
bool VisitRecordDecl(const RecordDecl *RD) {
|
||||
Checker->visitRecord(RD);
|
||||
return true;
|
||||
}
|
||||
bool VisitVarDecl(const VarDecl *VD) {
|
||||
Checker->visitVariable(VD);
|
||||
return true;
|
||||
}
|
||||
// TODO: Visit array new and mallocs for arrays.
|
||||
};
|
||||
|
||||
LocalVisitor visitor(this);
|
||||
visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
|
||||
}
|
||||
|
||||
/// \brief Look for records of overly padded types. If padding *
|
||||
/// PadMultiplier exceeds AllowedPad, then generate a report.
|
||||
/// PadMultiplier is used to share code with the array padding
|
||||
/// checker.
|
||||
void visitRecord(const RecordDecl *RD, uint64_t PadMultiplier = 1) const {
|
||||
if (shouldSkipDecl(RD))
|
||||
return;
|
||||
|
||||
auto &ASTContext = RD->getASTContext();
|
||||
const ASTRecordLayout &RL = ASTContext.getASTRecordLayout(RD);
|
||||
assert(llvm::isPowerOf2_64(RL.getAlignment().getQuantity()));
|
||||
|
||||
CharUnits BaselinePad = calculateBaselinePad(RD, ASTContext, RL);
|
||||
if (BaselinePad.isZero())
|
||||
return;
|
||||
|
||||
CharUnits OptimalPad;
|
||||
SmallVector<const FieldDecl *, 20> OptimalFieldsOrder;
|
||||
std::tie(OptimalPad, OptimalFieldsOrder) =
|
||||
calculateOptimalPad(RD, ASTContext, RL);
|
||||
|
||||
CharUnits DiffPad = PadMultiplier * (BaselinePad - OptimalPad);
|
||||
if (DiffPad.getQuantity() <= AllowedPad) {
|
||||
assert(!DiffPad.isNegative() && "DiffPad should not be negative");
|
||||
// There is not enough excess padding to trigger a warning.
|
||||
return;
|
||||
}
|
||||
reportRecord(RD, BaselinePad, OptimalPad, OptimalFieldsOrder);
|
||||
}
|
||||
|
||||
/// \brief Look for arrays of overly padded types. If the padding of the
|
||||
/// array type exceeds AllowedPad, then generate a report.
|
||||
void visitVariable(const VarDecl *VD) const {
|
||||
const ArrayType *ArrTy = VD->getType()->getAsArrayTypeUnsafe();
|
||||
if (ArrTy == nullptr)
|
||||
return;
|
||||
uint64_t Elts = 0;
|
||||
if (const ConstantArrayType *CArrTy = dyn_cast<ConstantArrayType>(ArrTy))
|
||||
Elts = CArrTy->getSize().getZExtValue();
|
||||
if (Elts == 0)
|
||||
return;
|
||||
const RecordType *RT = ArrTy->getElementType()->getAs<RecordType>();
|
||||
if (RT == nullptr)
|
||||
return;
|
||||
|
||||
// TODO: Recurse into the fields and base classes to see if any
|
||||
// of those have excess padding.
|
||||
visitRecord(RT->getDecl(), Elts);
|
||||
}
|
||||
|
||||
bool shouldSkipDecl(const RecordDecl *RD) const {
|
||||
auto Location = RD->getLocation();
|
||||
// If the construct doesn't have a source file, then it's not something
|
||||
// we want to diagnose.
|
||||
if (!Location.isValid())
|
||||
return true;
|
||||
SrcMgr::CharacteristicKind Kind =
|
||||
BR->getSourceManager().getFileCharacteristic(Location);
|
||||
// Throw out all records that come from system headers.
|
||||
if (Kind != SrcMgr::C_User)
|
||||
return true;
|
||||
|
||||
// Not going to attempt to optimize unions.
|
||||
if (RD->isUnion())
|
||||
return true;
|
||||
// How do you reorder fields if you haven't got any?
|
||||
if (RD->field_empty())
|
||||
return true;
|
||||
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
|
||||
// Tail padding with base classes ends up being very complicated.
|
||||
// We will skip objects with base classes for now.
|
||||
if (CXXRD->getNumBases() != 0)
|
||||
return true;
|
||||
// Virtual bases are complicated, skipping those for now.
|
||||
if (CXXRD->getNumVBases() != 0)
|
||||
return true;
|
||||
// Can't layout a template, so skip it. We do still layout the
|
||||
// instantiations though.
|
||||
if (CXXRD->getTypeForDecl()->isDependentType())
|
||||
return true;
|
||||
if (CXXRD->getTypeForDecl()->isInstantiationDependentType())
|
||||
return true;
|
||||
}
|
||||
auto IsTrickyField = [](const FieldDecl *FD) -> bool {
|
||||
// Bitfield layout is hard.
|
||||
if (FD->isBitField())
|
||||
return true;
|
||||
|
||||
// Variable length arrays are tricky too.
|
||||
QualType Ty = FD->getType();
|
||||
if (Ty->isIncompleteArrayType())
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
if (std::any_of(RD->field_begin(), RD->field_end(), IsTrickyField))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static CharUnits calculateBaselinePad(const RecordDecl *RD,
|
||||
const ASTContext &ASTContext,
|
||||
const ASTRecordLayout &RL) {
|
||||
CharUnits PaddingSum;
|
||||
CharUnits Offset = ASTContext.toCharUnitsFromBits(RL.getFieldOffset(0));
|
||||
for (const FieldDecl *FD : RD->fields()) {
|
||||
// This checker only cares about the padded size of the
|
||||
// field, and not the data size. If the field is a record
|
||||
// with tail padding, then we won't put that number in our
|
||||
// total because reordering fields won't fix that problem.
|
||||
CharUnits FieldSize = ASTContext.getTypeSizeInChars(FD->getType());
|
||||
auto FieldOffsetBits = RL.getFieldOffset(FD->getFieldIndex());
|
||||
CharUnits FieldOffset = ASTContext.toCharUnitsFromBits(FieldOffsetBits);
|
||||
PaddingSum += (FieldOffset - Offset);
|
||||
Offset = FieldOffset + FieldSize;
|
||||
}
|
||||
PaddingSum += RL.getSize() - Offset;
|
||||
return PaddingSum;
|
||||
}
|
||||
|
||||
/// Optimal padding overview:
|
||||
/// 1. Find a close approximation to where we can place our first field.
|
||||
/// This will usually be at offset 0.
|
||||
/// 2. Try to find the best field that can legally be placed at the current
|
||||
/// offset.
|
||||
/// a. "Best" is the largest alignment that is legal, but smallest size.
|
||||
/// This is to account for overly aligned types.
|
||||
/// 3. If no fields can fit, pad by rounding the current offset up to the
|
||||
/// smallest alignment requirement of our fields. Measure and track the
|
||||
// amount of padding added. Go back to 2.
|
||||
/// 4. Increment the current offset by the size of the chosen field.
|
||||
/// 5. Remove the chosen field from the set of future possibilities.
|
||||
/// 6. Go back to 2 if there are still unplaced fields.
|
||||
/// 7. Add tail padding by rounding the current offset up to the structure
|
||||
/// alignment. Track the amount of padding added.
|
||||
|
||||
static std::pair<CharUnits, SmallVector<const FieldDecl *, 20>>
|
||||
calculateOptimalPad(const RecordDecl *RD, const ASTContext &ASTContext,
|
||||
const ASTRecordLayout &RL) {
|
||||
struct FieldInfo {
|
||||
CharUnits Align;
|
||||
CharUnits Size;
|
||||
const FieldDecl *Field;
|
||||
bool operator<(const FieldInfo &RHS) const {
|
||||
// Order from small alignments to large alignments,
|
||||
// then large sizes to small sizes.
|
||||
// then large field indices to small field indices
|
||||
return std::make_tuple(Align, -Size,
|
||||
Field ? -static_cast<int>(Field->getFieldIndex())
|
||||
: 0) <
|
||||
std::make_tuple(
|
||||
RHS.Align, -RHS.Size,
|
||||
RHS.Field ? -static_cast<int>(RHS.Field->getFieldIndex())
|
||||
: 0);
|
||||
}
|
||||
};
|
||||
SmallVector<FieldInfo, 20> Fields;
|
||||
auto GatherSizesAndAlignments = [](const FieldDecl *FD) {
|
||||
FieldInfo RetVal;
|
||||
RetVal.Field = FD;
|
||||
auto &Ctx = FD->getASTContext();
|
||||
std::tie(RetVal.Size, RetVal.Align) =
|
||||
Ctx.getTypeInfoInChars(FD->getType());
|
||||
assert(llvm::isPowerOf2_64(RetVal.Align.getQuantity()));
|
||||
if (auto Max = FD->getMaxAlignment())
|
||||
RetVal.Align = std::max(Ctx.toCharUnitsFromBits(Max), RetVal.Align);
|
||||
return RetVal;
|
||||
};
|
||||
std::transform(RD->field_begin(), RD->field_end(),
|
||||
std::back_inserter(Fields), GatherSizesAndAlignments);
|
||||
std::sort(Fields.begin(), Fields.end());
|
||||
// This lets us skip over vptrs and non-virtual bases,
|
||||
// so that we can just worry about the fields in our object.
|
||||
// Note that this does cause us to miss some cases where we
|
||||
// could pack more bytes in to a base class's tail padding.
|
||||
CharUnits NewOffset = ASTContext.toCharUnitsFromBits(RL.getFieldOffset(0));
|
||||
CharUnits NewPad;
|
||||
SmallVector<const FieldDecl *, 20> OptimalFieldsOrder;
|
||||
while (!Fields.empty()) {
|
||||
unsigned TrailingZeros =
|
||||
llvm::countTrailingZeros((unsigned long long)NewOffset.getQuantity());
|
||||
// If NewOffset is zero, then countTrailingZeros will be 64. Shifting
|
||||
// 64 will overflow our unsigned long long. Shifting 63 will turn
|
||||
// our long long (and CharUnits internal type) negative. So shift 62.
|
||||
long long CurAlignmentBits = 1ull << (std::min)(TrailingZeros, 62u);
|
||||
CharUnits CurAlignment = CharUnits::fromQuantity(CurAlignmentBits);
|
||||
FieldInfo InsertPoint = {CurAlignment, CharUnits::Zero(), nullptr};
|
||||
auto CurBegin = Fields.begin();
|
||||
auto CurEnd = Fields.end();
|
||||
|
||||
// In the typical case, this will find the last element
|
||||
// of the vector. We won't find a middle element unless
|
||||
// we started on a poorly aligned address or have an overly
|
||||
// aligned field.
|
||||
auto Iter = std::upper_bound(CurBegin, CurEnd, InsertPoint);
|
||||
if (Iter != CurBegin) {
|
||||
// We found a field that we can layout with the current alignment.
|
||||
--Iter;
|
||||
NewOffset += Iter->Size;
|
||||
OptimalFieldsOrder.push_back(Iter->Field);
|
||||
Fields.erase(Iter);
|
||||
} else {
|
||||
// We are poorly aligned, and we need to pad in order to layout another
|
||||
// field. Round up to at least the smallest field alignment that we
|
||||
// currently have.
|
||||
CharUnits NextOffset = NewOffset.alignTo(Fields[0].Align);
|
||||
NewPad += NextOffset - NewOffset;
|
||||
NewOffset = NextOffset;
|
||||
}
|
||||
}
|
||||
// Calculate tail padding.
|
||||
CharUnits NewSize = NewOffset.alignTo(RL.getAlignment());
|
||||
NewPad += NewSize - NewOffset;
|
||||
return {NewPad, std::move(OptimalFieldsOrder)};
|
||||
}
|
||||
|
||||
void reportRecord(
|
||||
const RecordDecl *RD, CharUnits BaselinePad, CharUnits OptimalPad,
|
||||
const SmallVector<const FieldDecl *, 20> &OptimalFieldsOrder) const {
|
||||
if (!PaddingBug)
|
||||
PaddingBug =
|
||||
llvm::make_unique<BugType>(this, "Excessive Padding", "Performance");
|
||||
|
||||
SmallString<100> Buf;
|
||||
llvm::raw_svector_ostream Os(Buf);
|
||||
Os << "Excessive padding in '";
|
||||
Os << QualType::getAsString(RD->getTypeForDecl(), Qualifiers(),
|
||||
LangOptions())
|
||||
<< "'";
|
||||
|
||||
if (auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
|
||||
// TODO: make this show up better in the console output and in
|
||||
// the HTML. Maybe just make it show up in HTML like the path
|
||||
// diagnostics show.
|
||||
SourceLocation ILoc = TSD->getPointOfInstantiation();
|
||||
if (ILoc.isValid())
|
||||
Os << " instantiated here: "
|
||||
<< ILoc.printToString(BR->getSourceManager());
|
||||
}
|
||||
|
||||
Os << " (" << BaselinePad.getQuantity() << " padding bytes, where "
|
||||
<< OptimalPad.getQuantity() << " is optimal). \n"
|
||||
<< "Optimal fields order: \n";
|
||||
for (const auto *FD : OptimalFieldsOrder)
|
||||
Os << FD->getName() << ", \n";
|
||||
Os << "consider reordering the fields or adding explicit padding "
|
||||
"members.";
|
||||
|
||||
PathDiagnosticLocation CELoc =
|
||||
PathDiagnosticLocation::create(RD, BR->getSourceManager());
|
||||
auto Report = llvm::make_unique<BugReport>(*PaddingBug, Os.str(), CELoc);
|
||||
Report->setDeclWithIssue(RD);
|
||||
Report->addRange(RD->getSourceRange());
|
||||
BR->emitReport(std::move(Report));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void ento::registerPaddingChecker(CheckerManager &Mgr) {
|
||||
Mgr.registerChecker<PaddingChecker>();
|
||||
}
|
||||
//=======- PaddingChecker.cpp ------------------------------------*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a checker that checks for padding that could be
|
||||
// removed by re-ordering members.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangSACheckers.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/RecordLayout.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <numeric>
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class PaddingChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
|
||||
private:
|
||||
mutable std::unique_ptr<BugType> PaddingBug;
|
||||
mutable int64_t AllowedPad;
|
||||
mutable BugReporter *BR;
|
||||
|
||||
public:
|
||||
void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
|
||||
BugReporter &BRArg) const {
|
||||
BR = &BRArg;
|
||||
AllowedPad =
|
||||
MGR.getAnalyzerOptions().getOptionAsInteger("AllowedPad", 24, this);
|
||||
assert(AllowedPad >= 0 && "AllowedPad option should be non-negative");
|
||||
|
||||
// The calls to checkAST* from AnalysisConsumer don't
|
||||
// visit template instantiations or lambda classes. We
|
||||
// want to visit those, so we make our own RecursiveASTVisitor.
|
||||
struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
|
||||
const PaddingChecker *Checker;
|
||||
bool shouldVisitTemplateInstantiations() const { return true; }
|
||||
bool shouldVisitImplicitCode() const { return true; }
|
||||
explicit LocalVisitor(const PaddingChecker *Checker) : Checker(Checker) {}
|
||||
bool VisitRecordDecl(const RecordDecl *RD) {
|
||||
Checker->visitRecord(RD);
|
||||
return true;
|
||||
}
|
||||
bool VisitVarDecl(const VarDecl *VD) {
|
||||
Checker->visitVariable(VD);
|
||||
return true;
|
||||
}
|
||||
// TODO: Visit array new and mallocs for arrays.
|
||||
};
|
||||
|
||||
LocalVisitor visitor(this);
|
||||
visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
|
||||
}
|
||||
|
||||
/// \brief Look for records of overly padded types. If padding *
|
||||
/// PadMultiplier exceeds AllowedPad, then generate a report.
|
||||
/// PadMultiplier is used to share code with the array padding
|
||||
/// checker.
|
||||
void visitRecord(const RecordDecl *RD, uint64_t PadMultiplier = 1) const {
|
||||
if (shouldSkipDecl(RD))
|
||||
return;
|
||||
|
||||
auto &ASTContext = RD->getASTContext();
|
||||
const ASTRecordLayout &RL = ASTContext.getASTRecordLayout(RD);
|
||||
assert(llvm::isPowerOf2_64(RL.getAlignment().getQuantity()));
|
||||
|
||||
CharUnits BaselinePad = calculateBaselinePad(RD, ASTContext, RL);
|
||||
if (BaselinePad.isZero())
|
||||
return;
|
||||
|
||||
CharUnits OptimalPad;
|
||||
SmallVector<const FieldDecl *, 20> OptimalFieldsOrder;
|
||||
std::tie(OptimalPad, OptimalFieldsOrder) =
|
||||
calculateOptimalPad(RD, ASTContext, RL);
|
||||
|
||||
CharUnits DiffPad = PadMultiplier * (BaselinePad - OptimalPad);
|
||||
if (DiffPad.getQuantity() <= AllowedPad) {
|
||||
assert(!DiffPad.isNegative() && "DiffPad should not be negative");
|
||||
// There is not enough excess padding to trigger a warning.
|
||||
return;
|
||||
}
|
||||
reportRecord(RD, BaselinePad, OptimalPad, OptimalFieldsOrder);
|
||||
}
|
||||
|
||||
/// \brief Look for arrays of overly padded types. If the padding of the
|
||||
/// array type exceeds AllowedPad, then generate a report.
|
||||
void visitVariable(const VarDecl *VD) const {
|
||||
const ArrayType *ArrTy = VD->getType()->getAsArrayTypeUnsafe();
|
||||
if (ArrTy == nullptr)
|
||||
return;
|
||||
uint64_t Elts = 0;
|
||||
if (const ConstantArrayType *CArrTy = dyn_cast<ConstantArrayType>(ArrTy))
|
||||
Elts = CArrTy->getSize().getZExtValue();
|
||||
if (Elts == 0)
|
||||
return;
|
||||
const RecordType *RT = ArrTy->getElementType()->getAs<RecordType>();
|
||||
if (RT == nullptr)
|
||||
return;
|
||||
|
||||
// TODO: Recurse into the fields and base classes to see if any
|
||||
// of those have excess padding.
|
||||
visitRecord(RT->getDecl(), Elts);
|
||||
}
|
||||
|
||||
bool shouldSkipDecl(const RecordDecl *RD) const {
|
||||
auto Location = RD->getLocation();
|
||||
// If the construct doesn't have a source file, then it's not something
|
||||
// we want to diagnose.
|
||||
if (!Location.isValid())
|
||||
return true;
|
||||
SrcMgr::CharacteristicKind Kind =
|
||||
BR->getSourceManager().getFileCharacteristic(Location);
|
||||
// Throw out all records that come from system headers.
|
||||
if (Kind != SrcMgr::C_User)
|
||||
return true;
|
||||
|
||||
// Not going to attempt to optimize unions.
|
||||
if (RD->isUnion())
|
||||
return true;
|
||||
// How do you reorder fields if you haven't got any?
|
||||
if (RD->field_empty())
|
||||
return true;
|
||||
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
|
||||
// Tail padding with base classes ends up being very complicated.
|
||||
// We will skip objects with base classes for now.
|
||||
if (CXXRD->getNumBases() != 0)
|
||||
return true;
|
||||
// Virtual bases are complicated, skipping those for now.
|
||||
if (CXXRD->getNumVBases() != 0)
|
||||
return true;
|
||||
// Can't layout a template, so skip it. We do still layout the
|
||||
// instantiations though.
|
||||
if (CXXRD->getTypeForDecl()->isDependentType())
|
||||
return true;
|
||||
if (CXXRD->getTypeForDecl()->isInstantiationDependentType())
|
||||
return true;
|
||||
}
|
||||
auto IsTrickyField = [](const FieldDecl *FD) -> bool {
|
||||
// Bitfield layout is hard.
|
||||
if (FD->isBitField())
|
||||
return true;
|
||||
|
||||
// Variable length arrays are tricky too.
|
||||
QualType Ty = FD->getType();
|
||||
if (Ty->isIncompleteArrayType())
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
if (std::any_of(RD->field_begin(), RD->field_end(), IsTrickyField))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static CharUnits calculateBaselinePad(const RecordDecl *RD,
|
||||
const ASTContext &ASTContext,
|
||||
const ASTRecordLayout &RL) {
|
||||
CharUnits PaddingSum;
|
||||
CharUnits Offset = ASTContext.toCharUnitsFromBits(RL.getFieldOffset(0));
|
||||
for (const FieldDecl *FD : RD->fields()) {
|
||||
// This checker only cares about the padded size of the
|
||||
// field, and not the data size. If the field is a record
|
||||
// with tail padding, then we won't put that number in our
|
||||
// total because reordering fields won't fix that problem.
|
||||
CharUnits FieldSize = ASTContext.getTypeSizeInChars(FD->getType());
|
||||
auto FieldOffsetBits = RL.getFieldOffset(FD->getFieldIndex());
|
||||
CharUnits FieldOffset = ASTContext.toCharUnitsFromBits(FieldOffsetBits);
|
||||
PaddingSum += (FieldOffset - Offset);
|
||||
Offset = FieldOffset + FieldSize;
|
||||
}
|
||||
PaddingSum += RL.getSize() - Offset;
|
||||
return PaddingSum;
|
||||
}
|
||||
|
||||
/// Optimal padding overview:
|
||||
/// 1. Find a close approximation to where we can place our first field.
|
||||
/// This will usually be at offset 0.
|
||||
/// 2. Try to find the best field that can legally be placed at the current
|
||||
/// offset.
|
||||
/// a. "Best" is the largest alignment that is legal, but smallest size.
|
||||
/// This is to account for overly aligned types.
|
||||
/// 3. If no fields can fit, pad by rounding the current offset up to the
|
||||
/// smallest alignment requirement of our fields. Measure and track the
|
||||
// amount of padding added. Go back to 2.
|
||||
/// 4. Increment the current offset by the size of the chosen field.
|
||||
/// 5. Remove the chosen field from the set of future possibilities.
|
||||
/// 6. Go back to 2 if there are still unplaced fields.
|
||||
/// 7. Add tail padding by rounding the current offset up to the structure
|
||||
/// alignment. Track the amount of padding added.
|
||||
|
||||
static std::pair<CharUnits, SmallVector<const FieldDecl *, 20>>
|
||||
calculateOptimalPad(const RecordDecl *RD, const ASTContext &ASTContext,
|
||||
const ASTRecordLayout &RL) {
|
||||
struct FieldInfo {
|
||||
CharUnits Align;
|
||||
CharUnits Size;
|
||||
const FieldDecl *Field;
|
||||
bool operator<(const FieldInfo &RHS) const {
|
||||
// Order from small alignments to large alignments,
|
||||
// then large sizes to small sizes.
|
||||
// then large field indices to small field indices
|
||||
return std::make_tuple(Align, -Size,
|
||||
Field ? -static_cast<int>(Field->getFieldIndex())
|
||||
: 0) <
|
||||
std::make_tuple(
|
||||
RHS.Align, -RHS.Size,
|
||||
RHS.Field ? -static_cast<int>(RHS.Field->getFieldIndex())
|
||||
: 0);
|
||||
}
|
||||
};
|
||||
SmallVector<FieldInfo, 20> Fields;
|
||||
auto GatherSizesAndAlignments = [](const FieldDecl *FD) {
|
||||
FieldInfo RetVal;
|
||||
RetVal.Field = FD;
|
||||
auto &Ctx = FD->getASTContext();
|
||||
std::tie(RetVal.Size, RetVal.Align) =
|
||||
Ctx.getTypeInfoInChars(FD->getType());
|
||||
assert(llvm::isPowerOf2_64(RetVal.Align.getQuantity()));
|
||||
if (auto Max = FD->getMaxAlignment())
|
||||
RetVal.Align = std::max(Ctx.toCharUnitsFromBits(Max), RetVal.Align);
|
||||
return RetVal;
|
||||
};
|
||||
std::transform(RD->field_begin(), RD->field_end(),
|
||||
std::back_inserter(Fields), GatherSizesAndAlignments);
|
||||
std::sort(Fields.begin(), Fields.end());
|
||||
// This lets us skip over vptrs and non-virtual bases,
|
||||
// so that we can just worry about the fields in our object.
|
||||
// Note that this does cause us to miss some cases where we
|
||||
// could pack more bytes in to a base class's tail padding.
|
||||
CharUnits NewOffset = ASTContext.toCharUnitsFromBits(RL.getFieldOffset(0));
|
||||
CharUnits NewPad;
|
||||
SmallVector<const FieldDecl *, 20> OptimalFieldsOrder;
|
||||
while (!Fields.empty()) {
|
||||
unsigned TrailingZeros =
|
||||
llvm::countTrailingZeros((unsigned long long)NewOffset.getQuantity());
|
||||
// If NewOffset is zero, then countTrailingZeros will be 64. Shifting
|
||||
// 64 will overflow our unsigned long long. Shifting 63 will turn
|
||||
// our long long (and CharUnits internal type) negative. So shift 62.
|
||||
long long CurAlignmentBits = 1ull << (std::min)(TrailingZeros, 62u);
|
||||
CharUnits CurAlignment = CharUnits::fromQuantity(CurAlignmentBits);
|
||||
FieldInfo InsertPoint = {CurAlignment, CharUnits::Zero(), nullptr};
|
||||
auto CurBegin = Fields.begin();
|
||||
auto CurEnd = Fields.end();
|
||||
|
||||
// In the typical case, this will find the last element
|
||||
// of the vector. We won't find a middle element unless
|
||||
// we started on a poorly aligned address or have an overly
|
||||
// aligned field.
|
||||
auto Iter = std::upper_bound(CurBegin, CurEnd, InsertPoint);
|
||||
if (Iter != CurBegin) {
|
||||
// We found a field that we can layout with the current alignment.
|
||||
--Iter;
|
||||
NewOffset += Iter->Size;
|
||||
OptimalFieldsOrder.push_back(Iter->Field);
|
||||
Fields.erase(Iter);
|
||||
} else {
|
||||
// We are poorly aligned, and we need to pad in order to layout another
|
||||
// field. Round up to at least the smallest field alignment that we
|
||||
// currently have.
|
||||
CharUnits NextOffset = NewOffset.alignTo(Fields[0].Align);
|
||||
NewPad += NextOffset - NewOffset;
|
||||
NewOffset = NextOffset;
|
||||
}
|
||||
}
|
||||
// Calculate tail padding.
|
||||
CharUnits NewSize = NewOffset.alignTo(RL.getAlignment());
|
||||
NewPad += NewSize - NewOffset;
|
||||
return {NewPad, std::move(OptimalFieldsOrder)};
|
||||
}
|
||||
|
||||
void reportRecord(
|
||||
const RecordDecl *RD, CharUnits BaselinePad, CharUnits OptimalPad,
|
||||
const SmallVector<const FieldDecl *, 20> &OptimalFieldsOrder) const {
|
||||
if (!PaddingBug)
|
||||
PaddingBug =
|
||||
llvm::make_unique<BugType>(this, "Excessive Padding", "Performance");
|
||||
|
||||
SmallString<100> Buf;
|
||||
llvm::raw_svector_ostream Os(Buf);
|
||||
Os << "Excessive padding in '";
|
||||
Os << QualType::getAsString(RD->getTypeForDecl(), Qualifiers()) << "'";
|
||||
|
||||
if (auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
|
||||
// TODO: make this show up better in the console output and in
|
||||
// the HTML. Maybe just make it show up in HTML like the path
|
||||
// diagnostics show.
|
||||
SourceLocation ILoc = TSD->getPointOfInstantiation();
|
||||
if (ILoc.isValid())
|
||||
Os << " instantiated here: "
|
||||
<< ILoc.printToString(BR->getSourceManager());
|
||||
}
|
||||
|
||||
Os << " (" << BaselinePad.getQuantity() << " padding bytes, where "
|
||||
<< OptimalPad.getQuantity() << " is optimal). \n"
|
||||
<< "Optimal fields order: \n";
|
||||
for (const auto *FD : OptimalFieldsOrder)
|
||||
Os << FD->getName() << ", \n";
|
||||
Os << "consider reordering the fields or adding explicit padding "
|
||||
"members.";
|
||||
|
||||
PathDiagnosticLocation CELoc =
|
||||
PathDiagnosticLocation::create(RD, BR->getSourceManager());
|
||||
auto Report = llvm::make_unique<BugReport>(*PaddingBug, Os.str(), CELoc);
|
||||
Report->setDeclWithIssue(RD);
|
||||
Report->addRange(RD->getSourceRange());
|
||||
BR->emitReport(std::move(Report));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void ento::registerPaddingChecker(CheckerManager &Mgr) {
|
||||
Mgr.registerChecker<PaddingChecker>();
|
||||
}
|
||||
|
|
|
@ -1,56 +1,56 @@
|
|||
// RUN: %clang_cc1 -ast-dump %s 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK-LABEL: example0
|
||||
void example0() {
|
||||
double d = 2.0;
|
||||
// CHECK: VarDecl{{.*}}rd 'double &'
|
||||
// CHECK-NEXT: DeclRefExpr
|
||||
double &rd = d;
|
||||
// CHECK: VarDecl{{.*}}rcd 'const double &'
|
||||
// CHECK-NEXT: ImplicitCastExpr{{.*}}'const double' lvalue <NoOp>
|
||||
const double &rcd = d;
|
||||
}
|
||||
|
||||
struct A { };
|
||||
struct B : A { } b;
|
||||
|
||||
// CHECK-LABEL: example1
|
||||
void example1() {
|
||||
// CHECK: VarDecl{{.*}}ra 'A &'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'A' lvalue <DerivedToBase (A)>
|
||||
A &ra = b;
|
||||
// CHECK: VarDecl{{.*}}rca 'const A &'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const A' lvalue <DerivedToBase (A)>
|
||||
// CHECK-NOT: MaterializeTemporaryExpr
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const B' lvalue <NoOp>
|
||||
const A& rca = b;
|
||||
}
|
||||
|
||||
extern B f();
|
||||
|
||||
struct X {
|
||||
operator B();
|
||||
} x;
|
||||
|
||||
// CHECK-LABEL: example2
|
||||
void example2() {
|
||||
// CHECK: VarDecl{{.*}}rca 'const A &'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const A' lvalue <DerivedToBase (A)>
|
||||
// CHECK: MaterializeTemporaryExpr{{.*}}'const B'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const B' <NoOp>
|
||||
// CHECK: CallExpr{{.*}}B
|
||||
const A &rca = f();
|
||||
// CHECK: VarDecl{{.*}}r 'const A &'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const A' lvalue <DerivedToBase (A)>
|
||||
// CHECK: MaterializeTemporaryExpr{{.*}}'const B'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const B' <NoOp>
|
||||
// CHECK: CXXMemberCallExpr{{.*}}'B'
|
||||
const A& r = x;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: example3
|
||||
void example3() {
|
||||
// CHECK: VarDecl{{.*}}rcd2 'const double &'
|
||||
// CHECK: ImplicitCastExpr{{.*}} <IntegralToFloating>
|
||||
const double& rcd2 = 2;
|
||||
}
|
||||
// RUN: %clang_cc1 -ast-dump %s 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK-LABEL: example0
|
||||
void example0() {
|
||||
double d = 2.0;
|
||||
// CHECK: VarDecl{{.*}}rd 'double &'
|
||||
// CHECK-NEXT: DeclRefExpr
|
||||
double &rd = d;
|
||||
// CHECK: VarDecl{{.*}}rcd 'const double &'
|
||||
// CHECK-NEXT: ImplicitCastExpr{{.*}}'const double' lvalue <NoOp>
|
||||
const double &rcd = d;
|
||||
}
|
||||
|
||||
struct A { };
|
||||
struct B : A { } b;
|
||||
|
||||
// CHECK-LABEL: example1
|
||||
void example1() {
|
||||
// CHECK: VarDecl{{.*}}ra 'struct A &'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue <DerivedToBase (A)>
|
||||
A &ra = b;
|
||||
// CHECK: VarDecl{{.*}}rca 'const struct A &'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <DerivedToBase (A)>
|
||||
// CHECK-NOT: MaterializeTemporaryExpr
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const struct B' lvalue <NoOp>
|
||||
const A& rca = b;
|
||||
}
|
||||
|
||||
extern B f();
|
||||
|
||||
struct X {
|
||||
operator B();
|
||||
} x;
|
||||
|
||||
// CHECK-LABEL: example2
|
||||
void example2() {
|
||||
// CHECK: VarDecl{{.*}}rca 'const struct A &'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <DerivedToBase (A)>
|
||||
// CHECK: MaterializeTemporaryExpr{{.*}}'const struct B'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const struct B' <NoOp>
|
||||
// CHECK: CallExpr{{.*}}B
|
||||
const A &rca = f();
|
||||
// CHECK: VarDecl{{.*}}r 'const struct A &'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <DerivedToBase (A)>
|
||||
// CHECK: MaterializeTemporaryExpr{{.*}}'const struct B'
|
||||
// CHECK: ImplicitCastExpr{{.*}}'const struct B' <NoOp>
|
||||
// CHECK: CXXMemberCallExpr{{.*}}'struct B'
|
||||
const A& r = x;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: example3
|
||||
void example3() {
|
||||
// CHECK: VarDecl{{.*}}rcd2 'const double &'
|
||||
// CHECK: ImplicitCastExpr{{.*}} <IntegralToFloating>
|
||||
const double& rcd2 = 2;
|
||||
}
|
||||
|
|
|
@ -1,326 +1,326 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace
|
||||
// RUN: %clang_cc1 -std=c++11 -ast-dump -fnative-half-type %s | FileCheck %s --check-prefix=CHECK-NATIVE --strict-whitespace
|
||||
|
||||
/* Various contexts where type _Float16 can appear. */
|
||||
|
||||
/* Namespace */
|
||||
namespace {
|
||||
_Float16 f1n;
|
||||
_Float16 f2n = 33.f16;
|
||||
_Float16 arr1n[10];
|
||||
_Float16 arr2n[] = { 1.2, 3.0, 3.e4 };
|
||||
const volatile _Float16 func1n(const _Float16 &arg) {
|
||||
return arg + f2n + arr1n[4] - arr2n[1];
|
||||
}
|
||||
}
|
||||
|
||||
//CHECK: |-NamespaceDecl
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} f1n '_Float16'
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} f2n '_Float16' cinit
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 3.300000e+01
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} arr1n '_Float16 [10]'
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} arr2n '_Float16 [3]' cinit
|
||||
//CHECK-NEXT: | | `-InitListExpr {{.*}} '_Float16 [3]'
|
||||
//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | | | `-FloatingLiteral {{.*}} 'double' 1.200000e+00
|
||||
//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | | | `-FloatingLiteral {{.*}} 'double' 3.000000e+00
|
||||
//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} 'double' 3.000000e+04
|
||||
//CHECK-NEXT: | `-FunctionDecl {{.*}} func1n 'const volatile _Float16 (const _Float16 &)'
|
||||
|
||||
/* File */
|
||||
_Float16 f1f;
|
||||
_Float16 f2f = 32.4;
|
||||
_Float16 arr1f[10];
|
||||
_Float16 arr2f[] = { -1.2, -3.0, -3.e4 };
|
||||
_Float16 func1f(_Float16 arg);
|
||||
|
||||
//CHECK: |-VarDecl {{.*}} f1f '_Float16'
|
||||
//CHECK-NEXT: |-VarDecl {{.*}} f2f '_Float16' cinit
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 3.240000e+01
|
||||
//CHECK-NEXT: |-VarDecl {{.*}} arr1f '_Float16 [10]'
|
||||
//CHECK-NEXT: |-VarDecl {{.*}} arr2f '_Float16 [3]' cinit
|
||||
//CHECK-NEXT: | `-InitListExpr {{.*}} '_Float16 [3]'
|
||||
//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | | `-UnaryOperator {{.*}} 'double' prefix '-'
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} 'double' 1.200000e+00
|
||||
//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | | `-UnaryOperator {{.*}} 'double' prefix '-'
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} 'double' 3.000000e+00
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | `-UnaryOperator {{.*}} 'double' prefix '-'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 3.000000e+04
|
||||
//CHECK-NEXT: |-FunctionDecl {{.*}} func1f '_Float16 (_Float16)'
|
||||
//CHECK-NEXT: | `-ParmVarDecl {{.*}} arg '_Float16'
|
||||
|
||||
|
||||
// Mixing __fp16 and Float16 types:
|
||||
// The _Float16 type is first converted to __fp16 type and then the operation
|
||||
// is completed as if both operands were of __fp16 type.
|
||||
|
||||
__fp16 B = -0.1;
|
||||
auto C = -1.0f16 + B;
|
||||
|
||||
// When we do *not* have native half types, we expect __fp16 to be promoted to
|
||||
// float, and consequently also _Float16 promotions to float:
|
||||
|
||||
//CHECK: -VarDecl {{.*}} used B '__fp16' cinit
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '__fp16' <FloatingCast>
|
||||
//CHECK-NEXT: | `-UnaryOperator {{.*}} 'double' prefix '-'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 1.000000e-01
|
||||
//CHECK-NEXT: |-VarDecl {{.*}} C 'float':'float' cinit
|
||||
//CHECK-NEXT: | `-BinaryOperator {{.*}} 'float' '+'
|
||||
//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} 'float' <FloatingCast>
|
||||
//CHECK-NEXT: | | `-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'float' <FloatingCast>
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '__fp16' <LValueToRValue>
|
||||
//CHECK-NEXT: | `-DeclRefExpr {{.*}} '__fp16' lvalue Var 0x{{.*}} 'B' '__fp16'
|
||||
|
||||
// When do have native half types, we expect to see promotions to fp16:
|
||||
|
||||
//CHECK-NATIVE: |-VarDecl {{.*}} used B '__fp16' cinit
|
||||
//CHECK-NATIVE: | `-ImplicitCastExpr {{.*}} '__fp16' <FloatingCast>
|
||||
//CHECK-NATIVE: | `-UnaryOperator {{.*}} 'double' prefix '-'
|
||||
//CHECK-NATIVE: | `-FloatingLiteral {{.*}} 'double' 1.000000e-01
|
||||
//CHECK-NATIVE: |-VarDecl {{.*}} C '__fp16':'__fp16' cinit
|
||||
//CHECK-NATIVE: | `-BinaryOperator {{.*}} '__fp16' '+'
|
||||
//CHECK-NATIVE: | |-ImplicitCastExpr {{.*}} '__fp16' <FloatingCast>
|
||||
//CHECK-NATIVE: | | `-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NATIVE: | | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
|
||||
//CHECK-NATIVE: | `-ImplicitCastExpr {{.*}} '__fp16' <LValueToRValue>
|
||||
//CHECK-NATIVE: | `-DeclRefExpr {{.*}} '__fp16' lvalue Var 0x{{.*}} 'B' '__fp16'
|
||||
|
||||
|
||||
/* Class */
|
||||
|
||||
class C1 {
|
||||
_Float16 f1c;
|
||||
static const _Float16 f2c;
|
||||
volatile _Float16 f3c;
|
||||
public:
|
||||
C1(_Float16 arg) : f1c(arg), f3c(arg) { }
|
||||
_Float16 func1c(_Float16 arg ) {
|
||||
return f1c + arg;
|
||||
}
|
||||
static _Float16 func2c(_Float16 arg) {
|
||||
return arg * C1::f2c;
|
||||
}
|
||||
};
|
||||
|
||||
//CHECK: |-CXXRecordDecl {{.*}} referenced class C1 definition
|
||||
//CHECK: | |-CXXRecordDecl {{.*}} implicit referenced class C1
|
||||
//CHECK-NEXT: | |-FieldDecl {{.*}} referenced f1c '_Float16'
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} used f2c 'const _Float16' static
|
||||
//CHECK-NEXT: | |-FieldDecl {{.*}} f3c 'volatile _Float16'
|
||||
//CHECK-NEXT: | |-AccessSpecDecl
|
||||
//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} used C1 'void (_Float16)
|
||||
//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used arg '_Float16'
|
||||
//CHECK-NEXT: | | |-CXXCtorInitializer Field {{.*}} 'f1c' '_Float16'
|
||||
//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
|
||||
//CHECK-NEXT: | | |-CXXCtorInitializer Field {{.*}} 'f3c' 'volatile _Float16'
|
||||
//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
|
||||
//CHECK-NEXT: | | `-CompoundStmt
|
||||
//CHECK-NEXT: | |-CXXMethodDecl {{.*}} used func1c '_Float16 (_Float16)
|
||||
//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used arg '_Float16'
|
||||
//CHECK-NEXT: | | `-CompoundStmt
|
||||
//CHECK-NEXT: | | `-ReturnStmt
|
||||
//CHECK-NEXT: | | `-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | `-MemberExpr {{.*}} '_Float16' lvalue ->f1c 0x{{.*}}
|
||||
//CHECK-NEXT: | | | `-CXXThisExpr {{.*}} 'C1 *' this
|
||||
//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
|
||||
//CHECK-NEXT: | |-CXXMethodDecl {{.*}} used func2c '_Float16 (_Float16)' static
|
||||
//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used arg '_Float16'
|
||||
//CHECK-NEXT: | | `-CompoundStmt
|
||||
//CHECK-NEXT: | | `-ReturnStmt
|
||||
//CHECK-NEXT: | | `-BinaryOperator {{.*}} '_Float16' '*'
|
||||
//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
|
||||
//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'const _Float16' lvalue Var 0x{{.*}} 'f2c' 'const _Float16'
|
||||
|
||||
|
||||
/* Template */
|
||||
|
||||
template <class C> C func1t(C arg) {
|
||||
return arg * 2.f16;
|
||||
}
|
||||
|
||||
//CHECK: |-FunctionTemplateDecl {{.*}} func1t
|
||||
//CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} C
|
||||
//CHECK-NEXT: | |-FunctionDecl {{.*}} func1t 'C (C)'
|
||||
//CHECK-NEXT: | | |-ParmVarDecl {{.*}} referenced arg 'C'
|
||||
//CHECK-NEXT: | | `-CompoundStmt
|
||||
//CHECK-NEXT: | | `-ReturnStmt
|
||||
//CHECK-NEXT: | | `-BinaryOperator {{.*}} '<dependent type>' '*'
|
||||
//CHECK-NEXT: | | |-DeclRefExpr {{.*}} 'C' lvalue ParmVar {{.*}} 'arg' 'C'
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 2.000000e+00
|
||||
//CHECK-NEXT: | `-FunctionDecl {{.*}} used func1t '_Float16 (_Float16)'
|
||||
//CHECK-NEXT: | |-TemplateArgument type '_Float16'
|
||||
//CHECK-NEXT: | |-ParmVarDecl {{.*}} used arg '_Float16':'_Float16'
|
||||
//CHECK-NEXT: | `-CompoundStmt
|
||||
//CHECK-NEXT: | `-ReturnStmt
|
||||
//CHECK-NEXT: | `-BinaryOperator {{.*}} '_Float16' '*'
|
||||
//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16':'_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16':'_Float16' lvalue ParmVar {{.*}} 'arg' '_Float16':'_Float16'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 2.000000e+00
|
||||
|
||||
|
||||
template <class C> struct S1 {
|
||||
C mem1;
|
||||
};
|
||||
|
||||
//CHECK: |-ClassTemplateDecl {{.*}} S1
|
||||
//CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} referenced class depth 0 index 0 C
|
||||
//CHECK-NEXT: | |-CXXRecordDecl {{.*}} struct S1 definition
|
||||
//CHECK: | | |-CXXRecordDecl {{.*}} implicit struct S1
|
||||
//CHECK-NEXT: | | `-FieldDecl {{.*}} mem1 'C'
|
||||
//CHECK-NEXT: | `-ClassTemplateSpecialization {{.*}} 'S1'
|
||||
|
||||
template <> struct S1<_Float16> {
|
||||
_Float16 mem2;
|
||||
};
|
||||
|
||||
|
||||
/* Local */
|
||||
|
||||
extern int printf (const char *__restrict __format, ...);
|
||||
|
||||
int main(void) {
|
||||
_Float16 f1l = 1e3f16;
|
||||
//CHECK: | `-VarDecl {{.*}} used f1l '_Float16' cinit
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+03
|
||||
|
||||
_Float16 f2l = -0.f16;
|
||||
//CHECK: | `-VarDecl {{.*}} used f2l '_Float16' cinit
|
||||
//CHECK-NEXT: | `-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 0.000000e+00
|
||||
|
||||
_Float16 f3l = 1.000976562;
|
||||
//CHECK: | `-VarDecl {{.*}} used f3l '_Float16' cinit
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 1.000977e+00
|
||||
|
||||
C1 c1(f1l);
|
||||
//CHECK: | `-VarDecl{{.*}} used c1 'C1' callinit
|
||||
//CHECK-NEXT: | `-CXXConstructExpr {{.*}} 'C1' 'void (_Float16)
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var 0x{{.*}} 'f1l' '_Float16'
|
||||
|
||||
S1<_Float16> s1 = { 132.f16 };
|
||||
//CHECK: | `-VarDecl {{.*}} used s1 'S1<_Float16>':'S1<_Float16>' cinit
|
||||
//CHECK-NEXT: | `-InitListExpr {{.*}} 'S1<_Float16>':'S1<_Float16>'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 1.320000e+02
|
||||
|
||||
_Float16 f4l = func1n(f1l) + func1f(f2l) + c1.func1c(f3l) + c1.func2c(f1l) +
|
||||
func1t(f1l) + s1.mem2 - f1n + f2n;
|
||||
//CHECK: | `-VarDecl {{.*}} used f4l '_Float16' cinit
|
||||
//CHECK-NEXT: | `-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | |-BinaryOperator {{.*}} '_Float16' '-'
|
||||
//CHECK-NEXT: | | |-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | | |-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | | | |-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | | | | |-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | | | | | |-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | | | | | | |-CallExpr {{.*}} '_Float16'
|
||||
//CHECK-NEXT: | | | | | | | | |-ImplicitCastExpr {{.*}} 'const volatile _Float16 (*)(const _Float16 &)' <FunctionToPointerDecay>
|
||||
//CHECK-NEXT: | | | | | | | | | `-DeclRefExpr {{.*}} 'const volatile _Float16 (const _Float16 &)' lvalue Function {{.*}} 'func1n' 'const volatile _Float16 (const _Float16 &)'
|
||||
//CHECK-NEXT: | | | | | | | | `-ImplicitCastExpr {{.*}} 'const _Float16' lvalue <NoOp>
|
||||
//CHECK-NEXT: | | | | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1l' '_Float16'
|
||||
//CHECK-NEXT: | | | | | | | `-CallExpr {{.*}} '_Float16'
|
||||
//CHECK-NEXT: | | | | | | | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
|
||||
//CHECK-NEXT: | | | | | | | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1f' '_Float16 (_Float16)'
|
||||
//CHECK-NEXT: | | | | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2l' '_Float16'
|
||||
//CHECK-NEXT: | | | | | | `-CXXMemberCallExpr {{.*}} '_Float16'
|
||||
//CHECK-NEXT: | | | | | | |-MemberExpr {{.*}} '<bound member function type>' .func1c {{.*}}
|
||||
//CHECK-NEXT: | | | | | | | `-DeclRefExpr {{.*}} 'C1' lvalue Var {{.*}} 'c1' 'C1'
|
||||
//CHECK-NEXT: | | | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f3l' '_Float16'
|
||||
//CHECK-NEXT: | | | | | `-CallExpr {{.*}} '_Float16'
|
||||
//CHECK-NEXT: | | | | | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
|
||||
//CHECK-NEXT: | | | | | | `-MemberExpr {{.*}} '_Float16 (_Float16)' lvalue .func2c {{.*}}
|
||||
//CHECK-NEXT: | | | | | | `-DeclRefExpr {{.*}} 'C1' lvalue Var {{.*}} 'c1' 'C1'
|
||||
//CHECK-NEXT: | | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1l' '_Float16'
|
||||
//CHECK-NEXT: | | | | `-CallExpr {{.*}} '_Float16':'_Float16'
|
||||
//CHECK-NEXT: | | | | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
|
||||
//CHECK-NEXT: | | | | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1t' '_Float16 (_Float16)' (FunctionTemplate {{.*}} 'func1t')
|
||||
//CHECK-NEXT: | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1l' '_Float16'
|
||||
//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | `-MemberExpr {{.*}} '_Float16' lvalue .mem2 {{.*}}
|
||||
//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'S1<_Float16>':'S1<_Float16>' lvalue Var {{.*}} 's1' 'S1<_Float16>':'S1<_Float16>'
|
||||
//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1n' '_Float16'
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
|
||||
|
||||
auto f5l = -1.f16, *f6l = &f2l, f7l = func1t(f3l);
|
||||
//CHECK: | |-VarDecl {{.*}} f5l '_Float16':'_Float16' cinit
|
||||
//CHECK-NEXT: | | `-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} f6l '_Float16 *' cinit
|
||||
//CHECK-NEXT: | | `-UnaryOperator {{.*}} '_Float16 *' prefix '&'
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2l' '_Float16'
|
||||
//CHECK-NEXT: | `-VarDecl {{.*}} f7l '_Float16':'_Float16' cinit
|
||||
//CHECK-NEXT: | `-CallExpr {{.*}} '_Float16':'_Float16'
|
||||
//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1t' '_Float16 (_Float16)' (FunctionTemplate {{.*}} 'func1t')
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f3l' '_Float16'
|
||||
|
||||
_Float16 f8l = f4l++;
|
||||
//CHECK: | `-VarDecl {{.*}} f8l '_Float16' cinit
|
||||
//CHECK-NEXT: | `-UnaryOperator {{.*}} '_Float16' postfix '++'
|
||||
//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f4l' '_Float16'
|
||||
|
||||
_Float16 arr1l[] = { -1.f16, -0.f16, -11.f16 };
|
||||
//CHECK: `-VarDecl {{.*}} arr1l '_Float16 [3]' cinit
|
||||
//CHECK-NEXT: `-InitListExpr {{.*}} '_Float16 [3]'
|
||||
//CHECK-NEXT: |-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
|
||||
//CHECK-NEXT: |-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 0.000000e+00
|
||||
//CHECK-NEXT: `-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: `-FloatingLiteral {{.*}} '_Float16' 1.100000e+01
|
||||
|
||||
float cvtf = f2n;
|
||||
//CHECK: `-VarDecl {{.*}} cvtf 'float' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'float' <FloatingCast>
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
|
||||
|
||||
double cvtd = f2n;
|
||||
//CHECK: `-VarDecl {{.*}} cvtd 'double' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'double' <FloatingCast>
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
|
||||
|
||||
long double cvtld = f2n;
|
||||
//CHECK: `-VarDecl {{.*}} cvtld 'long double' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
|
||||
|
||||
_Float16 f2h = 42.0f;
|
||||
//CHECK: `-VarDecl {{.*}} f2h '_Float16' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: `-FloatingLiteral {{.*}} 'float' 4.200000e+01
|
||||
|
||||
_Float16 d2h = 42.0;
|
||||
//CHECK: `-VarDecl {{.*}} d2h '_Float16' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: `-FloatingLiteral {{.*}} 'double' 4.200000e+01
|
||||
|
||||
_Float16 ld2h = 42.0l;
|
||||
//CHECK: `-VarDecl {{.*}} ld2h '_Float16' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: `-FloatingLiteral {{.*}} 'long double' 4.200000e+01
|
||||
}
|
||||
// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace
|
||||
// RUN: %clang_cc1 -std=c++11 -ast-dump -fnative-half-type %s | FileCheck %s --check-prefix=CHECK-NATIVE --strict-whitespace
|
||||
|
||||
/* Various contexts where type _Float16 can appear. */
|
||||
|
||||
/* Namespace */
|
||||
namespace {
|
||||
_Float16 f1n;
|
||||
_Float16 f2n = 33.f16;
|
||||
_Float16 arr1n[10];
|
||||
_Float16 arr2n[] = { 1.2, 3.0, 3.e4 };
|
||||
const volatile _Float16 func1n(const _Float16 &arg) {
|
||||
return arg + f2n + arr1n[4] - arr2n[1];
|
||||
}
|
||||
}
|
||||
|
||||
//CHECK: |-NamespaceDecl
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} f1n '_Float16'
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} f2n '_Float16' cinit
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 3.300000e+01
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} arr1n '_Float16 [10]'
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} arr2n '_Float16 [3]' cinit
|
||||
//CHECK-NEXT: | | `-InitListExpr {{.*}} '_Float16 [3]'
|
||||
//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | | | `-FloatingLiteral {{.*}} 'double' 1.200000e+00
|
||||
//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | | | `-FloatingLiteral {{.*}} 'double' 3.000000e+00
|
||||
//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} 'double' 3.000000e+04
|
||||
//CHECK-NEXT: | `-FunctionDecl {{.*}} func1n 'const volatile _Float16 (const _Float16 &)'
|
||||
|
||||
/* File */
|
||||
_Float16 f1f;
|
||||
_Float16 f2f = 32.4;
|
||||
_Float16 arr1f[10];
|
||||
_Float16 arr2f[] = { -1.2, -3.0, -3.e4 };
|
||||
_Float16 func1f(_Float16 arg);
|
||||
|
||||
//CHECK: |-VarDecl {{.*}} f1f '_Float16'
|
||||
//CHECK-NEXT: |-VarDecl {{.*}} f2f '_Float16' cinit
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 3.240000e+01
|
||||
//CHECK-NEXT: |-VarDecl {{.*}} arr1f '_Float16 [10]'
|
||||
//CHECK-NEXT: |-VarDecl {{.*}} arr2f '_Float16 [3]' cinit
|
||||
//CHECK-NEXT: | `-InitListExpr {{.*}} '_Float16 [3]'
|
||||
//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | | `-UnaryOperator {{.*}} 'double' prefix '-'
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} 'double' 1.200000e+00
|
||||
//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | | `-UnaryOperator {{.*}} 'double' prefix '-'
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} 'double' 3.000000e+00
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | `-UnaryOperator {{.*}} 'double' prefix '-'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 3.000000e+04
|
||||
//CHECK-NEXT: |-FunctionDecl {{.*}} func1f '_Float16 (_Float16)'
|
||||
//CHECK-NEXT: | `-ParmVarDecl {{.*}} arg '_Float16'
|
||||
|
||||
|
||||
// Mixing __fp16 and Float16 types:
|
||||
// The _Float16 type is first converted to __fp16 type and then the operation
|
||||
// is completed as if both operands were of __fp16 type.
|
||||
|
||||
__fp16 B = -0.1;
|
||||
auto C = -1.0f16 + B;
|
||||
|
||||
// When we do *not* have native half types, we expect __fp16 to be promoted to
|
||||
// float, and consequently also _Float16 promotions to float:
|
||||
|
||||
//CHECK: -VarDecl {{.*}} used B '__fp16' cinit
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '__fp16' <FloatingCast>
|
||||
//CHECK-NEXT: | `-UnaryOperator {{.*}} 'double' prefix '-'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 1.000000e-01
|
||||
//CHECK-NEXT: |-VarDecl {{.*}} C 'float':'float' cinit
|
||||
//CHECK-NEXT: | `-BinaryOperator {{.*}} 'float' '+'
|
||||
//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} 'float' <FloatingCast>
|
||||
//CHECK-NEXT: | | `-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'float' <FloatingCast>
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '__fp16' <LValueToRValue>
|
||||
//CHECK-NEXT: | `-DeclRefExpr {{.*}} '__fp16' lvalue Var 0x{{.*}} 'B' '__fp16'
|
||||
|
||||
// When do have native half types, we expect to see promotions to fp16:
|
||||
|
||||
//CHECK-NATIVE: |-VarDecl {{.*}} used B '__fp16' cinit
|
||||
//CHECK-NATIVE: | `-ImplicitCastExpr {{.*}} '__fp16' <FloatingCast>
|
||||
//CHECK-NATIVE: | `-UnaryOperator {{.*}} 'double' prefix '-'
|
||||
//CHECK-NATIVE: | `-FloatingLiteral {{.*}} 'double' 1.000000e-01
|
||||
//CHECK-NATIVE: |-VarDecl {{.*}} C '__fp16':'__fp16' cinit
|
||||
//CHECK-NATIVE: | `-BinaryOperator {{.*}} '__fp16' '+'
|
||||
//CHECK-NATIVE: | |-ImplicitCastExpr {{.*}} '__fp16' <FloatingCast>
|
||||
//CHECK-NATIVE: | | `-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NATIVE: | | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
|
||||
//CHECK-NATIVE: | `-ImplicitCastExpr {{.*}} '__fp16' <LValueToRValue>
|
||||
//CHECK-NATIVE: | `-DeclRefExpr {{.*}} '__fp16' lvalue Var 0x{{.*}} 'B' '__fp16'
|
||||
|
||||
|
||||
/* Class */
|
||||
|
||||
class C1 {
|
||||
_Float16 f1c;
|
||||
static const _Float16 f2c;
|
||||
volatile _Float16 f3c;
|
||||
public:
|
||||
C1(_Float16 arg) : f1c(arg), f3c(arg) { }
|
||||
_Float16 func1c(_Float16 arg ) {
|
||||
return f1c + arg;
|
||||
}
|
||||
static _Float16 func2c(_Float16 arg) {
|
||||
return arg * C1::f2c;
|
||||
}
|
||||
};
|
||||
|
||||
//CHECK: |-CXXRecordDecl {{.*}} referenced class C1 definition
|
||||
//CHECK: | |-CXXRecordDecl {{.*}} implicit referenced class C1
|
||||
//CHECK-NEXT: | |-FieldDecl {{.*}} referenced f1c '_Float16'
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} used f2c 'const _Float16' static
|
||||
//CHECK-NEXT: | |-FieldDecl {{.*}} f3c 'volatile _Float16'
|
||||
//CHECK-NEXT: | |-AccessSpecDecl
|
||||
//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} used C1 'void (_Float16)
|
||||
//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used arg '_Float16'
|
||||
//CHECK-NEXT: | | |-CXXCtorInitializer Field {{.*}} 'f1c' '_Float16'
|
||||
//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
|
||||
//CHECK-NEXT: | | |-CXXCtorInitializer Field {{.*}} 'f3c' 'volatile _Float16'
|
||||
//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
|
||||
//CHECK-NEXT: | | `-CompoundStmt
|
||||
//CHECK-NEXT: | |-CXXMethodDecl {{.*}} used func1c '_Float16 (_Float16)
|
||||
//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used arg '_Float16'
|
||||
//CHECK-NEXT: | | `-CompoundStmt
|
||||
//CHECK-NEXT: | | `-ReturnStmt
|
||||
//CHECK-NEXT: | | `-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | `-MemberExpr {{.*}} '_Float16' lvalue ->f1c 0x{{.*}}
|
||||
//CHECK-NEXT: | | | `-CXXThisExpr {{.*}} 'class C1 *' this
|
||||
//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
|
||||
//CHECK-NEXT: | |-CXXMethodDecl {{.*}} used func2c '_Float16 (_Float16)' static
|
||||
//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used arg '_Float16'
|
||||
//CHECK-NEXT: | | `-CompoundStmt
|
||||
//CHECK-NEXT: | | `-ReturnStmt
|
||||
//CHECK-NEXT: | | `-BinaryOperator {{.*}} '_Float16' '*'
|
||||
//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
|
||||
//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'const _Float16' lvalue Var 0x{{.*}} 'f2c' 'const _Float16'
|
||||
|
||||
|
||||
/* Template */
|
||||
|
||||
template <class C> C func1t(C arg) {
|
||||
return arg * 2.f16;
|
||||
}
|
||||
|
||||
//CHECK: |-FunctionTemplateDecl {{.*}} func1t
|
||||
//CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} C
|
||||
//CHECK-NEXT: | |-FunctionDecl {{.*}} func1t 'C (C)'
|
||||
//CHECK-NEXT: | | |-ParmVarDecl {{.*}} referenced arg 'C'
|
||||
//CHECK-NEXT: | | `-CompoundStmt
|
||||
//CHECK-NEXT: | | `-ReturnStmt
|
||||
//CHECK-NEXT: | | `-BinaryOperator {{.*}} '<dependent type>' '*'
|
||||
//CHECK-NEXT: | | |-DeclRefExpr {{.*}} 'C' lvalue ParmVar {{.*}} 'arg' 'C'
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 2.000000e+00
|
||||
//CHECK-NEXT: | `-FunctionDecl {{.*}} used func1t '_Float16 (_Float16)'
|
||||
//CHECK-NEXT: | |-TemplateArgument type '_Float16'
|
||||
//CHECK-NEXT: | |-ParmVarDecl {{.*}} used arg '_Float16':'_Float16'
|
||||
//CHECK-NEXT: | `-CompoundStmt
|
||||
//CHECK-NEXT: | `-ReturnStmt
|
||||
//CHECK-NEXT: | `-BinaryOperator {{.*}} '_Float16' '*'
|
||||
//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16':'_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16':'_Float16' lvalue ParmVar {{.*}} 'arg' '_Float16':'_Float16'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 2.000000e+00
|
||||
|
||||
|
||||
template <class C> struct S1 {
|
||||
C mem1;
|
||||
};
|
||||
|
||||
//CHECK: |-ClassTemplateDecl {{.*}} S1
|
||||
//CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} referenced class depth 0 index 0 C
|
||||
//CHECK-NEXT: | |-CXXRecordDecl {{.*}} struct S1 definition
|
||||
//CHECK: | | |-CXXRecordDecl {{.*}} implicit struct S1
|
||||
//CHECK-NEXT: | | `-FieldDecl {{.*}} mem1 'C'
|
||||
//CHECK-NEXT: | `-ClassTemplateSpecialization {{.*}} 'S1'
|
||||
|
||||
template <> struct S1<_Float16> {
|
||||
_Float16 mem2;
|
||||
};
|
||||
|
||||
|
||||
/* Local */
|
||||
|
||||
extern int printf (const char *__restrict __format, ...);
|
||||
|
||||
int main(void) {
|
||||
_Float16 f1l = 1e3f16;
|
||||
//CHECK: | `-VarDecl {{.*}} used f1l '_Float16' cinit
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+03
|
||||
|
||||
_Float16 f2l = -0.f16;
|
||||
//CHECK: | `-VarDecl {{.*}} used f2l '_Float16' cinit
|
||||
//CHECK-NEXT: | `-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 0.000000e+00
|
||||
|
||||
_Float16 f3l = 1.000976562;
|
||||
//CHECK: | `-VarDecl {{.*}} used f3l '_Float16' cinit
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 1.000977e+00
|
||||
|
||||
C1 c1(f1l);
|
||||
//CHECK: | `-VarDecl{{.*}} used c1 'class C1' callinit
|
||||
//CHECK-NEXT: | `-CXXConstructExpr {{.*}} 'class C1' 'void (_Float16)
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var 0x{{.*}} 'f1l' '_Float16'
|
||||
|
||||
S1<_Float16> s1 = { 132.f16 };
|
||||
//CHECK: | `-VarDecl {{.*}} used s1 'S1<_Float16>':'struct S1<_Float16>' cinit
|
||||
//CHECK-NEXT: | `-InitListExpr {{.*}} 'S1<_Float16>':'struct S1<_Float16>'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 1.320000e+02
|
||||
|
||||
_Float16 f4l = func1n(f1l) + func1f(f2l) + c1.func1c(f3l) + c1.func2c(f1l) +
|
||||
func1t(f1l) + s1.mem2 - f1n + f2n;
|
||||
//CHECK: | `-VarDecl {{.*}} used f4l '_Float16' cinit
|
||||
//CHECK-NEXT: | `-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | |-BinaryOperator {{.*}} '_Float16' '-'
|
||||
//CHECK-NEXT: | | |-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | | |-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | | | |-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | | | | |-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | | | | | |-BinaryOperator {{.*}} '_Float16' '+'
|
||||
//CHECK-NEXT: | | | | | | | |-CallExpr {{.*}} '_Float16'
|
||||
//CHECK-NEXT: | | | | | | | | |-ImplicitCastExpr {{.*}} 'const volatile _Float16 (*)(const _Float16 &)' <FunctionToPointerDecay>
|
||||
//CHECK-NEXT: | | | | | | | | | `-DeclRefExpr {{.*}} 'const volatile _Float16 (const _Float16 &)' lvalue Function {{.*}} 'func1n' 'const volatile _Float16 (const _Float16 &)'
|
||||
//CHECK-NEXT: | | | | | | | | `-ImplicitCastExpr {{.*}} 'const _Float16' lvalue <NoOp>
|
||||
//CHECK-NEXT: | | | | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1l' '_Float16'
|
||||
//CHECK-NEXT: | | | | | | | `-CallExpr {{.*}} '_Float16'
|
||||
//CHECK-NEXT: | | | | | | | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
|
||||
//CHECK-NEXT: | | | | | | | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1f' '_Float16 (_Float16)'
|
||||
//CHECK-NEXT: | | | | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2l' '_Float16'
|
||||
//CHECK-NEXT: | | | | | | `-CXXMemberCallExpr {{.*}} '_Float16'
|
||||
//CHECK-NEXT: | | | | | | |-MemberExpr {{.*}} '<bound member function type>' .func1c {{.*}}
|
||||
//CHECK-NEXT: | | | | | | | `-DeclRefExpr {{.*}} 'class C1' lvalue Var {{.*}} 'c1' 'class C1'
|
||||
//CHECK-NEXT: | | | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f3l' '_Float16'
|
||||
//CHECK-NEXT: | | | | | `-CallExpr {{.*}} '_Float16'
|
||||
//CHECK-NEXT: | | | | | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
|
||||
//CHECK-NEXT: | | | | | | `-MemberExpr {{.*}} '_Float16 (_Float16)' lvalue .func2c {{.*}}
|
||||
//CHECK-NEXT: | | | | | | `-DeclRefExpr {{.*}} 'class C1' lvalue Var {{.*}} 'c1' 'class C1'
|
||||
//CHECK-NEXT: | | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1l' '_Float16'
|
||||
//CHECK-NEXT: | | | | `-CallExpr {{.*}} '_Float16':'_Float16'
|
||||
//CHECK-NEXT: | | | | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
|
||||
//CHECK-NEXT: | | | | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1t' '_Float16 (_Float16)' (FunctionTemplate {{.*}} 'func1t')
|
||||
//CHECK-NEXT: | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1l' '_Float16'
|
||||
//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | | `-MemberExpr {{.*}} '_Float16' lvalue .mem2 {{.*}}
|
||||
//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'S1<_Float16>':'struct S1<_Float16>' lvalue Var {{.*}} 's1' 'S1<_Float16>':'struct S1<_Float16>'
|
||||
//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1n' '_Float16'
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
|
||||
|
||||
auto f5l = -1.f16, *f6l = &f2l, f7l = func1t(f3l);
|
||||
//CHECK: | |-VarDecl {{.*}} f5l '_Float16':'_Float16' cinit
|
||||
//CHECK-NEXT: | | `-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
|
||||
//CHECK-NEXT: | |-VarDecl {{.*}} f6l '_Float16 *' cinit
|
||||
//CHECK-NEXT: | | `-UnaryOperator {{.*}} '_Float16 *' prefix '&'
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2l' '_Float16'
|
||||
//CHECK-NEXT: | `-VarDecl {{.*}} f7l '_Float16':'_Float16' cinit
|
||||
//CHECK-NEXT: | `-CallExpr {{.*}} '_Float16':'_Float16'
|
||||
//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
|
||||
//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1t' '_Float16 (_Float16)' (FunctionTemplate {{.*}} 'func1t')
|
||||
//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f3l' '_Float16'
|
||||
|
||||
_Float16 f8l = f4l++;
|
||||
//CHECK: | `-VarDecl {{.*}} f8l '_Float16' cinit
|
||||
//CHECK-NEXT: | `-UnaryOperator {{.*}} '_Float16' postfix '++'
|
||||
//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f4l' '_Float16'
|
||||
|
||||
_Float16 arr1l[] = { -1.f16, -0.f16, -11.f16 };
|
||||
//CHECK: `-VarDecl {{.*}} arr1l '_Float16 [3]' cinit
|
||||
//CHECK-NEXT: `-InitListExpr {{.*}} '_Float16 [3]'
|
||||
//CHECK-NEXT: |-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
|
||||
//CHECK-NEXT: |-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 0.000000e+00
|
||||
//CHECK-NEXT: `-UnaryOperator {{.*}} '_Float16' prefix '-'
|
||||
//CHECK-NEXT: `-FloatingLiteral {{.*}} '_Float16' 1.100000e+01
|
||||
|
||||
float cvtf = f2n;
|
||||
//CHECK: `-VarDecl {{.*}} cvtf 'float' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'float' <FloatingCast>
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
|
||||
|
||||
double cvtd = f2n;
|
||||
//CHECK: `-VarDecl {{.*}} cvtd 'double' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'double' <FloatingCast>
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
|
||||
|
||||
long double cvtld = f2n;
|
||||
//CHECK: `-VarDecl {{.*}} cvtld 'long double' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
|
||||
//CHECK-NEXT: `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
|
||||
|
||||
_Float16 f2h = 42.0f;
|
||||
//CHECK: `-VarDecl {{.*}} f2h '_Float16' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: `-FloatingLiteral {{.*}} 'float' 4.200000e+01
|
||||
|
||||
_Float16 d2h = 42.0;
|
||||
//CHECK: `-VarDecl {{.*}} d2h '_Float16' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: `-FloatingLiteral {{.*}} 'double' 4.200000e+01
|
||||
|
||||
_Float16 ld2h = 42.0l;
|
||||
//CHECK: `-VarDecl {{.*}} ld2h '_Float16' cinit
|
||||
//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
|
||||
//CHECK-NEXT: `-FloatingLiteral {{.*}} 'long double' 4.200000e+01
|
||||
}
|
||||
|
|
|
@ -1,211 +1,211 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++11 -Wno-deprecated-declarations -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
|
||||
|
||||
int TestLocation
|
||||
__attribute__((unused));
|
||||
// CHECK: VarDecl{{.*}}TestLocation
|
||||
// CHECK-NEXT: UnusedAttr 0x{{[^ ]*}} <line:[[@LINE-2]]:16>
|
||||
|
||||
int TestIndent
|
||||
__attribute__((unused));
|
||||
// CHECK: {{^}}VarDecl{{.*TestIndent[^()]*$}}
|
||||
// CHECK-NEXT: {{^}}`-UnusedAttr{{[^()]*$}}
|
||||
|
||||
void TestAttributedStmt() {
|
||||
switch (1) {
|
||||
case 1:
|
||||
[[clang::fallthrough]];
|
||||
case 2:
|
||||
;
|
||||
}
|
||||
}
|
||||
// CHECK: FunctionDecl{{.*}}TestAttributedStmt
|
||||
// CHECK: AttributedStmt
|
||||
// CHECK-NEXT: FallThroughAttr
|
||||
// CHECK-NEXT: NullStmt
|
||||
|
||||
[[clang::warn_unused_result]] int TestCXX11DeclAttr();
|
||||
// CHECK: FunctionDecl{{.*}}TestCXX11DeclAttr
|
||||
// CHECK-NEXT: WarnUnusedResultAttr
|
||||
|
||||
int TestAlignedNull __attribute__((aligned));
|
||||
// CHECK: VarDecl{{.*}}TestAlignedNull
|
||||
// CHECK-NEXT: AlignedAttr {{.*}} aligned
|
||||
// CHECK-NEXT: <<<NULL>>>
|
||||
|
||||
int TestAlignedExpr __attribute__((aligned(4)));
|
||||
// CHECK: VarDecl{{.*}}TestAlignedExpr
|
||||
// CHECK-NEXT: AlignedAttr {{.*}} aligned
|
||||
// CHECK-NEXT: IntegerLiteral
|
||||
|
||||
int TestEnum __attribute__((visibility("default")));
|
||||
// CHECK: VarDecl{{.*}}TestEnum
|
||||
// CHECK-NEXT: VisibilityAttr{{.*}} Default
|
||||
|
||||
class __attribute__((lockable)) Mutex {
|
||||
} mu1, mu2;
|
||||
int TestExpr __attribute__((guarded_by(mu1)));
|
||||
// CHECK: VarDecl{{.*}}TestExpr
|
||||
// CHECK-NEXT: GuardedByAttr
|
||||
// CHECK-NEXT: DeclRefExpr{{.*}}mu1
|
||||
|
||||
class Mutex TestVariadicExpr __attribute__((acquired_after(mu1, mu2)));
|
||||
// CHECK: VarDecl{{.*}}TestVariadicExpr
|
||||
// CHECK: AcquiredAfterAttr
|
||||
// CHECK-NEXT: DeclRefExpr{{.*}}mu1
|
||||
// CHECK-NEXT: DeclRefExpr{{.*}}mu2
|
||||
|
||||
void function1(void *) {
|
||||
int TestFunction __attribute__((cleanup(function1)));
|
||||
}
|
||||
// CHECK: VarDecl{{.*}}TestFunction
|
||||
// CHECK-NEXT: CleanupAttr{{.*}} Function{{.*}}function1
|
||||
|
||||
void TestIdentifier(void *, int)
|
||||
__attribute__((pointer_with_type_tag(ident1,1,2)));
|
||||
// CHECK: FunctionDecl{{.*}}TestIdentifier
|
||||
// CHECK: ArgumentWithTypeTagAttr{{.*}} pointer_with_type_tag ident1
|
||||
|
||||
void TestBool(void *, int)
|
||||
__attribute__((pointer_with_type_tag(bool1,1,2)));
|
||||
// CHECK: FunctionDecl{{.*}}TestBool
|
||||
// CHECK: ArgumentWithTypeTagAttr{{.*}}pointer_with_type_tag bool1 0 1 IsPointer
|
||||
|
||||
void TestUnsigned(void *, int)
|
||||
__attribute__((pointer_with_type_tag(unsigned1,1,2)));
|
||||
// CHECK: FunctionDecl{{.*}}TestUnsigned
|
||||
// CHECK: ArgumentWithTypeTagAttr{{.*}} pointer_with_type_tag unsigned1 0 1
|
||||
|
||||
void TestInt(void) __attribute__((constructor(123)));
|
||||
// CHECK: FunctionDecl{{.*}}TestInt
|
||||
// CHECK-NEXT: ConstructorAttr{{.*}} 123
|
||||
|
||||
static int TestString __attribute__((alias("alias1")));
|
||||
// CHECK: VarDecl{{.*}}TestString
|
||||
// CHECK-NEXT: AliasAttr{{.*}} "alias1"
|
||||
|
||||
extern struct s1 TestType
|
||||
__attribute__((type_tag_for_datatype(ident1,int)));
|
||||
// CHECK: VarDecl{{.*}}TestType
|
||||
// CHECK-NEXT: TypeTagForDatatypeAttr{{.*}} int
|
||||
|
||||
void TestLabel() {
|
||||
L: __attribute__((unused)) int i;
|
||||
// CHECK: LabelStmt{{.*}}'L'
|
||||
// CHECK: VarDecl{{.*}}i 'int'
|
||||
// CHECK-NEXT: UnusedAttr{{.*}}
|
||||
|
||||
M: __attribute(()) int j;
|
||||
// CHECK: LabelStmt {{.*}} 'M'
|
||||
// CHECK-NEXT: DeclStmt
|
||||
// CHECK-NEXT: VarDecl {{.*}} j 'int'
|
||||
|
||||
N: __attribute(()) ;
|
||||
// CHECK: LabelStmt {{.*}} 'N'
|
||||
// CHECK-NEXT: NullStmt
|
||||
}
|
||||
|
||||
namespace Test {
|
||||
extern "C" int printf(const char *format, ...);
|
||||
// CHECK: FunctionDecl{{.*}}printf
|
||||
// CHECK-NEXT: ParmVarDecl{{.*}}format{{.*}}'const char *'
|
||||
// CHECK-NEXT: FormatAttr{{.*}}Implicit printf 1 2
|
||||
|
||||
alignas(8) extern int x;
|
||||
extern int x;
|
||||
// CHECK: VarDecl{{.*}} x 'int'
|
||||
// CHECK: VarDecl{{.*}} x 'int'
|
||||
// CHECK-NEXT: AlignedAttr{{.*}} Inherited
|
||||
}
|
||||
|
||||
int __attribute__((cdecl)) TestOne(void), TestTwo(void);
|
||||
// CHECK: FunctionDecl{{.*}}TestOne{{.*}}__attribute__((cdecl))
|
||||
// CHECK: FunctionDecl{{.*}}TestTwo{{.*}}__attribute__((cdecl))
|
||||
|
||||
void func() {
|
||||
auto Test = []() __attribute__((no_thread_safety_analysis)) {};
|
||||
// CHECK: CXXMethodDecl{{.*}}operator() 'void () const'
|
||||
// CHECK: NoThreadSafetyAnalysisAttr
|
||||
|
||||
// Because GNU's noreturn applies to the function type, and this lambda does
|
||||
// not have a capture list, the call operator and the function pointer
|
||||
// conversion should both be noreturn, but the method should not contain a
|
||||
// NoReturnAttr because the attribute applied to the type.
|
||||
auto Test2 = []() __attribute__((noreturn)) { while(1); };
|
||||
// CHECK: CXXMethodDecl{{.*}}operator() 'void () __attribute__((noreturn)) const'
|
||||
// CHECK-NOT: NoReturnAttr
|
||||
// CHECK: CXXConversionDecl{{.*}}operator void (*)() __attribute__((noreturn))
|
||||
}
|
||||
|
||||
namespace PR20930 {
|
||||
struct S {
|
||||
struct { int Test __attribute__((deprecated)); };
|
||||
// CHECK: FieldDecl{{.*}}Test 'int'
|
||||
// CHECK-NEXT: DeprecatedAttr
|
||||
};
|
||||
|
||||
void f() {
|
||||
S s;
|
||||
s.Test = 1;
|
||||
// CHECK: IndirectFieldDecl{{.*}}Test 'int'
|
||||
// CHECK: DeprecatedAttr
|
||||
}
|
||||
}
|
||||
|
||||
struct __attribute__((objc_bridge_related(NSParagraphStyle,,))) TestBridgedRef;
|
||||
// CHECK: CXXRecordDecl{{.*}} struct TestBridgedRef
|
||||
// CHECK-NEXT: ObjCBridgeRelatedAttr{{.*}} NSParagraphStyle
|
||||
|
||||
void TestExternalSourceSymbolAttr1()
|
||||
__attribute__((external_source_symbol(language="Swift", defined_in="module", generated_declaration)));
|
||||
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr1
|
||||
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration
|
||||
|
||||
void TestExternalSourceSymbolAttr2()
|
||||
__attribute__((external_source_symbol(defined_in="module", language="Swift")));
|
||||
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr2
|
||||
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module"{{$}}
|
||||
|
||||
void TestExternalSourceSymbolAttr3()
|
||||
__attribute__((external_source_symbol(generated_declaration, language="Objective-C++", defined_in="module")));
|
||||
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr3
|
||||
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Objective-C++" "module" GeneratedDeclaration
|
||||
|
||||
void TestExternalSourceSymbolAttr4()
|
||||
__attribute__((external_source_symbol(defined_in="Some external file.cs", generated_declaration, language="C Sharp")));
|
||||
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr4
|
||||
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "C Sharp" "Some external file.cs" GeneratedDeclaration
|
||||
|
||||
void TestExternalSourceSymbolAttr5()
|
||||
__attribute__((external_source_symbol(generated_declaration, defined_in="module", language="Swift")));
|
||||
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr5
|
||||
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration
|
||||
|
||||
namespace TestNoEscape {
|
||||
void noescapeFunc(int *p0, __attribute__((noescape)) int *p1) {}
|
||||
// CHECK: `-FunctionDecl{{.*}} noescapeFunc 'void (int *, __attribute__((noescape)) int *)'
|
||||
// CHECK-NEXT: ParmVarDecl
|
||||
// CHECK-NEXT: ParmVarDecl
|
||||
// CHECK-NEXT: NoEscapeAttr
|
||||
}
|
||||
|
||||
namespace TestSuppress {
|
||||
[[gsl::suppress("at-namespace")]];
|
||||
// CHECK: NamespaceDecl{{.*}} TestSuppress
|
||||
// CHECK-NEXT: EmptyDecl{{.*}}
|
||||
// CHECK-NEXT: SuppressAttr{{.*}} at-namespace
|
||||
[[gsl::suppress("on-decl")]]
|
||||
void TestSuppressFunction();
|
||||
// CHECK: FunctionDecl{{.*}} TestSuppressFunction
|
||||
// CHECK-NEXT SuppressAttr{{.*}} on-decl
|
||||
|
||||
void f() {
|
||||
int *i;
|
||||
|
||||
[[gsl::suppress("on-stmt")]] {
|
||||
// CHECK: AttributedStmt
|
||||
// CHECK-NEXT: SuppressAttr{{.*}} on-stmt
|
||||
// CHECK-NEXT: CompoundStmt
|
||||
i = reinterpret_cast<int*>(7);
|
||||
}
|
||||
}
|
||||
}
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++11 -Wno-deprecated-declarations -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
|
||||
|
||||
int TestLocation
|
||||
__attribute__((unused));
|
||||
// CHECK: VarDecl{{.*}}TestLocation
|
||||
// CHECK-NEXT: UnusedAttr 0x{{[^ ]*}} <line:[[@LINE-2]]:16>
|
||||
|
||||
int TestIndent
|
||||
__attribute__((unused));
|
||||
// CHECK: {{^}}VarDecl{{.*TestIndent[^()]*$}}
|
||||
// CHECK-NEXT: {{^}}`-UnusedAttr{{[^()]*$}}
|
||||
|
||||
void TestAttributedStmt() {
|
||||
switch (1) {
|
||||
case 1:
|
||||
[[clang::fallthrough]];
|
||||
case 2:
|
||||
;
|
||||
}
|
||||
}
|
||||
// CHECK: FunctionDecl{{.*}}TestAttributedStmt
|
||||
// CHECK: AttributedStmt
|
||||
// CHECK-NEXT: FallThroughAttr
|
||||
// CHECK-NEXT: NullStmt
|
||||
|
||||
[[clang::warn_unused_result]] int TestCXX11DeclAttr();
|
||||
// CHECK: FunctionDecl{{.*}}TestCXX11DeclAttr
|
||||
// CHECK-NEXT: WarnUnusedResultAttr
|
||||
|
||||
int TestAlignedNull __attribute__((aligned));
|
||||
// CHECK: VarDecl{{.*}}TestAlignedNull
|
||||
// CHECK-NEXT: AlignedAttr {{.*}} aligned
|
||||
// CHECK-NEXT: <<<NULL>>>
|
||||
|
||||
int TestAlignedExpr __attribute__((aligned(4)));
|
||||
// CHECK: VarDecl{{.*}}TestAlignedExpr
|
||||
// CHECK-NEXT: AlignedAttr {{.*}} aligned
|
||||
// CHECK-NEXT: IntegerLiteral
|
||||
|
||||
int TestEnum __attribute__((visibility("default")));
|
||||
// CHECK: VarDecl{{.*}}TestEnum
|
||||
// CHECK-NEXT: VisibilityAttr{{.*}} Default
|
||||
|
||||
class __attribute__((lockable)) Mutex {
|
||||
} mu1, mu2;
|
||||
int TestExpr __attribute__((guarded_by(mu1)));
|
||||
// CHECK: VarDecl{{.*}}TestExpr
|
||||
// CHECK-NEXT: GuardedByAttr
|
||||
// CHECK-NEXT: DeclRefExpr{{.*}}mu1
|
||||
|
||||
class Mutex TestVariadicExpr __attribute__((acquired_after(mu1, mu2)));
|
||||
// CHECK: VarDecl{{.*}}TestVariadicExpr
|
||||
// CHECK: AcquiredAfterAttr
|
||||
// CHECK-NEXT: DeclRefExpr{{.*}}mu1
|
||||
// CHECK-NEXT: DeclRefExpr{{.*}}mu2
|
||||
|
||||
void function1(void *) {
|
||||
int TestFunction __attribute__((cleanup(function1)));
|
||||
}
|
||||
// CHECK: VarDecl{{.*}}TestFunction
|
||||
// CHECK-NEXT: CleanupAttr{{.*}} Function{{.*}}function1
|
||||
|
||||
void TestIdentifier(void *, int)
|
||||
__attribute__((pointer_with_type_tag(ident1,1,2)));
|
||||
// CHECK: FunctionDecl{{.*}}TestIdentifier
|
||||
// CHECK: ArgumentWithTypeTagAttr{{.*}} pointer_with_type_tag ident1
|
||||
|
||||
void TestBool(void *, int)
|
||||
__attribute__((pointer_with_type_tag(bool1,1,2)));
|
||||
// CHECK: FunctionDecl{{.*}}TestBool
|
||||
// CHECK: ArgumentWithTypeTagAttr{{.*}}pointer_with_type_tag bool1 0 1 IsPointer
|
||||
|
||||
void TestUnsigned(void *, int)
|
||||
__attribute__((pointer_with_type_tag(unsigned1,1,2)));
|
||||
// CHECK: FunctionDecl{{.*}}TestUnsigned
|
||||
// CHECK: ArgumentWithTypeTagAttr{{.*}} pointer_with_type_tag unsigned1 0 1
|
||||
|
||||
void TestInt(void) __attribute__((constructor(123)));
|
||||
// CHECK: FunctionDecl{{.*}}TestInt
|
||||
// CHECK-NEXT: ConstructorAttr{{.*}} 123
|
||||
|
||||
static int TestString __attribute__((alias("alias1")));
|
||||
// CHECK: VarDecl{{.*}}TestString
|
||||
// CHECK-NEXT: AliasAttr{{.*}} "alias1"
|
||||
|
||||
extern struct s1 TestType
|
||||
__attribute__((type_tag_for_datatype(ident1,int)));
|
||||
// CHECK: VarDecl{{.*}}TestType
|
||||
// CHECK-NEXT: TypeTagForDatatypeAttr{{.*}} int
|
||||
|
||||
void TestLabel() {
|
||||
L: __attribute__((unused)) int i;
|
||||
// CHECK: LabelStmt{{.*}}'L'
|
||||
// CHECK: VarDecl{{.*}}i 'int'
|
||||
// CHECK-NEXT: UnusedAttr{{.*}}
|
||||
|
||||
M: __attribute(()) int j;
|
||||
// CHECK: LabelStmt {{.*}} 'M'
|
||||
// CHECK-NEXT: DeclStmt
|
||||
// CHECK-NEXT: VarDecl {{.*}} j 'int'
|
||||
|
||||
N: __attribute(()) ;
|
||||
// CHECK: LabelStmt {{.*}} 'N'
|
||||
// CHECK-NEXT: NullStmt
|
||||
}
|
||||
|
||||
namespace Test {
|
||||
extern "C" int printf(const char *format, ...);
|
||||
// CHECK: FunctionDecl{{.*}}printf
|
||||
// CHECK-NEXT: ParmVarDecl{{.*}}format{{.*}}'const char *'
|
||||
// CHECK-NEXT: FormatAttr{{.*}}Implicit printf 1 2
|
||||
|
||||
alignas(8) extern int x;
|
||||
extern int x;
|
||||
// CHECK: VarDecl{{.*}} x 'int'
|
||||
// CHECK: VarDecl{{.*}} x 'int'
|
||||
// CHECK-NEXT: AlignedAttr{{.*}} Inherited
|
||||
}
|
||||
|
||||
int __attribute__((cdecl)) TestOne(void), TestTwo(void);
|
||||
// CHECK: FunctionDecl{{.*}}TestOne{{.*}}__attribute__((cdecl))
|
||||
// CHECK: FunctionDecl{{.*}}TestTwo{{.*}}__attribute__((cdecl))
|
||||
|
||||
void func() {
|
||||
auto Test = []() __attribute__((no_thread_safety_analysis)) {};
|
||||
// CHECK: CXXMethodDecl{{.*}}operator() 'void (void) const'
|
||||
// CHECK: NoThreadSafetyAnalysisAttr
|
||||
|
||||
// Because GNU's noreturn applies to the function type, and this lambda does
|
||||
// not have a capture list, the call operator and the function pointer
|
||||
// conversion should both be noreturn, but the method should not contain a
|
||||
// NoReturnAttr because the attribute applied to the type.
|
||||
auto Test2 = []() __attribute__((noreturn)) { while(1); };
|
||||
// CHECK: CXXMethodDecl{{.*}}operator() 'void (void) __attribute__((noreturn)) const'
|
||||
// CHECK-NOT: NoReturnAttr
|
||||
// CHECK: CXXConversionDecl{{.*}}operator void (*)() __attribute__((noreturn))
|
||||
}
|
||||
|
||||
namespace PR20930 {
|
||||
struct S {
|
||||
struct { int Test __attribute__((deprecated)); };
|
||||
// CHECK: FieldDecl{{.*}}Test 'int'
|
||||
// CHECK-NEXT: DeprecatedAttr
|
||||
};
|
||||
|
||||
void f() {
|
||||
S s;
|
||||
s.Test = 1;
|
||||
// CHECK: IndirectFieldDecl{{.*}}Test 'int'
|
||||
// CHECK: DeprecatedAttr
|
||||
}
|
||||
}
|
||||
|
||||
struct __attribute__((objc_bridge_related(NSParagraphStyle,,))) TestBridgedRef;
|
||||
// CHECK: CXXRecordDecl{{.*}} struct TestBridgedRef
|
||||
// CHECK-NEXT: ObjCBridgeRelatedAttr{{.*}} NSParagraphStyle
|
||||
|
||||
void TestExternalSourceSymbolAttr1()
|
||||
__attribute__((external_source_symbol(language="Swift", defined_in="module", generated_declaration)));
|
||||
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr1
|
||||
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration
|
||||
|
||||
void TestExternalSourceSymbolAttr2()
|
||||
__attribute__((external_source_symbol(defined_in="module", language="Swift")));
|
||||
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr2
|
||||
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module"{{$}}
|
||||
|
||||
void TestExternalSourceSymbolAttr3()
|
||||
__attribute__((external_source_symbol(generated_declaration, language="Objective-C++", defined_in="module")));
|
||||
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr3
|
||||
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Objective-C++" "module" GeneratedDeclaration
|
||||
|
||||
void TestExternalSourceSymbolAttr4()
|
||||
__attribute__((external_source_symbol(defined_in="Some external file.cs", generated_declaration, language="C Sharp")));
|
||||
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr4
|
||||
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "C Sharp" "Some external file.cs" GeneratedDeclaration
|
||||
|
||||
void TestExternalSourceSymbolAttr5()
|
||||
__attribute__((external_source_symbol(generated_declaration, defined_in="module", language="Swift")));
|
||||
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr5
|
||||
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration
|
||||
|
||||
namespace TestNoEscape {
|
||||
void noescapeFunc(int *p0, __attribute__((noescape)) int *p1) {}
|
||||
// CHECK: `-FunctionDecl{{.*}} noescapeFunc 'void (int *, __attribute__((noescape)) int *)'
|
||||
// CHECK-NEXT: ParmVarDecl
|
||||
// CHECK-NEXT: ParmVarDecl
|
||||
// CHECK-NEXT: NoEscapeAttr
|
||||
}
|
||||
|
||||
namespace TestSuppress {
|
||||
[[gsl::suppress("at-namespace")]];
|
||||
// CHECK: NamespaceDecl{{.*}} TestSuppress
|
||||
// CHECK-NEXT: EmptyDecl{{.*}}
|
||||
// CHECK-NEXT: SuppressAttr{{.*}} at-namespace
|
||||
[[gsl::suppress("on-decl")]]
|
||||
void TestSuppressFunction();
|
||||
// CHECK: FunctionDecl{{.*}} TestSuppressFunction
|
||||
// CHECK-NEXT SuppressAttr{{.*}} on-decl
|
||||
|
||||
void f() {
|
||||
int *i;
|
||||
|
||||
[[gsl::suppress("on-stmt")]] {
|
||||
// CHECK: AttributedStmt
|
||||
// CHECK-NEXT: SuppressAttr{{.*}} on-stmt
|
||||
// CHECK-NEXT: CompoundStmt
|
||||
i = reinterpret_cast<int*>(7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ struct Invalid {
|
|||
//CHECK: {{^}}[[Blue]]| |-[[RESET]][[Blue]]HTMLEndTagComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:13[[RESET]], [[Yellow]]col:16[[RESET]]> Name="a"{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| |-[[RESET]][[Blue]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:5:4[[RESET]]> Text=" "{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[Blue]]HTMLStartTagComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:5[[RESET]], [[Yellow]]col:8[[RESET]]> Name="br" SelfClosing{{$}}
|
||||
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]FunctionDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:9:1[[RESET]], [[Yellow]]line:16:1[[RESET]]> [[Yellow]]line:9:6[[RESET]][[CYAN]] TestAttributedStmt[[RESET]] [[Green]]'void (void)'[[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]FunctionDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:9:1[[RESET]], [[Yellow]]line:16:1[[RESET]]> [[Yellow]]line:9:6[[RESET]][[CYAN]] TestAttributedStmt[[RESET]] [[Green]]'void ()'[[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| |-[[RESET]][[MAGENTA:.\[0;1;35m]]CompoundStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:27[[RESET]], [[Yellow]]line:16:1[[RESET]]>{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]SwitchStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:10:3[[RESET]], [[Yellow]]line:15:3[[RESET]]>{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[Blue:.\[0;34m]]<<<NULL>>>[[RESET]]{{$}}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,64 +1,64 @@
|
|||
// RUN: not %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -fms-extensions -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix CHECK -strict-whitespace %s
|
||||
|
||||
namespace TestInvalidRParenOnCXXUnresolvedConstructExpr {
|
||||
template <class T>
|
||||
void f(T i, T j) {
|
||||
return T (i, j;
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: NamespaceDecl {{.*}} <{{.*}}> {{.*}} TestInvalidRParenOnCXXUnresolvedConstructExpr
|
||||
// CHECK-NEXT: `-FunctionTemplateDecl
|
||||
// CHECK-NEXT: |-TemplateTypeParmDecl
|
||||
// CHECK-NEXT: `-FunctionDecl
|
||||
// CHECK-NEXT: |-ParmVarDecl
|
||||
// CHECK-NEXT: |-ParmVarDecl
|
||||
// CHECK-NEXT: `-CompoundStmt
|
||||
// CHECK-NEXT: `-ReturnStmt
|
||||
// CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} <col:10, col:16> 'T'
|
||||
// CHECK-NEXT: |-DeclRefExpr {{.*}} <col:13> 'T' lvalue ParmVar {{.*}} 'i' 'T'
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} <col:16> 'T' lvalue ParmVar {{.*}} 'j' 'T'
|
||||
|
||||
|
||||
namespace TestInvalidIf {
|
||||
int g(int i) {
|
||||
if (invalid_condition)
|
||||
return 4;
|
||||
else
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// CHECK: NamespaceDecl {{.*}} <{{.*}}> {{.*}} TestInvalidIf
|
||||
// CHECK-NEXT: `-FunctionDecl
|
||||
// CHECK-NEXT: |-ParmVarDecl
|
||||
// CHECK-NEXT: `-CompoundStmt
|
||||
// CHECK-NEXT: `-IfStmt {{.*}} <line:25:3, line:28:12>
|
||||
// CHECK-NEXT: |-<<<NULL>>>
|
||||
// CHECK-NEXT: |-<<<NULL>>>
|
||||
// CHECK-NEXT: |-OpaqueValueExpr {{.*}} <<invalid sloc>> 'bool'
|
||||
// CHECK-NEXT: |-ReturnStmt {{.*}} <line:26:5, col:12>
|
||||
// CHECK-NEXT: | `-IntegerLiteral {{.*}} <col:12> 'int' 4
|
||||
// CHECK-NEXT: `-ReturnStmt {{.*}} <line:28:5, col:12>
|
||||
// CHECK-NEXT: `-ImplicitCastExpr {{.*}} <col:12> 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} <col:12> 'int' lvalue ParmVar {{.*}} 'i' 'int'
|
||||
|
||||
namespace TestInvalidFunctionDecl {
|
||||
struct Str {
|
||||
double foo1(double, invalid_type);
|
||||
};
|
||||
double Str::foo1(double, invalid_type)
|
||||
{ return 45; }
|
||||
}
|
||||
// CHECK: NamespaceDecl {{.*}} <{{.*}}> {{.*}} TestInvalidFunctionDecl
|
||||
// CHECK-NEXT: |-CXXRecordDecl {{.*}} <line:46:1, line:48:1> line:46:8 struct Str definition
|
||||
// CHECK: | |-CXXRecordDecl {{.*}} <col:1, col:8> col:8 implicit struct Str
|
||||
// CHECK-NEXT: | `-CXXMethodDecl {{.*}} <line:47:4, col:36> col:11 invalid foo1 'double (double, int)'
|
||||
// CHECK-NEXT: | |-ParmVarDecl {{.*}} <col:16> col:22 'double'
|
||||
// CHECK-NEXT: | `-ParmVarDecl {{.*}} <col:24, <invalid sloc>> col:36 invalid 'int'
|
||||
// CHECK-NEXT: `-CXXMethodDecl {{.*}} parent {{.*}} <line:49:1, line:50:14> line:49:13 invalid foo1 'double (double, int)'
|
||||
// CHECK-NEXT: |-ParmVarDecl {{.*}} <col:18> col:24 'double'
|
||||
// CHECK-NEXT: |-ParmVarDecl {{.*}} <col:26, <invalid sloc>> col:38 invalid 'int'
|
||||
// CHECK-NEXT: `-CompoundStmt {{.*}} <line:50:1, col:14>
|
||||
// CHECK-NEXT: `-ReturnStmt {{.*}} <col:3, col:10>
|
||||
// CHECK-NEXT: `-ImplicitCastExpr {{.*}} <col:10> 'double' <IntegralToFloating>
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} <col:10> 'int' 45
|
||||
// RUN: not %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -fms-extensions -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix CHECK -strict-whitespace %s
|
||||
|
||||
namespace TestInvalidRParenOnCXXUnresolvedConstructExpr {
|
||||
template <class T>
|
||||
void f(T i, T j) {
|
||||
return T (i, j;
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: NamespaceDecl {{.*}} <{{.*}}> {{.*}} TestInvalidRParenOnCXXUnresolvedConstructExpr
|
||||
// CHECK-NEXT: `-FunctionTemplateDecl
|
||||
// CHECK-NEXT: |-TemplateTypeParmDecl
|
||||
// CHECK-NEXT: `-FunctionDecl
|
||||
// CHECK-NEXT: |-ParmVarDecl
|
||||
// CHECK-NEXT: |-ParmVarDecl
|
||||
// CHECK-NEXT: `-CompoundStmt
|
||||
// CHECK-NEXT: `-ReturnStmt
|
||||
// CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} <col:10, col:16> 'T'
|
||||
// CHECK-NEXT: |-DeclRefExpr {{.*}} <col:13> 'T' lvalue ParmVar {{.*}} 'i' 'T'
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} <col:16> 'T' lvalue ParmVar {{.*}} 'j' 'T'
|
||||
|
||||
|
||||
namespace TestInvalidIf {
|
||||
int g(int i) {
|
||||
if (invalid_condition)
|
||||
return 4;
|
||||
else
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// CHECK: NamespaceDecl {{.*}} <{{.*}}> {{.*}} TestInvalidIf
|
||||
// CHECK-NEXT: `-FunctionDecl
|
||||
// CHECK-NEXT: |-ParmVarDecl
|
||||
// CHECK-NEXT: `-CompoundStmt
|
||||
// CHECK-NEXT: `-IfStmt {{.*}} <line:25:3, line:28:12>
|
||||
// CHECK-NEXT: |-<<<NULL>>>
|
||||
// CHECK-NEXT: |-<<<NULL>>>
|
||||
// CHECK-NEXT: |-OpaqueValueExpr {{.*}} <<invalid sloc>> '_Bool'
|
||||
// CHECK-NEXT: |-ReturnStmt {{.*}} <line:26:5, col:12>
|
||||
// CHECK-NEXT: | `-IntegerLiteral {{.*}} <col:12> 'int' 4
|
||||
// CHECK-NEXT: `-ReturnStmt {{.*}} <line:28:5, col:12>
|
||||
// CHECK-NEXT: `-ImplicitCastExpr {{.*}} <col:12> 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} <col:12> 'int' lvalue ParmVar {{.*}} 'i' 'int'
|
||||
|
||||
namespace TestInvalidFunctionDecl {
|
||||
struct Str {
|
||||
double foo1(double, invalid_type);
|
||||
};
|
||||
double Str::foo1(double, invalid_type)
|
||||
{ return 45; }
|
||||
}
|
||||
// CHECK: NamespaceDecl {{.*}} <{{.*}}> {{.*}} TestInvalidFunctionDecl
|
||||
// CHECK-NEXT: |-CXXRecordDecl {{.*}} <line:46:1, line:48:1> line:46:8 struct Str definition
|
||||
// CHECK: | |-CXXRecordDecl {{.*}} <col:1, col:8> col:8 implicit struct Str
|
||||
// CHECK-NEXT: | `-CXXMethodDecl {{.*}} <line:47:4, col:36> col:11 invalid foo1 'double (double, int)'
|
||||
// CHECK-NEXT: | |-ParmVarDecl {{.*}} <col:16> col:22 'double'
|
||||
// CHECK-NEXT: | `-ParmVarDecl {{.*}} <col:24, <invalid sloc>> col:36 invalid 'int'
|
||||
// CHECK-NEXT: `-CXXMethodDecl {{.*}} parent {{.*}} <line:49:1, line:50:14> line:49:13 invalid foo1 'double (double, int)'
|
||||
// CHECK-NEXT: |-ParmVarDecl {{.*}} <col:18> col:24 'double'
|
||||
// CHECK-NEXT: |-ParmVarDecl {{.*}} <col:26, <invalid sloc>> col:38 invalid 'int'
|
||||
// CHECK-NEXT: `-CompoundStmt {{.*}} <line:50:1, col:14>
|
||||
// CHECK-NEXT: `-ReturnStmt {{.*}} <col:3, col:10>
|
||||
// CHECK-NEXT: `-ImplicitCastExpr {{.*}} <col:10> 'double' <IntegralToFloating>
|
||||
// CHECK-NEXT: `-IntegerLiteral {{.*}} <col:10> 'int' 45
|
||||
|
|
|
@ -1,68 +1,68 @@
|
|||
// RUN: %clang_cc1 -verify -fopenmp -ast-dump %s | FileCheck %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
int ga, gb;
|
||||
#pragma omp threadprivate(ga, gb)
|
||||
|
||||
// CHECK: |-OMPThreadPrivateDecl {{.+}} <col:9> col:9
|
||||
// CHECK-NEXT: | |-DeclRefExpr {{.+}} <col:27> 'int' lvalue Var {{.+}} 'ga' 'int'
|
||||
// CHECK-NEXT: | `-DeclRefExpr {{.+}} <col:31> 'int' lvalue Var {{.+}} 'gb' 'int'
|
||||
|
||||
#pragma omp declare reduction(+ : int, char : omp_out *= omp_in)
|
||||
|
||||
#pragma omp declare reduction(fun : float : omp_out += omp_in) initializer(omp_priv = omp_orig + 15)
|
||||
|
||||
// CHECK: |-OMPDeclareReductionDecl {{.+}} <line:11:35> col:35 operator+ 'int' combiner
|
||||
// CHECK-NEXT: | |-CompoundAssignOperator {{.+}} <col:47, col:58> 'int' lvalue '*=' ComputeLHSTy='int' ComputeResultTy='int'
|
||||
// CHECK-NEXT: | | |-DeclRefExpr {{.+}} <col:47> 'int' lvalue Var {{.+}} 'omp_out' 'int'
|
||||
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:58> 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:58> 'int' lvalue Var {{.+}} 'omp_in' 'int'
|
||||
// CHECK-NEXT: | |-VarDecl {{.+}} <col:35> col:35 implicit used omp_in 'int'
|
||||
// CHECK-NEXT: | `-VarDecl {{.+}} <col:35> col:35 implicit used omp_out 'int'
|
||||
// CHECK-NEXT: |-OMPDeclareReductionDecl {{.+}} <col:40> col:40 operator+ 'char' combiner
|
||||
// CHECK-NEXT: | |-CompoundAssignOperator {{.+}} <col:47, col:58> 'char' lvalue '*=' ComputeLHSTy='int' ComputeResultTy='int'
|
||||
// CHECK-NEXT: | | |-DeclRefExpr {{.+}} <col:47> 'char' lvalue Var {{.+}} 'omp_out' 'char'
|
||||
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:58> 'int' <IntegralCast>
|
||||
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:58> 'char' <LValueToRValue>
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:58> 'char' lvalue Var {{.+}} 'omp_in' 'char'
|
||||
// CHECK-NEXT: | |-VarDecl {{.+}} <col:40> col:40 implicit used omp_in 'char'
|
||||
// CHECK-NEXT: | `-VarDecl {{.+}} <col:40> col:40 implicit used omp_out 'char'
|
||||
// CHECK-NEXT: |-OMPDeclareReductionDecl {{.+}} <line:13:37> col:37 fun 'float' combiner initializer
|
||||
// CHECK-NEXT: | |-CompoundAssignOperator {{.+}} <col:45, col:56> 'float' lvalue '+=' ComputeLHSTy='float' ComputeResultTy='float'
|
||||
// CHECK-NEXT: | | |-DeclRefExpr {{.+}} <col:45> 'float' lvalue Var {{.+}} 'omp_out' 'float'
|
||||
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:56> 'float' <LValueToRValue>
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:56> 'float' lvalue Var {{.+}} 'omp_in' 'float'
|
||||
|
||||
struct S {
|
||||
int a, b;
|
||||
S() {
|
||||
#pragma omp parallel for default(none) private(a) shared(b) schedule(static, a)
|
||||
for (int i = 0; i < 0; ++i)
|
||||
++a;
|
||||
}
|
||||
};
|
||||
|
||||
// CHECK: | `-OMPParallelForDirective {{.+}} <line:39:9, col:80>
|
||||
// CHECK-NEXT: | |-OMPDefaultClause {{.+}} <col:26, col:40>
|
||||
// CHECK-NEXT: | |-OMPPrivateClause {{.+}} <col:40, col:51>
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:48> 'int' lvalue OMPCapturedExpr {{.+}} 'a' 'int &'
|
||||
// CHECK-NEXT: | |-OMPSharedClause {{.+}} <col:51, col:61>
|
||||
// CHECK-NEXT: | | `-MemberExpr {{.+}} <col:58> 'int' lvalue ->b
|
||||
// CHECK-NEXT: | | `-CXXThisExpr {{.+}} <col:58> 'S *' this
|
||||
// CHECK-NEXT: | |-OMPScheduleClause {{.+}} <col:61, col:79>
|
||||
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:78> 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:78> 'int' lvalue OMPCapturedExpr {{.+}} '.capture_expr.' 'int'
|
||||
// CHECK-NEXT: | |-CapturedStmt {{.+}} <line:40:5, line:41:9>
|
||||
// CHECK-NEXT: | | |-CapturedDecl {{.+}} <<invalid sloc>> <invalid sloc>
|
||||
// CHECK-NEXT: | | | |-ForStmt {{.+}} <line:40:5, line:41:9>
|
||||
// CHECK: | | | | `-UnaryOperator {{.+}} <line:41:7, col:9> 'int' lvalue prefix '++'
|
||||
// CHECK-NEXT: | | | | `-DeclRefExpr {{.+}} <col:9> 'int' lvalue OMPCapturedExpr {{.+}} 'a' 'int &'
|
||||
|
||||
#pragma omp declare simd
|
||||
#pragma omp declare simd inbranch
|
||||
void foo();
|
||||
|
||||
// CHECK: `-FunctionDecl {{.+}} <line:63:1, col:10> col:6 foo 'void ()'
|
||||
// CHECK-NEXT: |-OMPDeclareSimdDeclAttr {{.+}} <line:62:9, col:34> Implicit BS_Inbranch
|
||||
// CHECK: `-OMPDeclareSimdDeclAttr {{.+}} <line:61:9, col:25> Implicit BS_Undefined
|
||||
|
||||
// RUN: %clang_cc1 -verify -fopenmp -ast-dump %s | FileCheck %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
int ga, gb;
|
||||
#pragma omp threadprivate(ga, gb)
|
||||
|
||||
// CHECK: |-OMPThreadPrivateDecl {{.+}} <col:9> col:9
|
||||
// CHECK-NEXT: | |-DeclRefExpr {{.+}} <col:27> 'int' lvalue Var {{.+}} 'ga' 'int'
|
||||
// CHECK-NEXT: | `-DeclRefExpr {{.+}} <col:31> 'int' lvalue Var {{.+}} 'gb' 'int'
|
||||
|
||||
#pragma omp declare reduction(+ : int, char : omp_out *= omp_in)
|
||||
|
||||
#pragma omp declare reduction(fun : float : omp_out += omp_in) initializer(omp_priv = omp_orig + 15)
|
||||
|
||||
// CHECK: |-OMPDeclareReductionDecl {{.+}} <line:11:35> col:35 operator+ 'int' combiner
|
||||
// CHECK-NEXT: | |-CompoundAssignOperator {{.+}} <col:47, col:58> 'int' lvalue '*=' ComputeLHSTy='int' ComputeResultTy='int'
|
||||
// CHECK-NEXT: | | |-DeclRefExpr {{.+}} <col:47> 'int' lvalue Var {{.+}} 'omp_out' 'int'
|
||||
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:58> 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:58> 'int' lvalue Var {{.+}} 'omp_in' 'int'
|
||||
// CHECK-NEXT: | |-VarDecl {{.+}} <col:35> col:35 implicit used omp_in 'int'
|
||||
// CHECK-NEXT: | `-VarDecl {{.+}} <col:35> col:35 implicit used omp_out 'int'
|
||||
// CHECK-NEXT: |-OMPDeclareReductionDecl {{.+}} <col:40> col:40 operator+ 'char' combiner
|
||||
// CHECK-NEXT: | |-CompoundAssignOperator {{.+}} <col:47, col:58> 'char' lvalue '*=' ComputeLHSTy='int' ComputeResultTy='int'
|
||||
// CHECK-NEXT: | | |-DeclRefExpr {{.+}} <col:47> 'char' lvalue Var {{.+}} 'omp_out' 'char'
|
||||
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:58> 'int' <IntegralCast>
|
||||
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:58> 'char' <LValueToRValue>
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:58> 'char' lvalue Var {{.+}} 'omp_in' 'char'
|
||||
// CHECK-NEXT: | |-VarDecl {{.+}} <col:40> col:40 implicit used omp_in 'char'
|
||||
// CHECK-NEXT: | `-VarDecl {{.+}} <col:40> col:40 implicit used omp_out 'char'
|
||||
// CHECK-NEXT: |-OMPDeclareReductionDecl {{.+}} <line:13:37> col:37 fun 'float' combiner initializer
|
||||
// CHECK-NEXT: | |-CompoundAssignOperator {{.+}} <col:45, col:56> 'float' lvalue '+=' ComputeLHSTy='float' ComputeResultTy='float'
|
||||
// CHECK-NEXT: | | |-DeclRefExpr {{.+}} <col:45> 'float' lvalue Var {{.+}} 'omp_out' 'float'
|
||||
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:56> 'float' <LValueToRValue>
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:56> 'float' lvalue Var {{.+}} 'omp_in' 'float'
|
||||
|
||||
struct S {
|
||||
int a, b;
|
||||
S() {
|
||||
#pragma omp parallel for default(none) private(a) shared(b) schedule(static, a)
|
||||
for (int i = 0; i < 0; ++i)
|
||||
++a;
|
||||
}
|
||||
};
|
||||
|
||||
// CHECK: | `-OMPParallelForDirective {{.+}} <line:39:9, col:80>
|
||||
// CHECK-NEXT: | |-OMPDefaultClause {{.+}} <col:26, col:40>
|
||||
// CHECK-NEXT: | |-OMPPrivateClause {{.+}} <col:40, col:51>
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:48> 'int' lvalue OMPCapturedExpr {{.+}} 'a' 'int &'
|
||||
// CHECK-NEXT: | |-OMPSharedClause {{.+}} <col:51, col:61>
|
||||
// CHECK-NEXT: | | `-MemberExpr {{.+}} <col:58> 'int' lvalue ->b
|
||||
// CHECK-NEXT: | | `-CXXThisExpr {{.+}} <col:58> 'struct S *' this
|
||||
// CHECK-NEXT: | |-OMPScheduleClause {{.+}} <col:61, col:79>
|
||||
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:78> 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:78> 'int' lvalue OMPCapturedExpr {{.+}} '.capture_expr.' 'int'
|
||||
// CHECK-NEXT: | |-CapturedStmt {{.+}} <line:40:5, line:41:9>
|
||||
// CHECK-NEXT: | | |-CapturedDecl {{.+}} <<invalid sloc>> <invalid sloc>
|
||||
// CHECK-NEXT: | | | |-ForStmt {{.+}} <line:40:5, line:41:9>
|
||||
// CHECK: | | | | `-UnaryOperator {{.+}} <line:41:7, col:9> 'int' lvalue prefix '++'
|
||||
// CHECK-NEXT: | | | | `-DeclRefExpr {{.+}} <col:9> 'int' lvalue OMPCapturedExpr {{.+}} 'a' 'int &'
|
||||
|
||||
#pragma omp declare simd
|
||||
#pragma omp declare simd inbranch
|
||||
void foo();
|
||||
|
||||
// CHECK: `-FunctionDecl {{.+}} <line:63:1, col:10> col:6 foo 'void (void)'
|
||||
// CHECK-NEXT: |-OMPDeclareSimdDeclAttr {{.+}} <line:62:9, col:34> Implicit BS_Inbranch
|
||||
// CHECK: `-OMPDeclareSimdDeclAttr {{.+}} <line:61:9, col:25> Implicit BS_Undefined
|
||||
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.10 -std=c++11 -ast-dump %s | FileCheck %s
|
||||
// CHECK: CXXCtorInitializer Field {{.*}} 'ptr' 'void *'
|
||||
// CHECK: CXXCtorInitializer Field {{.*}} 'q' 'Q'
|
||||
|
||||
@interface NSObject
|
||||
@end
|
||||
|
||||
@interface I : NSObject
|
||||
@end
|
||||
|
||||
struct Q { Q(); };
|
||||
|
||||
struct S {
|
||||
S();
|
||||
void *ptr = nullptr;
|
||||
Q q;
|
||||
};
|
||||
|
||||
@implementation I
|
||||
S::S() {}
|
||||
@end
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.10 -std=c++11 -ast-dump %s | FileCheck %s
|
||||
// CHECK: CXXCtorInitializer Field {{.*}} 'ptr' 'void *'
|
||||
// CHECK: CXXCtorInitializer Field {{.*}} 'q' 'struct Q'
|
||||
|
||||
@interface NSObject
|
||||
@end
|
||||
|
||||
@interface I : NSObject
|
||||
@end
|
||||
|
||||
struct Q { Q(); };
|
||||
|
||||
struct S {
|
||||
S();
|
||||
void *ptr = nullptr;
|
||||
Q q;
|
||||
};
|
||||
|
||||
@implementation I
|
||||
S::S() {}
|
||||
@end
|
||||
|
|
|
@ -1,98 +1,98 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -std=c++03 -verify -ast-dump %s > %t-03
|
||||
// RUN: FileCheck --input-file=%t-03 %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -ast-dump %s > %t-11
|
||||
// RUN: FileCheck --input-file=%t-11 %s
|
||||
// RUN: FileCheck --input-file=%t-11 %s --check-prefix=CHECK-CXX11
|
||||
|
||||
// http://llvm.org/PR7905
|
||||
namespace PR7905 {
|
||||
struct S; // expected-note {{forward declaration}}
|
||||
void foo1() {
|
||||
(void)(S[]) {{3}}; // expected-error {{array has incomplete element type}}
|
||||
}
|
||||
|
||||
template <typename T> struct M { T m; };
|
||||
void foo2() {
|
||||
(void)(M<short> []) {{3}};
|
||||
}
|
||||
}
|
||||
|
||||
// Check compound literals mixed with C++11 list-initialization.
|
||||
namespace brace_initializers {
|
||||
struct POD {
|
||||
int x, y;
|
||||
};
|
||||
struct HasCtor {
|
||||
HasCtor(int x, int y);
|
||||
};
|
||||
struct HasDtor {
|
||||
int x, y;
|
||||
~HasDtor();
|
||||
};
|
||||
struct HasCtorDtor {
|
||||
HasCtorDtor(int x, int y);
|
||||
~HasCtorDtor();
|
||||
};
|
||||
|
||||
void test() {
|
||||
(void)(POD){1, 2};
|
||||
// CHECK-NOT: CXXBindTemporaryExpr {{.*}} 'brace_initializers::POD'
|
||||
// CHECK: CompoundLiteralExpr {{.*}} 'brace_initializers::POD'
|
||||
// CHECK-NEXT: InitListExpr {{.*}} 'brace_initializers::POD'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}}
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 2{{$}}
|
||||
|
||||
(void)(HasDtor){1, 2};
|
||||
// CHECK: CXXBindTemporaryExpr {{.*}} 'brace_initializers::HasDtor'
|
||||
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'brace_initializers::HasDtor'
|
||||
// CHECK-NEXT: InitListExpr {{.*}} 'brace_initializers::HasDtor'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}}
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 2{{$}}
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
(void)(HasCtor){1, 2};
|
||||
// CHECK-CXX11-NOT: CXXBindTemporaryExpr {{.*}} 'brace_initializers::HasCtor'
|
||||
// CHECK-CXX11: CompoundLiteralExpr {{.*}} 'brace_initializers::HasCtor'
|
||||
// CHECK-CXX11-NEXT: CXXTemporaryObjectExpr {{.*}} 'brace_initializers::HasCtor'
|
||||
// CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 1{{$}}
|
||||
// CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 2{{$}}
|
||||
|
||||
(void)(HasCtorDtor){1, 2};
|
||||
// CHECK-CXX11: CXXBindTemporaryExpr {{.*}} 'brace_initializers::HasCtorDtor'
|
||||
// CHECK-CXX11-NEXT: CompoundLiteralExpr {{.*}} 'brace_initializers::HasCtorDtor'
|
||||
// CHECK-CXX11-NEXT: CXXTemporaryObjectExpr {{.*}} 'brace_initializers::HasCtorDtor'
|
||||
// CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 1{{$}}
|
||||
// CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 2{{$}}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct PrivateDtor {
|
||||
int x, y;
|
||||
private:
|
||||
~PrivateDtor(); // expected-note {{declared private here}}
|
||||
};
|
||||
|
||||
void testPrivateDtor() {
|
||||
(void)(PrivateDtor){1, 2}; // expected-error {{temporary of type 'brace_initializers::PrivateDtor' has private destructor}}
|
||||
}
|
||||
}
|
||||
|
||||
// This doesn't necessarily need to be an error, but CodeGen can't handle it
|
||||
// at the moment.
|
||||
int PR17415 = (int){PR17415}; // expected-error {{initializer element is not a compile-time constant}}
|
||||
|
||||
// Make sure we accept this. (Not sure if we actually should... but we do
|
||||
// at the moment.)
|
||||
template<unsigned> struct Value { };
|
||||
template<typename T>
|
||||
int &check_narrowed(Value<sizeof((T){1.1})>);
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
// Compound literals in global lambdas have automatic storage duration
|
||||
// and are not subject to the constant-initialization rules.
|
||||
int computed_with_lambda = [] {
|
||||
int x = 5;
|
||||
int result = ((int[]) { x, x + 2, x + 4, x + 6 })[0];
|
||||
return result;
|
||||
}();
|
||||
#endif
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++03 -verify -ast-dump %s > %t-03
|
||||
// RUN: FileCheck --input-file=%t-03 %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -ast-dump %s > %t-11
|
||||
// RUN: FileCheck --input-file=%t-11 %s
|
||||
// RUN: FileCheck --input-file=%t-11 %s --check-prefix=CHECK-CXX11
|
||||
|
||||
// http://llvm.org/PR7905
|
||||
namespace PR7905 {
|
||||
struct S; // expected-note {{forward declaration}}
|
||||
void foo1() {
|
||||
(void)(S[]) {{3}}; // expected-error {{array has incomplete element type}}
|
||||
}
|
||||
|
||||
template <typename T> struct M { T m; };
|
||||
void foo2() {
|
||||
(void)(M<short> []) {{3}};
|
||||
}
|
||||
}
|
||||
|
||||
// Check compound literals mixed with C++11 list-initialization.
|
||||
namespace brace_initializers {
|
||||
struct POD {
|
||||
int x, y;
|
||||
};
|
||||
struct HasCtor {
|
||||
HasCtor(int x, int y);
|
||||
};
|
||||
struct HasDtor {
|
||||
int x, y;
|
||||
~HasDtor();
|
||||
};
|
||||
struct HasCtorDtor {
|
||||
HasCtorDtor(int x, int y);
|
||||
~HasCtorDtor();
|
||||
};
|
||||
|
||||
void test() {
|
||||
(void)(POD){1, 2};
|
||||
// CHECK-NOT: CXXBindTemporaryExpr {{.*}} 'struct brace_initializers::POD'
|
||||
// CHECK: CompoundLiteralExpr {{.*}} 'struct brace_initializers::POD'
|
||||
// CHECK-NEXT: InitListExpr {{.*}} 'struct brace_initializers::POD'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}}
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 2{{$}}
|
||||
|
||||
(void)(HasDtor){1, 2};
|
||||
// CHECK: CXXBindTemporaryExpr {{.*}} 'struct brace_initializers::HasDtor'
|
||||
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'struct brace_initializers::HasDtor'
|
||||
// CHECK-NEXT: InitListExpr {{.*}} 'struct brace_initializers::HasDtor'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 1{{$}}
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 2{{$}}
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
(void)(HasCtor){1, 2};
|
||||
// CHECK-CXX11-NOT: CXXBindTemporaryExpr {{.*}} 'struct brace_initializers::HasCtor'
|
||||
// CHECK-CXX11: CompoundLiteralExpr {{.*}} 'struct brace_initializers::HasCtor'
|
||||
// CHECK-CXX11-NEXT: CXXTemporaryObjectExpr {{.*}} 'struct brace_initializers::HasCtor'
|
||||
// CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 1{{$}}
|
||||
// CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 2{{$}}
|
||||
|
||||
(void)(HasCtorDtor){1, 2};
|
||||
// CHECK-CXX11: CXXBindTemporaryExpr {{.*}} 'struct brace_initializers::HasCtorDtor'
|
||||
// CHECK-CXX11-NEXT: CompoundLiteralExpr {{.*}} 'struct brace_initializers::HasCtorDtor'
|
||||
// CHECK-CXX11-NEXT: CXXTemporaryObjectExpr {{.*}} 'struct brace_initializers::HasCtorDtor'
|
||||
// CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 1{{$}}
|
||||
// CHECK-CXX11-NEXT: IntegerLiteral {{.*}} 2{{$}}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct PrivateDtor {
|
||||
int x, y;
|
||||
private:
|
||||
~PrivateDtor(); // expected-note {{declared private here}}
|
||||
};
|
||||
|
||||
void testPrivateDtor() {
|
||||
(void)(PrivateDtor){1, 2}; // expected-error {{temporary of type 'brace_initializers::PrivateDtor' has private destructor}}
|
||||
}
|
||||
}
|
||||
|
||||
// This doesn't necessarily need to be an error, but CodeGen can't handle it
|
||||
// at the moment.
|
||||
int PR17415 = (int){PR17415}; // expected-error {{initializer element is not a compile-time constant}}
|
||||
|
||||
// Make sure we accept this. (Not sure if we actually should... but we do
|
||||
// at the moment.)
|
||||
template<unsigned> struct Value { };
|
||||
template<typename T>
|
||||
int &check_narrowed(Value<sizeof((T){1.1})>);
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
// Compound literals in global lambdas have automatic storage duration
|
||||
// and are not subject to the constant-initialization rules.
|
||||
int computed_with_lambda = [] {
|
||||
int x = 5;
|
||||
int result = ((int[]) { x, x + 2, x + 4, x + 6 })[0];
|
||||
return result;
|
||||
}();
|
||||
#endif
|
||||
|
|
|
@ -1,52 +1,52 @@
|
|||
// RUN: %clang_cc1 -triple i686-mingw32 -ast-dump %s | FileCheck %s
|
||||
|
||||
template<class T>
|
||||
class P {
|
||||
public:
|
||||
P(T* t) {}
|
||||
};
|
||||
|
||||
namespace foo {
|
||||
class A { public: A(int = 0) {} };
|
||||
enum B {};
|
||||
typedef int C;
|
||||
}
|
||||
|
||||
// CHECK: VarDecl {{0x[0-9a-fA-F]+}} <line:16:1, col:36> col:15 ImplicitConstrArray 'foo::A [2]'
|
||||
static foo::A ImplicitConstrArray[2];
|
||||
|
||||
int main() {
|
||||
// CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::A *'
|
||||
P<foo::A> p14 = new foo::A;
|
||||
// CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::B *'
|
||||
P<foo::B> p24 = new foo::B;
|
||||
// CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::C *'
|
||||
P<foo::C> pr4 = new foo::C;
|
||||
}
|
||||
|
||||
foo::A getName() {
|
||||
// CHECK: CXXConstructExpr {{0x[0-9a-fA-F]+}} <col:10, col:17> 'foo::A'
|
||||
return foo::A();
|
||||
}
|
||||
|
||||
void destruct(foo::A *a1, foo::A *a2, P<int> *p1) {
|
||||
// CHECK: MemberExpr {{0x[0-9a-fA-F]+}} <col:3, col:8> '<bound member function type>' ->~A
|
||||
a1->~A();
|
||||
// CHECK: MemberExpr {{0x[0-9a-fA-F]+}} <col:3, col:16> '<bound member function type>' ->~A
|
||||
a2->foo::A::~A();
|
||||
// CHECK: MemberExpr {{0x[0-9a-fA-F]+}} <col:3, col:13> '<bound member function type>' ->~P
|
||||
p1->~P<int>();
|
||||
}
|
||||
|
||||
struct D {
|
||||
D(int);
|
||||
~D();
|
||||
};
|
||||
|
||||
void construct() {
|
||||
using namespace foo;
|
||||
A a = A(12);
|
||||
// CHECK: CXXConstructExpr {{0x[0-9a-fA-F]+}} <col:9, col:13> 'foo::A' 'void (int){{( __attribute__\(\(thiscall\)\))?}}'
|
||||
D d = D(12);
|
||||
// CHECK: CXXConstructExpr {{0x[0-9a-fA-F]+}} <col:9, col:13> 'D' 'void (int){{( __attribute__\(\(thiscall\)\))?}}'
|
||||
}
|
||||
// RUN: %clang_cc1 -triple i686-mingw32 -ast-dump %s | FileCheck %s
|
||||
|
||||
template<class T>
|
||||
class P {
|
||||
public:
|
||||
P(T* t) {}
|
||||
};
|
||||
|
||||
namespace foo {
|
||||
class A { public: A(int = 0) {} };
|
||||
enum B {};
|
||||
typedef int C;
|
||||
}
|
||||
|
||||
// CHECK: VarDecl {{0x[0-9a-fA-F]+}} <line:16:1, col:36> col:15 ImplicitConstrArray 'foo::A [2]'
|
||||
static foo::A ImplicitConstrArray[2];
|
||||
|
||||
int main() {
|
||||
// CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::A *'
|
||||
P<foo::A> p14 = new foo::A;
|
||||
// CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::B *'
|
||||
P<foo::B> p24 = new foo::B;
|
||||
// CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::C *'
|
||||
P<foo::C> pr4 = new foo::C;
|
||||
}
|
||||
|
||||
foo::A getName() {
|
||||
// CHECK: CXXConstructExpr {{0x[0-9a-fA-F]+}} <col:10, col:17> 'foo::A'
|
||||
return foo::A();
|
||||
}
|
||||
|
||||
void destruct(foo::A *a1, foo::A *a2, P<int> *p1) {
|
||||
// CHECK: MemberExpr {{0x[0-9a-fA-F]+}} <col:3, col:8> '<bound member function type>' ->~A
|
||||
a1->~A();
|
||||
// CHECK: MemberExpr {{0x[0-9a-fA-F]+}} <col:3, col:16> '<bound member function type>' ->~A
|
||||
a2->foo::A::~A();
|
||||
// CHECK: MemberExpr {{0x[0-9a-fA-F]+}} <col:3, col:13> '<bound member function type>' ->~P
|
||||
p1->~P<int>();
|
||||
}
|
||||
|
||||
struct D {
|
||||
D(int);
|
||||
~D();
|
||||
};
|
||||
|
||||
void construct() {
|
||||
using namespace foo;
|
||||
A a = A(12);
|
||||
// CHECK: CXXConstructExpr {{0x[0-9a-fA-F]+}} <col:9, col:13> 'class foo::A' 'void (int){{( __attribute__\(\(thiscall\)\))?}}'
|
||||
D d = D(12);
|
||||
// CHECK: CXXConstructExpr {{0x[0-9a-fA-F]+}} <col:9, col:13> 'struct D' 'void (int){{( __attribute__\(\(thiscall\)\))?}}'
|
||||
}
|
||||
|
|
|
@ -1,116 +1,116 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11 -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -ast-dump | FileCheck %s --check-prefix=CHECK-AST
|
||||
|
||||
// definitions for std::move
|
||||
namespace std {
|
||||
inline namespace foo {
|
||||
template <class T> struct remove_reference { typedef T type; };
|
||||
template <class T> struct remove_reference<T&> { typedef T type; };
|
||||
template <class T> struct remove_reference<T&&> { typedef T type; };
|
||||
|
||||
template <class T> typename remove_reference<T>::type &&move(T &&t);
|
||||
}
|
||||
}
|
||||
|
||||
// test1 and test2 should not warn until after implementation of DR1579.
|
||||
struct A {};
|
||||
struct B : public A {};
|
||||
|
||||
A test1(B b1) {
|
||||
B b2;
|
||||
return b1;
|
||||
return b2;
|
||||
return std::move(b1);
|
||||
return std::move(b2);
|
||||
}
|
||||
|
||||
struct C {
|
||||
C() {}
|
||||
C(A) {}
|
||||
};
|
||||
|
||||
C test2(A a1, B b1) {
|
||||
A a2;
|
||||
B b2;
|
||||
|
||||
return a1;
|
||||
return a2;
|
||||
return b1;
|
||||
return b2;
|
||||
|
||||
return std::move(a1);
|
||||
return std::move(a2);
|
||||
return std::move(b1);
|
||||
return std::move(b2);
|
||||
}
|
||||
|
||||
// Copy of tests above with types changed to reference types.
|
||||
A test3(B& b1) {
|
||||
B& b2 = b1;
|
||||
return b1;
|
||||
return b2;
|
||||
return std::move(b1);
|
||||
return std::move(b2);
|
||||
}
|
||||
|
||||
C test4(A& a1, B& b1) {
|
||||
A& a2 = a1;
|
||||
B& b2 = b1;
|
||||
|
||||
return a1;
|
||||
return a2;
|
||||
return b1;
|
||||
return b2;
|
||||
|
||||
return std::move(a1);
|
||||
return std::move(a2);
|
||||
return std::move(b1);
|
||||
return std::move(b2);
|
||||
}
|
||||
|
||||
// PR23819, case 2
|
||||
struct D {};
|
||||
D test5(D d) {
|
||||
return d;
|
||||
// Verify the implicit move from the AST dump
|
||||
// CHECK-AST: ReturnStmt{{.*}}line:[[@LINE-2]]
|
||||
// CHECK-AST-NEXT: CXXConstructExpr{{.*}}D{{.*}}void (D &&)
|
||||
// CHECK-AST-NEXT: ImplicitCastExpr
|
||||
// CHECK-AST-NEXT: DeclRefExpr{{.*}}ParmVar{{.*}}'d'
|
||||
|
||||
return std::move(d);
|
||||
// expected-warning@-1{{redundant move in return statement}}
|
||||
// expected-note@-2{{remove std::move call here}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:21-[[@LINE-4]]:22}:""
|
||||
}
|
||||
|
||||
namespace templates {
|
||||
struct A {};
|
||||
struct B { B(A); };
|
||||
|
||||
// Warn once here since the type is not dependent.
|
||||
template <typename T>
|
||||
A test1(A a) {
|
||||
return std::move(a);
|
||||
// expected-warning@-1{{redundant move in return statement}}
|
||||
// expected-note@-2{{remove std::move call here}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:22}:""
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:""
|
||||
}
|
||||
void run_test1() {
|
||||
test1<A>(A());
|
||||
test1<B>(A());
|
||||
}
|
||||
|
||||
// T1 and T2 may not be the same, the warning may not always apply.
|
||||
template <typename T1, typename T2>
|
||||
T1 test2(T2 t) {
|
||||
return std::move(t);
|
||||
}
|
||||
void run_test2() {
|
||||
test2<A, A>(A());
|
||||
test2<B, A>(A());
|
||||
}
|
||||
}
|
||||
// RUN: %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11 -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -ast-dump | FileCheck %s --check-prefix=CHECK-AST
|
||||
|
||||
// definitions for std::move
|
||||
namespace std {
|
||||
inline namespace foo {
|
||||
template <class T> struct remove_reference { typedef T type; };
|
||||
template <class T> struct remove_reference<T&> { typedef T type; };
|
||||
template <class T> struct remove_reference<T&&> { typedef T type; };
|
||||
|
||||
template <class T> typename remove_reference<T>::type &&move(T &&t);
|
||||
}
|
||||
}
|
||||
|
||||
// test1 and test2 should not warn until after implementation of DR1579.
|
||||
struct A {};
|
||||
struct B : public A {};
|
||||
|
||||
A test1(B b1) {
|
||||
B b2;
|
||||
return b1;
|
||||
return b2;
|
||||
return std::move(b1);
|
||||
return std::move(b2);
|
||||
}
|
||||
|
||||
struct C {
|
||||
C() {}
|
||||
C(A) {}
|
||||
};
|
||||
|
||||
C test2(A a1, B b1) {
|
||||
A a2;
|
||||
B b2;
|
||||
|
||||
return a1;
|
||||
return a2;
|
||||
return b1;
|
||||
return b2;
|
||||
|
||||
return std::move(a1);
|
||||
return std::move(a2);
|
||||
return std::move(b1);
|
||||
return std::move(b2);
|
||||
}
|
||||
|
||||
// Copy of tests above with types changed to reference types.
|
||||
A test3(B& b1) {
|
||||
B& b2 = b1;
|
||||
return b1;
|
||||
return b2;
|
||||
return std::move(b1);
|
||||
return std::move(b2);
|
||||
}
|
||||
|
||||
C test4(A& a1, B& b1) {
|
||||
A& a2 = a1;
|
||||
B& b2 = b1;
|
||||
|
||||
return a1;
|
||||
return a2;
|
||||
return b1;
|
||||
return b2;
|
||||
|
||||
return std::move(a1);
|
||||
return std::move(a2);
|
||||
return std::move(b1);
|
||||
return std::move(b2);
|
||||
}
|
||||
|
||||
// PR23819, case 2
|
||||
struct D {};
|
||||
D test5(D d) {
|
||||
return d;
|
||||
// Verify the implicit move from the AST dump
|
||||
// CHECK-AST: ReturnStmt{{.*}}line:[[@LINE-2]]
|
||||
// CHECK-AST-NEXT: CXXConstructExpr{{.*}}struct D{{.*}}void (struct D &&)
|
||||
// CHECK-AST-NEXT: ImplicitCastExpr
|
||||
// CHECK-AST-NEXT: DeclRefExpr{{.*}}ParmVar{{.*}}'d'
|
||||
|
||||
return std::move(d);
|
||||
// expected-warning@-1{{redundant move in return statement}}
|
||||
// expected-note@-2{{remove std::move call here}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:21-[[@LINE-4]]:22}:""
|
||||
}
|
||||
|
||||
namespace templates {
|
||||
struct A {};
|
||||
struct B { B(A); };
|
||||
|
||||
// Warn once here since the type is not dependent.
|
||||
template <typename T>
|
||||
A test1(A a) {
|
||||
return std::move(a);
|
||||
// expected-warning@-1{{redundant move in return statement}}
|
||||
// expected-note@-2{{remove std::move call here}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:22}:""
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:""
|
||||
}
|
||||
void run_test1() {
|
||||
test1<A>(A());
|
||||
test1<B>(A());
|
||||
}
|
||||
|
||||
// T1 and T2 may not be the same, the warning may not always apply.
|
||||
template <typename T1, typename T2>
|
||||
T1 test2(T2 t) {
|
||||
return std::move(t);
|
||||
}
|
||||
void run_test2() {
|
||||
test2<A, A>(A());
|
||||
test2<B, A>(A());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11.0 -std=gnu++11 -o /dev/null -x objective-c++ -fblocks -ast-dump %s 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: -FunctionDecl {{.*}} test 'id ()'
|
||||
// CHECK-NEXT: -CompoundStmt
|
||||
// CHECK-NEXT: -ReturnStmt
|
||||
// CHECK-NEXT: -ExprWithCleanups
|
||||
// CHECK-NEXT: -cleanup Block
|
||||
// CHECK-NEXT: -cleanup Block
|
||||
|
||||
@interface NSDictionary
|
||||
+ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
|
||||
@end
|
||||
|
||||
id test() {
|
||||
return @{@"a": [](){}, @"b": [](){}};
|
||||
}
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11.0 -std=gnu++11 -o /dev/null -x objective-c++ -fblocks -ast-dump %s 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: -FunctionDecl {{.*}} test 'id (void)'
|
||||
// CHECK-NEXT: -CompoundStmt
|
||||
// CHECK-NEXT: -ReturnStmt
|
||||
// CHECK-NEXT: -ExprWithCleanups
|
||||
// CHECK-NEXT: -cleanup Block
|
||||
// CHECK-NEXT: -cleanup Block
|
||||
|
||||
@interface NSDictionary
|
||||
+ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
|
||||
@end
|
||||
|
||||
id test() {
|
||||
return @{@"a": [](){}, @"b": [](){}};
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ namespace PR6733 {
|
|||
public: enum { kSomeConst = 128 };
|
||||
bar(int x = kSomeConst) {}
|
||||
};
|
||||
|
||||
// CHECK: FunctionDecl{{.*}}f 'void ()'
|
||||
|
||||
// CHECK: FunctionDecl{{.*}}f 'void (void)'
|
||||
void f() {
|
||||
// CHECK: VarDecl{{.*}}tmp 'bar<int>'
|
||||
// CHECK: CXXDefaultArgExpr{{.*}}'int'
|
||||
|
|
|
@ -1,55 +1,55 @@
|
|||
// RUN: %clang_cc1 -std=c++14 -verify -ast-dump %s | FileCheck %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
// CHECK: FunctionDecl {{.*}} used func 'void ()'
|
||||
// CHECK-NEXT: TemplateArgument type 'int'
|
||||
// CHECK: LambdaExpr {{.*}} '(lambda at
|
||||
// CHECK: ParmVarDecl {{.*}} used f 'foo' cinit
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'foo' EnumConstant {{.*}} 'a' 'foo'
|
||||
|
||||
namespace PR28795 {
|
||||
template<typename T>
|
||||
void func() {
|
||||
enum class foo { a, b };
|
||||
auto bar = [](foo f = foo::a) { return f; };
|
||||
bar();
|
||||
}
|
||||
|
||||
void foo() {
|
||||
func<int>();
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct class2 definition
|
||||
// CHECK: TemplateArgument type 'int'
|
||||
// CHECK: LambdaExpr {{.*}} '(lambda at
|
||||
// CHECK: ParmVarDecl {{.*}} used f 'foo' cinit
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'foo' EnumConstant {{.*}} 'a' 'foo'
|
||||
|
||||
// Template struct case:
|
||||
template <class T> struct class2 {
|
||||
void bar() {
|
||||
enum class foo { a, b };
|
||||
[](foo f = foo::a) { return f; }();
|
||||
}
|
||||
};
|
||||
|
||||
template struct class2<int>;
|
||||
|
||||
// CHECK: FunctionTemplateDecl {{.*}} f1
|
||||
// CHECK-NEXT: TemplateTypeParmDecl {{.*}} typename depth 0 index 0 T
|
||||
// CHECK-NEXT: FunctionDecl {{.*}} f1 'void ()'
|
||||
// CHECK: FunctionDecl {{.*}} f1 'void ()'
|
||||
// CHECK-NEXT: TemplateArgument type 'int'
|
||||
// CHECK: ParmVarDecl {{.*}} n 'foo' cinit
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'foo' EnumConstant {{.*}} 'a' 'foo'
|
||||
|
||||
template<typename T>
|
||||
void f1() {
|
||||
enum class foo { a, b };
|
||||
struct S {
|
||||
int g1(foo n = foo::a);
|
||||
};
|
||||
}
|
||||
|
||||
template void f1<int>();
|
||||
// RUN: %clang_cc1 -std=c++14 -verify -ast-dump %s | FileCheck %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
// CHECK: FunctionDecl {{.*}} used func 'void (void)'
|
||||
// CHECK-NEXT: TemplateArgument type 'int'
|
||||
// CHECK: LambdaExpr {{.*}} 'class (lambda at
|
||||
// CHECK: ParmVarDecl {{.*}} used f 'enum foo' cinit
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'enum foo' EnumConstant {{.*}} 'a' 'enum foo'
|
||||
|
||||
namespace PR28795 {
|
||||
template<typename T>
|
||||
void func() {
|
||||
enum class foo { a, b };
|
||||
auto bar = [](foo f = foo::a) { return f; };
|
||||
bar();
|
||||
}
|
||||
|
||||
void foo() {
|
||||
func<int>();
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct class2 definition
|
||||
// CHECK: TemplateArgument type 'int'
|
||||
// CHECK: LambdaExpr {{.*}} 'class (lambda at
|
||||
// CHECK: ParmVarDecl {{.*}} used f 'enum foo' cinit
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'enum foo' EnumConstant {{.*}} 'a' 'enum foo'
|
||||
|
||||
// Template struct case:
|
||||
template <class T> struct class2 {
|
||||
void bar() {
|
||||
enum class foo { a, b };
|
||||
[](foo f = foo::a) { return f; }();
|
||||
}
|
||||
};
|
||||
|
||||
template struct class2<int>;
|
||||
|
||||
// CHECK: FunctionTemplateDecl {{.*}} f1
|
||||
// CHECK-NEXT: TemplateTypeParmDecl {{.*}} typename depth 0 index 0 T
|
||||
// CHECK-NEXT: FunctionDecl {{.*}} f1 'void (void)'
|
||||
// CHECK: FunctionDecl {{.*}} f1 'void (void)'
|
||||
// CHECK-NEXT: TemplateArgument type 'int'
|
||||
// CHECK: ParmVarDecl {{.*}} n 'enum foo' cinit
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'enum foo' EnumConstant {{.*}} 'a' 'enum foo'
|
||||
|
||||
template<typename T>
|
||||
void f1() {
|
||||
enum class foo { a, b };
|
||||
struct S {
|
||||
int g1(foo n = foo::a);
|
||||
};
|
||||
}
|
||||
|
||||
template void f1<int>();
|
||||
|
|
Loading…
Reference in New Issue