From 284b3cbfd1cd5b6585437fbb8b95fe136f273efb Mon Sep 17 00:00:00 2001
From: Richard Smith
Date: Sun, 12 May 2013 17:32:42 +0000
Subject: C++1y: support for 'switch' statements in constexpr functions. This
is somewhat inefficient; we perform a linear scan of switch labels to find
the one matching the condition, and then walk the body looking for that
label. Both parts should be straightforward to optimize.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181671 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/AST/Stmt.h | 3 -
lib/AST/ExprConstant.cpp | 151 +++++++++++++++++++++++++++--
test/SemaCXX/constant-expression-cxx1y.cpp | 114 ++++++++++++++++++++++
3 files changed, 256 insertions(+), 12 deletions(-)
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 74c9ec2053..b2ab672627 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -967,9 +967,6 @@ public:
SwitchCase *getSwitchCaseList() { return FirstCase; }
/// \brief Set the case list for this switch statement.
- ///
- /// The caller is responsible for incrementing the retain counts on
- /// all of the SwitchCase statements in this list.
void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
SourceLocation getSwitchLoc() const { return SwitchLoc; }
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index bf967961aa..339e78bbe9 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -2769,7 +2769,9 @@ enum EvalStmtResult {
/// Hit a 'continue' statement.
ESR_Continue,
/// Hit a 'break' statement.
- ESR_Break
+ ESR_Break,
+ /// Still scanning for 'case' or 'default' statement.
+ ESR_CaseNotFound
};
}
@@ -2803,12 +2805,13 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
}
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
- const Stmt *S);
+ const Stmt *S, const SwitchCase *SC = 0);
/// Evaluate the body of a loop, and translate the result as appropriate.
static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
- const Stmt *Body) {
- switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) {
+ const Stmt *Body,
+ const SwitchCase *Case = 0) {
+ switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) {
case ESR_Break:
return ESR_Succeeded;
case ESR_Succeeded:
@@ -2816,17 +2819,128 @@ static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
return ESR_Continue;
case ESR_Failed:
case ESR_Returned:
+ case ESR_CaseNotFound:
return ESR;
}
llvm_unreachable("Invalid EvalStmtResult!");
}
+/// Evaluate a switch statement.
+static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info,
+ const SwitchStmt *SS) {
+ // Evaluate the switch condition.
+ if (SS->getConditionVariable() &&
+ !EvaluateDecl(Info, SS->getConditionVariable()))
+ return ESR_Failed;
+ APSInt Value;
+ if (!EvaluateInteger(SS->getCond(), Value, Info))
+ return ESR_Failed;
+
+ // Find the switch case corresponding to the value of the condition.
+ // FIXME: Cache this lookup.
+ const SwitchCase *Found = 0;
+ for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ if (isa(SC)) {
+ Found = SC;
+ continue;
+ }
+
+ const CaseStmt *CS = cast(SC);
+ APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
+ APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
+ : LHS;
+ if (LHS <= Value && Value <= RHS) {
+ Found = SC;
+ break;
+ }
+ }
+
+ if (!Found)
+ return ESR_Succeeded;
+
+ // Search the switch body for the switch case and evaluate it from there.
+ switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) {
+ case ESR_Break:
+ return ESR_Succeeded;
+ case ESR_Succeeded:
+ case ESR_Continue:
+ case ESR_Failed:
+ case ESR_Returned:
+ return ESR;
+ case ESR_CaseNotFound:
+ Found->dump();
+ SS->getBody()->dump();
+ llvm_unreachable("couldn't find switch case");
+ }
+}
+
// Evaluate a statement.
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
- const Stmt *S) {
+ const Stmt *S, const SwitchCase *Case) {
if (!Info.nextStep(S))
return ESR_Failed;
+ // If we're hunting down a 'case' or 'default' label, recurse through
+ // substatements until we hit the label.
+ if (Case) {
+ // FIXME: We don't start the lifetime of objects whose initialization we
+ // jump over. However, such objects must be of class type with a trivial
+ // default constructor that initialize all subobjects, so must be empty,
+ // so this almost never matters.
+ switch (S->getStmtClass()) {
+ case Stmt::CompoundStmtClass:
+ // FIXME: Precompute which substatement of a compound statement we
+ // would jump to, and go straight there rather than performing a
+ // linear scan each time.
+ case Stmt::LabelStmtClass:
+ case Stmt::AttributedStmtClass:
+ case Stmt::DoStmtClass:
+ break;
+
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ if (Case == S)
+ Case = 0;
+ break;
+
+ case Stmt::IfStmtClass: {
+ // FIXME: Precompute which side of an 'if' we would jump to, and go
+ // straight there rather than scanning both sides.
+ const IfStmt *IS = cast(S);
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case);
+ if (ESR != ESR_CaseNotFound || !IS->getElse())
+ return ESR;
+ return EvaluateStmt(Result, Info, IS->getElse(), Case);
+ }
+
+ case Stmt::WhileStmtClass: {
+ EvalStmtResult ESR =
+ EvaluateLoopBody(Result, Info, cast(S)->getBody(), Case);
+ if (ESR != ESR_Continue)
+ return ESR;
+ break;
+ }
+
+ case Stmt::ForStmtClass: {
+ const ForStmt *FS = cast(S);
+ EvalStmtResult ESR =
+ EvaluateLoopBody(Result, Info, FS->getBody(), Case);
+ if (ESR != ESR_Continue)
+ return ESR;
+ if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc()))
+ return ESR_Failed;
+ break;
+ }
+
+ case Stmt::DeclStmtClass:
+ // FIXME: If the variable has initialization that can't be jumped over,
+ // bail out of any immediately-surrounding compound-statement too.
+ default:
+ return ESR_CaseNotFound;
+ }
+ }
+
// FIXME: Mark all temporaries in the current frame as destroyed at
// the end of each full-expression.
switch (S->getStmtClass()) {
@@ -2865,11 +2979,13 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
const CompoundStmt *CS = cast(S);
for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
BE = CS->body_end(); BI != BE; ++BI) {
- EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);
- if (ESR != ESR_Succeeded)
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case);
+ if (ESR == ESR_Succeeded)
+ Case = 0;
+ else if (ESR != ESR_CaseNotFound)
return ESR;
}
- return ESR_Succeeded;
+ return Case ? ESR_CaseNotFound : ESR_Succeeded;
}
case Stmt::IfStmtClass: {
@@ -2909,9 +3025,10 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
const DoStmt *DS = cast(S);
bool Continue;
do {
- EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody());
+ EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case);
if (ESR != ESR_Continue)
return ESR;
+ Case = 0;
if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info))
return ESR_Failed;
@@ -2983,11 +3100,27 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
return ESR_Succeeded;
}
+ case Stmt::SwitchStmtClass:
+ return EvaluateSwitch(Result, Info, cast(S));
+
case Stmt::ContinueStmtClass:
return ESR_Continue;
case Stmt::BreakStmtClass:
return ESR_Break;
+
+ case Stmt::LabelStmtClass:
+ return EvaluateStmt(Result, Info, cast(S)->getSubStmt(), Case);
+
+ case Stmt::AttributedStmtClass:
+ // As a general principle, C++11 attributes can be ignored without
+ // any semantic impact.
+ return EvaluateStmt(Result, Info, cast(S)->getSubStmt(),
+ Case);
+
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ return EvaluateStmt(Result, Info, cast(S)->getSubStmt(), Case);
}
}
diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp
index 824a0e8b91..59a972a4fd 100644
--- a/test/SemaCXX/constant-expression-cxx1y.cpp
+++ b/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -593,3 +593,117 @@ namespace assignment_op {
}
static_assert(testC(), "");
}
+
+namespace switch_stmt {
+ constexpr int f(char k) {
+ bool b = false;
+ int z = 6;
+ switch (k) {
+ return -1;
+ case 0:
+ if (false) {
+ case 1:
+ z = 1;
+ for (; b;) {
+ return 5;
+ while (0)
+ case 2: return 2;
+ case 7: z = 7;
+ do case 6: {
+ return z;
+ if (false)
+ case 3: return 3;
+ case 4: z = 4;
+ } while (1);
+ case 5: b = true;
+ case 9: z = 9;
+ }
+ return z;
+ } else if (false) case 8: z = 8;
+ else if (false) {
+ case 10:
+ z = -10;
+ break;
+ }
+ else z = 0;
+ return z;
+ default:
+ return -1;
+ }
+ return -z;
+ }
+ static_assert(f(0) == 0, "");
+ static_assert(f(1) == 1, "");
+ static_assert(f(2) == 2, "");
+ static_assert(f(3) == 3, "");
+ static_assert(f(4) == 4, "");
+ static_assert(f(5) == 5, "");
+ static_assert(f(6) == 6, "");
+ static_assert(f(7) == 7, "");
+ static_assert(f(8) == 8, "");
+ static_assert(f(9) == 9, "");
+ static_assert(f(10) == 10, "");
+
+ // Check that we can continue an outer loop from within a switch.
+ constexpr bool contin() {
+ for (int n = 0; n != 10; ++n) {
+ switch (n) {
+ case 0:
+ ++n;
+ continue;
+ case 1:
+ return false;
+ case 2:
+ return true;
+ }
+ }
+ return false;
+ }
+ static_assert(contin(), "");
+
+ constexpr bool switch_into_for() {
+ int n = 0;
+ switch (n) {
+ for (; n == 1; ++n) {
+ return n == 1;
+ case 0: ;
+ }
+ }
+ return false;
+ }
+ static_assert(switch_into_for(), "");
+
+ constexpr void duff_copy(char *a, const char *b, int n) {
+ switch ((n - 1) % 8 + 1) {
+ for ( ; n; n = (n - 1) & ~7) {
+ case 8: a[n-8] = b[n-8];
+ case 7: a[n-7] = b[n-7];
+ case 6: a[n-6] = b[n-6];
+ case 5: a[n-5] = b[n-5];
+ case 4: a[n-4] = b[n-4];
+ case 3: a[n-3] = b[n-3];
+ case 2: a[n-2] = b[n-2];
+ case 1: a[n-1] = b[n-1];
+ }
+ case 0: ;
+ }
+ }
+
+ constexpr bool test_copy(const char *str, int n) {
+ char buffer[16] = {};
+ duff_copy(buffer, str, n);
+ for (int i = 0; i != sizeof(buffer); ++i)
+ if (buffer[i] != (i < n ? str[i] : 0))
+ return false;
+ return true;
+ }
+ static_assert(test_copy("foo", 0), "");
+ static_assert(test_copy("foo", 1), "");
+ static_assert(test_copy("foo", 2), "");
+ static_assert(test_copy("hello world", 0), "");
+ static_assert(test_copy("hello world", 7), "");
+ static_assert(test_copy("hello world", 8), "");
+ static_assert(test_copy("hello world", 9), "");
+ static_assert(test_copy("hello world", 10), "");
+ static_assert(test_copy("hello world", 10), "");
+}
--
cgit v1.2.3
From 87360f2acd4e2fa706707135b95c64e5e2b63435 Mon Sep 17 00:00:00 2001
From: David Blaikie
Date: Sun, 12 May 2013 18:05:52 +0000
Subject: Debug Info: Comment changes in r181393 by request of echristo
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181672 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/CodeGen/CGDebugInfo.cpp | 11 +++++++++++
lib/CodeGen/CGDebugInfo.h | 2 ++
2 files changed, 13 insertions(+)
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 7d5d260304..13b681edc9 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -2172,8 +2172,19 @@ llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
}
llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
+ // We only need a declaration (not a definition) of the type - so use whatever
+ // we would otherwise do to get a type for a pointee. (forward declarations in
+ // limited debug info, full definitions (if the type definition is available)
+ // in unlimited debug info)
if (const TypeDecl *RD = dyn_cast(D))
return CreatePointeeType(QualType(RD->getTypeForDecl(), 0), llvm::DIFile());
+ // Otherwise fall back to a fairly rudimentary cache of existing declarations.
+ // This doesn't handle providing declarations (for functions or variables) for
+ // entities without definitions in this TU, nor when the definition proceeds
+ // the call to this function.
+ // FIXME: This should be split out into more specific maps with support for
+ // emitting forward declarations and merging definitions with declarations,
+ // the same way as we do for types.
llvm::DenseMap::iterator I =
DeclCache.find(D->getCanonicalDecl());
if (I == DeclCache.end())
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index e61a50eeb4..f221a0cd3e 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -95,6 +95,8 @@ class CGDebugInfo {
llvm::DenseMap DIFileCache;
llvm::DenseMap SPCache;
+ /// \brief Cache declarations relevant to DW_TAG_imported_declarations (C++
+ /// using declarations) that aren't covered by other more specific caches.
llvm::DenseMap DeclCache;
llvm::DenseMap NameSpaceCache;
llvm::DenseMap StaticDataMemberCache;
--
cgit v1.2.3
From d248e586d60a3fe971369089e763d5e8f669b7a9 Mon Sep 17 00:00:00 2001
From: Richard Smith
Date: Sun, 12 May 2013 23:17:59 +0000
Subject: Fix stack overflow in linkage computation when a function with a
deduced return type returns a lambda defined within itself. The computation
of linkage for the function looked at the linkage of the lambda, and vice
versa.
This is solved by not checking whether an 'auto' in a function return type
deduces to a type with unique external linkage. We don't need this check,
because the type deduced for 'auto' doesn't affect whether two
otherwise-identical declarations would name different functions, so we don't
need to give an ostensibly external-linkage function internal linkage for this
reason. (We also don't need unique-external linkage in C++11 onwards at all,
but that's not implemented yet.)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181675 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/AST/Decl.cpp | 17 +++++++++++---
test/CodeGenCXX/cxx1y-deduced-return-type.cpp | 32 +++++++++++++++++++++++++++
2 files changed, 46 insertions(+), 3 deletions(-)
create mode 100644 test/CodeGenCXX/cxx1y-deduced-return-type.cpp
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index ab9d73b917..df923d6736 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -660,9 +660,20 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// this translation unit. However, we should use the C linkage
// rules instead for extern "C" declarations.
if (Context.getLangOpts().CPlusPlus &&
- !Function->isInExternCContext() &&
- Function->getType()->getLinkage() == UniqueExternalLinkage)
- return LinkageInfo::uniqueExternal();
+ !Function->isInExternCContext()) {
+ // Only look at the type-as-written. If this function has an auto-deduced
+ // return type, we can't compute the linkage of that type because it could
+ // require looking at the linkage of this function, and we don't need this
+ // for correctness because the type is not part of the function's
+ // signature.
+ // FIXME: This is a hack. We should be able to solve this circularity some
+ // other way.
+ QualType TypeAsWritten = Function->getType();
+ if (TypeSourceInfo *TSI = Function->getTypeSourceInfo())
+ TypeAsWritten = TSI->getType();
+ if (TypeAsWritten->getLinkage() == UniqueExternalLinkage)
+ return LinkageInfo::uniqueExternal();
+ }
// Consider LV from the template and the template arguments.
// We're at file scope, so we do not need to worry about nested
diff --git a/test/CodeGenCXX/cxx1y-deduced-return-type.cpp b/test/CodeGenCXX/cxx1y-deduced-return-type.cpp
new file mode 100644
index 0000000000..edf673df4a
--- /dev/null
+++ b/test/CodeGenCXX/cxx1y-deduced-return-type.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -std=c++1y -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: @x = global {{.*}} zeroinitializer
+
+// CHECK: define {{.*}} @_Z1fv
+inline auto f() {
+ int n = 0;
+ // CHECK: load i32
+ // CHECK: store i32
+ // CHECK: ret
+ return [=] () mutable { return ++n; };
+}
+
+auto x = f();
+
+template auto *g(T t) { return t; }
+template decltype(auto) h(T t) { return t; }
+
+// CHECK: define {{.*}} @_Z1zv
+void z() {
+ // CHECK: call {{.*}} @_Z1gIPZ1fvEUlvE_EPDaT_(
+ // CHECK: call {{.*}} @_Z1hIPZ1fvEUlvE_EDcT_(
+ g(&x);
+ h(&x);
+}
+
+auto i() { return [] {}; }
+// CHECK: define {{.*}} @_Z1jv
+auto j() {
+ // CHECK: call {{.*}} @"_Z1hIZ1ivE3$_0EDcT_"()
+ h(i());
+}
--
cgit v1.2.3
From 3c5f4b649f7a8ed51f9291c494a1b6e43f69d386 Mon Sep 17 00:00:00 2001
From: Richard Smith
Date: Sun, 12 May 2013 23:39:32 +0000
Subject: Downgrade C++14 "Clarifying memory allocation". We perform
non-conforming optimizations -- in particular, globalopt will remove calls to
::operator new(size_t) that did not come from new-expressions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181676 91177308-0d34-0410-b5e6-96231b3b80d8
---
www/cxx_status.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 7643c7a7b1..a0c697f149 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -467,7 +467,7 @@ available.
Clarifying memory allocation |
N3664 |
- Yes |
+ Partial |
--
cgit v1.2.3
From 181e3ecc0907ae0103586a9f4db52241995a8267 Mon Sep 17 00:00:00 2001
From: Rafael Espindola
Date: Mon, 13 May 2013 00:12:11 +0000
Subject: Cleanup handling of UniqueExternalLinkage.
This patch renames getLinkage to getLinkageInternal. Only code that
needs to handle UniqueExternalLinkage specially should call this.
Linkage, as defined in the c++ standard, is provided by
getFormalLinkage. It maps UniqueExternalLinkage to ExternalLinkage.
Most places in the compiler actually want isExternallyVisible, which
handles UniqueExternalLinkage as internal.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181677 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/AST/Decl.h | 21 +++++++--
include/clang/Basic/Linkage.h | 5 --
include/clang/Sema/Sema.h | 2 +-
lib/ARCMigrate/TransUnbridgedCasts.cpp | 4 +-
lib/ARCMigrate/Transforms.cpp | 4 +-
lib/AST/ASTContext.cpp | 75 ++++++++++++------------------
lib/AST/ASTImporter.cpp | 8 ++--
lib/AST/Decl.cpp | 10 ++--
lib/AST/ItaniumMangle.cpp | 4 +-
lib/AST/MicrosoftMangle.cpp | 2 +-
lib/AST/RecordLayoutBuilder.cpp | 2 +-
lib/AST/Type.cpp | 4 +-
lib/CodeGen/CGVTables.cpp | 2 +-
lib/CodeGen/CodeGenModule.cpp | 2 +-
lib/CodeGen/CodeGenTBAA.cpp | 3 +-
lib/Sema/Sema.cpp | 8 ++--
lib/Sema/SemaDecl.cpp | 22 ++++-----
lib/Sema/SemaDeclCXX.cpp | 2 +-
lib/Sema/SemaExpr.cpp | 8 ++--
lib/Sema/SemaTemplate.cpp | 4 +-
lib/Serialization/ASTReaderDecl.cpp | 4 +-
lib/Serialization/ASTWriterDecl.cpp | 4 +-
lib/StaticAnalyzer/Core/CheckerContext.cpp | 2 +-
tools/libclang/CIndex.cpp | 2 +-
tools/libclang/CIndexUSRs.cpp | 2 +-
tools/libclang/IndexingContext.cpp | 3 +-
26 files changed, 104 insertions(+), 105 deletions(-)
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index d5e6ebee4a..e35938a5e0 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -212,11 +212,26 @@ public:
bool isCXXInstanceMember() const;
/// \brief Determine what kind of linkage this entity has.
- Linkage getLinkage() const;
+ /// This is not the linkage as defined by the standard or the codegen notion
+ /// of linkage. It is just an implementation detail that is used to compute
+ /// those.
+ Linkage getLinkageInternal() const;
+
+ /// \brief Get the linkage from a semantic point of view. Entities in
+ /// anonymous namespaces are external (in c++98).
+ Linkage getFormalLinkage() const {
+ Linkage L = getLinkageInternal();
+ if (L == UniqueExternalLinkage)
+ return ExternalLinkage;
+ return L;
+ }
/// \brief True if this decl has external linkage.
- bool hasExternalLinkage() const {
- return getLinkage() == ExternalLinkage;
+ bool hasExternalFormalLinkage() const {
+ return getFormalLinkage() == ExternalLinkage;
+ }
+ bool isExternallyVisible() const {
+ return getLinkageInternal() == ExternalLinkage;
}
/// \brief Determines the visibility of this entity.
diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h
index 01b8db15f5..13d2d24d8e 100644
--- a/include/clang/Basic/Linkage.h
+++ b/include/clang/Basic/Linkage.h
@@ -62,11 +62,6 @@ enum GVALinkage {
GVA_ExplicitTemplateInstantiation
};
-/// \brief Determine whether the given linkage is semantically external.
-inline bool isExternalLinkage(Linkage L) {
- return L == UniqueExternalLinkage || L == ExternalLinkage;
-}
-
/// \brief Compute the minimum linkage given two linages.
inline Linkage minLinkage(Linkage L1, Linkage L2) {
return L1 < L2? L1 : L2;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 8e1ebd844e..78152313c8 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -216,7 +216,7 @@ class Sema {
// it will keep having external linkage. If it has internal linkage, we
// will not link it. Since it has no previous decls, it will remain
// with internal linkage.
- return !Old->isHidden() || New->hasExternalLinkage();
+ return !Old->isHidden() || New->isExternallyVisible();
}
public:
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index fc4a75fdb8..a5752f8157 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -148,7 +148,7 @@ private:
if (FD->getName() == "CFRetain" &&
FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->hasExternalLinkage()) {
+ FD->isExternallyVisible()) {
Expr *Arg = callE->getArg(0);
if (const ImplicitCastExpr *ICE = dyn_cast(Arg)) {
const Expr *sub = ICE->getSubExpr();
@@ -413,7 +413,7 @@ private:
FD = dyn_cast_or_null(callE->getCalleeDecl()))
if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->hasExternalLinkage())
+ FD->isExternallyVisible())
return true;
return false;
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 087219535a..6c724af53a 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -94,7 +94,7 @@ bool trans::isPlusOne(const Expr *E) {
if (FD->isGlobal() &&
FD->getIdentifier() &&
FD->getParent()->isTranslationUnit() &&
- FD->hasExternalLinkage() &&
+ FD->isExternallyVisible() &&
ento::cocoa::isRefType(callE->getType(), "CF",
FD->getIdentifier()->getName())) {
StringRef fname = FD->getIdentifier()->getName();
@@ -198,7 +198,7 @@ bool trans::isGlobalVar(Expr *E) {
E = E->IgnoreParenCasts();
if (DeclRefExpr *DRE = dyn_cast(E))
return DRE->getDecl()->getDeclContext()->isFileContext() &&
- DRE->getDecl()->hasExternalLinkage();
+ DRE->getDecl()->isExternallyVisible();
if (ConditionalOperator *condOp = dyn_cast(E))
return isGlobalVar(condOp->getTrueExpr()) &&
isGlobalVar(condOp->getFalseExpr());
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 986bb8c3d2..9901080101 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -7767,30 +7767,23 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
- GVALinkage External = GVA_StrongExternal;
-
- Linkage L = FD->getLinkage();
- switch (L) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
+ if (!FD->isExternallyVisible())
return GVA_Internal;
-
- case ExternalLinkage:
- switch (FD->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- External = GVA_StrongExternal;
- break;
- case TSK_ExplicitInstantiationDefinition:
- return GVA_ExplicitTemplateInstantiation;
+ GVALinkage External = GVA_StrongExternal;
+ switch (FD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ External = GVA_StrongExternal;
+ break;
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ImplicitInstantiation:
- External = GVA_TemplateInstantiation;
- break;
- }
+ case TSK_ExplicitInstantiationDefinition:
+ return GVA_ExplicitTemplateInstantiation;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ImplicitInstantiation:
+ External = GVA_TemplateInstantiation;
+ break;
}
if (!FD->isInlined())
@@ -7820,6 +7813,9 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
}
GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
+ if (!VD->isExternallyVisible())
+ return GVA_Internal;
+
// If this is a static data member, compute the kind of template
// specialization. Otherwise, this variable is not part of a
// template.
@@ -7827,33 +7823,21 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
if (VD->isStaticDataMember())
TSK = VD->getTemplateSpecializationKind();
- Linkage L = VD->getLinkage();
-
- switch (L) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
- return GVA_Internal;
+ switch (TSK) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ return GVA_StrongExternal;
- case ExternalLinkage:
- switch (TSK) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- return GVA_StrongExternal;
+ case TSK_ExplicitInstantiationDeclaration:
+ llvm_unreachable("Variable should not be instantiated");
+ // Fall through to treat this like any other instantiation.
- case TSK_ExplicitInstantiationDeclaration:
- llvm_unreachable("Variable should not be instantiated");
- // Fall through to treat this like any other instantiation.
-
- case TSK_ExplicitInstantiationDefinition:
- return GVA_ExplicitTemplateInstantiation;
+ case TSK_ExplicitInstantiationDefinition:
+ return GVA_ExplicitTemplateInstantiation;
- case TSK_ImplicitInstantiation:
- return GVA_TemplateInstantiation;
- }
+ case TSK_ImplicitInstantiation:
+ return GVA_TemplateInstantiation;
}
-
- llvm_unreachable("Invalid Linkage!");
}
bool ASTContext::DeclMustBeEmitted(const Decl *D) {
@@ -7986,7 +7970,8 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
void ASTContext::addUnnamedTag(const TagDecl *Tag) {
// FIXME: This mangling should be applied to function local classes too
if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() ||
- !isa(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage)
+ !isa(Tag->getParent()) ||
+ !Tag->isExternallyVisible())
return;
std::pair::iterator, bool> P =
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 915eb6feb8..740b4ff721 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -2610,8 +2610,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
continue;
if (FunctionDecl *FoundFunction = dyn_cast(FoundDecls[I])) {
- if (isExternalLinkage(FoundFunction->getLinkage()) &&
- isExternalLinkage(D->getLinkage())) {
+ if (FoundFunction->hasExternalFormalLinkage() &&
+ D->hasExternalFormalLinkage()) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundFunction->getType())) {
// FIXME: Actually try to merge the body and other attributes.
@@ -2995,8 +2995,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
if (VarDecl *FoundVar = dyn_cast(FoundDecls[I])) {
// We have found a variable that we may need to merge with. Check it.
- if (isExternalLinkage(FoundVar->getLinkage()) &&
- isExternalLinkage(D->getLinkage())) {
+ if (FoundVar->hasExternalFormalLinkage() &&
+ D->hasExternalFormalLinkage()) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundVar->getType())) {
MergeWithVar = FoundVar;
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index df923d6736..3e4c2cbdb2 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -483,6 +483,10 @@ static bool isSingleLineExternC(const Decl &D) {
return false;
}
+static bool isExternalLinkage(Linkage L) {
+ return L == UniqueExternalLinkage || L == ExternalLinkage;
+}
+
static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
LVComputationKind computation) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
@@ -885,7 +889,7 @@ bool NamedDecl::isLinkageValid() const {
Linkage(CachedLinkage);
}
-Linkage NamedDecl::getLinkage() const {
+Linkage NamedDecl::getLinkageInternal() const {
if (HasCachedLinkage)
return Linkage(CachedLinkage);
@@ -1289,7 +1293,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
}
bool NamedDecl::hasLinkage() const {
- return getLinkage() != NoLinkage;
+ return getLinkageInternal() != NoLinkage;
}
NamedDecl *NamedDecl::getUnderlyingDeclImpl() {
@@ -1513,7 +1517,7 @@ template
static LanguageLinkage getLanguageLinkageTemplate(const T &D) {
// C++ [dcl.link]p1: All function types, function names with external linkage,
// and variable names with external linkage have a language linkage.
- if (!isExternalLinkage(D.getLinkage()))
+ if (!D.hasExternalFormalLinkage())
return NoLanguageLinkage;
// Language linkage is a C++ concept, but saying that everything else in C has
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index d28aced172..3137f3c8fd 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -405,7 +405,7 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
if (DC->isFunctionOrMethod() && D->hasLinkage())
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = getEffectiveParentContext(DC);
- if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage)
+ if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage)
return false;
}
@@ -1053,7 +1053,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// static void foo();
// This naming convention is the same as that followed by GCC,
// though it shouldn't actually matter.
- if (ND && ND->getLinkage() == InternalLinkage &&
+ if (ND && ND->getFormalLinkage() == InternalLinkage &&
getEffectiveDeclContext(ND)->isFileContext())
Out << 'L';
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 7c797eef4d..d242cd9335 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -199,7 +199,7 @@ bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) {
// Variables at global scope with internal linkage are not mangled.
if (!FD) {
const DeclContext *DC = D->getDeclContext();
- if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage)
+ if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage)
return false;
}
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 42c3ba31bc..f27b502c9c 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -2354,7 +2354,7 @@ static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
// A class that is not externally visible doesn't have a key function. (Or
// at least, there's no point to assigning a key function to such a class;
// this doesn't affect the ABI.)
- if (RD->getLinkage() != ExternalLinkage)
+ if (!RD->isExternallyVisible())
return 0;
// Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6.
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index a1f0b08494..eacf367818 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -2124,7 +2124,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
// - it is a class or enumeration type that is named (or has a name
// for linkage purposes (7.1.3)) and the name has linkage; or
// - it is a specialization of a class template (14); or
- Linkage L = Tag->getLinkage();
+ Linkage L = Tag->getLinkageInternal();
bool IsLocalOrUnnamed =
Tag->getDeclContext()->isFunctionOrMethod() ||
!Tag->hasNameForLinkage();
@@ -2166,7 +2166,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
return result;
}
case Type::ObjCInterface: {
- Linkage L = cast(T)->getDecl()->getLinkage();
+ Linkage L = cast(T)->getDecl()->getLinkageInternal();
return CachedProperties(L, false);
}
case Type::ObjCObject:
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 069cd5f9e7..9a345cf472 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -719,7 +719,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
/// Note that we only call this at the end of the translation unit.
llvm::GlobalVariable::LinkageTypes
CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
- if (RD->getLinkage() != ExternalLinkage)
+ if (!RD->isExternallyVisible())
return llvm::GlobalVariable::InternalLinkage;
// We're at the end of the translation unit, so the current key
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 695048e5b3..0736879037 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1763,7 +1763,7 @@ void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D,
return;
// Must have internal linkage and an ordinary name.
- if (!D->getIdentifier() || D->getLinkage() != InternalLinkage)
+ if (!D->getIdentifier() || D->getFormalLinkage() != InternalLinkage)
return;
// Must be in an extern "C" context. Entities declared directly within
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index 5ff1560a48..3f0eaee536 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -162,8 +162,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
// on their mangled names, if they're external.
// TODO: Is there a way to get a program-wide unique name for a
// decl with local linkage or no linkage?
- if (Features.CPlusPlus &&
- ETy->getDecl()->getLinkage() != ExternalLinkage)
+ if (Features.CPlusPlus && !ETy->getDecl()->isExternallyVisible())
return MetadataCache[Ty] = getChar();
// TODO: This is using the RTTI name. Is there a better way to get
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index e718be2f8b..b7810da98e 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -332,7 +332,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
if (D->getMostRecentDecl()->isUsed())
return true;
- if (D->hasExternalLinkage())
+ if (D->isExternallyVisible())
return true;
if (const FunctionDecl *FD = dyn_cast(D)) {
@@ -402,13 +402,13 @@ void Sema::getUndefinedButUsed(
if (FunctionDecl *FD = dyn_cast(ND)) {
if (FD->isDefined())
continue;
- if (FD->hasExternalLinkage() &&
+ if (FD->isExternallyVisible() &&
!FD->getMostRecentDecl()->isInlined())
continue;
} else {
if (cast(ND)->hasDefinition() != VarDecl::DeclarationOnly)
continue;
- if (ND->hasExternalLinkage())
+ if (ND->isExternallyVisible())
continue;
}
@@ -435,7 +435,7 @@ static void checkUndefinedButUsed(Sema &S) {
I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
NamedDecl *ND = I->first;
- if (ND->getLinkage() != ExternalLinkage) {
+ if (!ND->isExternallyVisible()) {
S.Diag(ND->getLocation(), diag::warn_undefined_internal)
<< isa(ND) << ND;
} else {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 5d8839a65b..49be515f0b 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1194,7 +1194,7 @@ bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) {
DC = DC->getParent();
}
- return !D->hasExternalLinkage();
+ return !D->isExternallyVisible();
}
bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
@@ -1614,7 +1614,7 @@ static void filterNonConflictingPreviousDecls(ASTContext &context,
if (!old->isHidden())
continue;
- if (old->getLinkage() != ExternalLinkage)
+ if (!old->isExternallyVisible())
filter.erase();
}
@@ -2314,7 +2314,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// storage classes.
if (!isa(New) && !isa(Old) &&
New->getStorageClass() == SC_Static &&
- isExternalLinkage(Old->getLinkage()) &&
+ Old->hasExternalFormalLinkage() &&
!New->getTemplateSpecializationInfo() &&
!canRedefineFunction(Old, getLangOpts())) {
if (getLangOpts().MicrosoftExt) {
@@ -2923,7 +2923,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
// [dcl.stc]p8: Check if we have a non-static decl followed by a static.
if (New->getStorageClass() == SC_Static &&
!New->isStaticDataMember() &&
- isExternalLinkage(Old->getLinkage())) {
+ Old->hasExternalFormalLinkage()) {
Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -4625,13 +4625,13 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
// 'weak' only applies to declarations with external linkage.
if (WeakAttr *Attr = ND.getAttr()) {
- if (ND.getLinkage() != ExternalLinkage) {
+ if (!ND.isExternallyVisible()) {
S.Diag(Attr->getLocation(), diag::err_attribute_weak_static);
ND.dropAttr();
}
}
if (WeakRefAttr *Attr = ND.getAttr()) {
- if (ND.hasExternalLinkage()) {
+ if (ND.isExternallyVisible()) {
S.Diag(Attr->getLocation(), diag::err_attribute_weakref_not_static);
ND.dropAttr();
}
@@ -6579,7 +6579,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// If there's a #pragma GCC visibility in scope, and this isn't a class
// member, set the visibility of this function.
- if (!DC->isRecord() && NewFD->hasExternalLinkage())
+ if (!DC->isRecord() && NewFD->isExternallyVisible())
AddPushedVisibilityAttribute(NewFD);
// If there's a #pragma clang arc_cf_code_audited in scope, consider
@@ -7816,7 +7816,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
// declared with no linkage (C99 6.2.2p6), the type for the
// object shall be complete.
if (!Type->isDependentType() && Var->isLocalVarDecl() &&
- !Var->getLinkage() && !Var->isInvalidDecl() &&
+ !Var->hasLinkage() && !Var->isInvalidDecl() &&
RequireCompleteType(Var->getLocation(), Type,
diag::err_typecheck_decl_incomplete_type))
Var->setInvalidDecl();
@@ -8029,7 +8029,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
if (var->isThisDeclarationADefinition() &&
- var->hasExternalLinkage() &&
+ var->isExternallyVisible() &&
getDiagnostics().getDiagnosticLevel(
diag::warn_missing_variable_declarations,
var->getLocation())) {
@@ -8138,7 +8138,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
const DeclContext *DC = VD->getDeclContext();
// If there's a #pragma GCC visibility in scope, and this isn't a class
// member, set the visibility of this variable.
- if (!DC->isRecord() && VD->hasExternalLinkage())
+ if (!DC->isRecord() && VD->isExternallyVisible())
AddPushedVisibilityAttribute(VD);
if (VD->isFileVarDecl())
@@ -8904,7 +8904,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// ODR use before the definition. Avoid the expensive map lookup if this
// is the first declaration.
if (FD->getPreviousDecl() != 0 && FD->getPreviousDecl()->isUsed()) {
- if (FD->getLinkage() != ExternalLinkage)
+ if (!FD->isExternallyVisible())
UndefinedButUsed.erase(FD);
else if (FD->isInlined() &&
(LangOpts.CPlusPlus || !LangOpts.GNUInline) &&
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e5d0316f73..e5e43897ee 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -11824,7 +11824,7 @@ bool Sema::DefineUsedVTables() {
Consumer.HandleVTable(Class, VTablesUsed[Canonical]);
// Optionally warn if we're emitting a weak vtable.
- if (Class->hasExternalLinkage() &&
+ if (Class->isExternallyVisible() &&
Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
const FunctionDecl *KeyFunctionDef = 0;
if (!KeyFunction ||
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index b6b6444738..2595f2d099 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -197,11 +197,11 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S,
return;
if (!Current->isInlined())
return;
- if (Current->getLinkage() != ExternalLinkage)
+ if (!Current->isExternallyVisible())
return;
-
+
// Check if the decl has internal linkage.
- if (D->getLinkage() != InternalLinkage)
+ if (D->getFormalLinkage() != InternalLinkage)
return;
// Downgrade from ExtWarn to Extension if
@@ -11459,7 +11459,7 @@ static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
// Keep track of used but undefined variables.
// FIXME: We shouldn't suppress this warning for static data members.
if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
- Var->getLinkage() != ExternalLinkage &&
+ !Var->isExternallyVisible() &&
!(Var->isStaticDataMember() && Var->hasInit())) {
SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];
if (old.isInvalid()) old = Loc;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index b9695cc1e1..7f1def7daf 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3793,14 +3793,14 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
}
// Address / reference template args must have external linkage in C++98.
- if (Entity->getLinkage() == InternalLinkage) {
+ if (Entity->getFormalLinkage() == InternalLinkage) {
S.Diag(Arg->getLocStart(), S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_object_internal :
diag::ext_template_arg_object_internal)
<< !Func << Entity << Arg->getSourceRange();
S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object)
<< !Func;
- } else if (Entity->getLinkage() == NoLinkage) {
+ } else if (!Entity->hasLinkage()) {
S.Diag(Arg->getLocStart(), diag::err_template_arg_object_no_linkage)
<< !Func << Entity << Arg->getSourceRange();
S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object)
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 086acd261d..e3f9f43a3b 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1783,14 +1783,14 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
//prototyped/non-prototyped functions, etc.
if (FunctionDecl *FuncX = dyn_cast(X)) {
FunctionDecl *FuncY = cast(Y);
- return (FuncX->getLinkage() == FuncY->getLinkage()) &&
+ return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) &&
FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType());
}
// Variables with the same type and linkage match.
if (VarDecl *VarX = dyn_cast(X)) {
VarDecl *VarY = cast(Y);
- return (VarX->getLinkage() == VarY->getLinkage()) &&
+ return (VarX->getLinkageInternal() == VarY->getLinkageInternal()) &&
VarX->getASTContext().hasSameType(VarX->getType(), VarY->getType());
}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 67349db687..7a22afaba7 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -334,7 +334,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(D->hasImplicitReturnZero());
Record.push_back(D->isConstexpr());
Record.push_back(D->HasSkippedBody);
- Record.push_back(D->getLinkage());
+ Record.push_back(D->getLinkageInternal());
Writer.AddSourceLocation(D->getLocEnd(), Record);
Record.push_back(D->getTemplatedKind());
@@ -694,7 +694,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->isARCPseudoStrong());
Record.push_back(D->isConstexpr());
- Record.push_back(D->getLinkage());
+ Record.push_back(D->getLinkageInternal());
if (D->getInit()) {
Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 74eeef1c67..6b22bf411c 100644
--- a/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -68,7 +68,7 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
// If this function is not externally visible, it is not a C library function.
// Note that we make an exception for inline functions, which may be
// declared in header files without external linkage.
- if (!FD->isInlined() && FD->getLinkage() != ExternalLinkage)
+ if (!FD->isInlined() && !FD->isExternallyVisible())
return false;
if (Name.empty())
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index c25e625df5..71827f8a23 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -5681,7 +5681,7 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
const Decl *D = cxcursor::getCursorDecl(cursor);
if (const NamedDecl *ND = dyn_cast_or_null(D))
- switch (ND->getLinkage()) {
+ switch (ND->getLinkageInternal()) {
case NoLinkage: return CXLinkage_NoLinkage;
case InternalLinkage: return CXLinkage_Internal;
case UniqueExternalLinkage: return CXLinkage_UniqueExternal;
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index a911ce5e95..96c1d2e11d 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -151,7 +151,7 @@ bool USRGenerator::EmitDeclName(const NamedDecl *D) {
}
static inline bool ShouldGenerateLocation(const NamedDecl *D) {
- return D->getLinkage() != ExternalLinkage;
+ return !D->isExternallyVisible();
}
void USRGenerator::VisitDeclContext(const DeclContext *DC) {
diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp
index 14b430c7dc..cb9b492586 100644
--- a/tools/libclang/IndexingContext.cpp
+++ b/tools/libclang/IndexingContext.cpp
@@ -210,11 +210,12 @@ bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
return false;
if (const NamedDecl *ND = dyn_cast(D)) {
- switch (ND->getLinkage()) {
+ switch (ND->getFormalLinkage()) {
case NoLinkage:
case InternalLinkage:
return true;
case UniqueExternalLinkage:
+ llvm_unreachable("Not a sema linkage");
case ExternalLinkage:
return false;
}
--
cgit v1.2.3
From d4494681ef9dd76d8168e8a96af5473fb58e2e79 Mon Sep 17 00:00:00 2001
From: Richard Smith
Date: Mon, 13 May 2013 00:29:57 +0000
Subject: Add missing triple to CodeGen test.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181679 91177308-0d34-0410-b5e6-96231b3b80d8
---
test/CodeGenCXX/cxx1y-deduced-return-type.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/CodeGenCXX/cxx1y-deduced-return-type.cpp b/test/CodeGenCXX/cxx1y-deduced-return-type.cpp
index edf673df4a..6d15a2246d 100644
--- a/test/CodeGenCXX/cxx1y-deduced-return-type.cpp
+++ b/test/CodeGenCXX/cxx1y-deduced-return-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++1y -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
// CHECK: @x = global {{.*}} zeroinitializer
--
cgit v1.2.3
From 1fcf31efaf58fcdf274409cf8926915636bce033 Mon Sep 17 00:00:00 2001
From: Rafael Espindola
Date: Mon, 13 May 2013 01:24:18 +0000
Subject: Update for LLVM interface change in r181680.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181681 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/Parse/ParseStmt.cpp | 2 +-
tools/driver/cc1as_main.cpp | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 43b6965d31..f47b0e5435 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -2091,8 +2091,8 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
const std::string &TT = TheTriple.getTriple();
const llvm::Target *TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
- OwningPtr MAI(TheTarget->createMCAsmInfo(TT));
OwningPtr MRI(TheTarget->createMCRegInfo(TT));
+ OwningPtr MAI(TheTarget->createMCAsmInfo(*MRI, TT));
OwningPtr MOFI(new llvm::MCObjectFileInfo());
OwningPtr
STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 232ea2f668..46ba2463f1 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -287,12 +287,12 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
// it later.
SrcMgr.setIncludeDirs(Opts.IncludePaths);
- OwningPtr MAI(TheTarget->createMCAsmInfo(Opts.Triple));
- assert(MAI && "Unable to create target asm info!");
-
OwningPtr MRI(TheTarget->createMCRegInfo(Opts.Triple));
assert(MRI && "Unable to create target register info!");
+ OwningPtr MAI(TheTarget->createMCAsmInfo(*MRI, Opts.Triple));
+ assert(MAI && "Unable to create target asm info!");
+
bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary);
if (!Out)
--
cgit v1.2.3
From 6af701f29be43e49a25ab098c79940ae4cbb69c7 Mon Sep 17 00:00:00 2001
From: Alexey Bataev
Date: Mon, 13 May 2013 04:18:18 +0000
Subject: OpenMP threadprivate with qualified names.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181683 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/AST/DeclOpenMP.h | 26 ++--
include/clang/Basic/DiagnosticParseKinds.td | 5 +-
include/clang/Basic/DiagnosticSemaKinds.td | 18 ++-
include/clang/Parse/Parser.h | 11 +-
include/clang/Sema/Sema.h | 17 +-
lib/AST/DeclOpenMP.cpp | 10 +-
lib/AST/DeclPrinter.cpp | 4 +-
lib/Basic/OpenMPKinds.cpp | 3 +-
lib/Parse/ParseOpenMP.cpp | 93 ++++++-----
lib/Parse/Parser.cpp | 5 +-
lib/Parse/RAIIObjectsForParser.h | 7 +-
lib/Sema/SemaOpenMP.cpp | 230 +++++++++++++++-------------
lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 +-
lib/Serialization/ASTReaderDecl.cpp | 4 +-
test/OpenMP/predefined_macro.c | 1 -
test/OpenMP/threadprivate_messages.cpp | 52 ++++---
16 files changed, 271 insertions(+), 223 deletions(-)
diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h
index ca92040c32..42fe907aa1 100644
--- a/include/clang/AST/DeclOpenMP.h
+++ b/include/clang/AST/DeclOpenMP.h
@@ -1,4 +1,4 @@
-//===--- OpenMP.h - Classes for representing OpenMP directives ---*- C++ -*-===//
+//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file defines OpenMP nodes.
+/// \brief This file defines OpenMP nodes for declarative directives.
///
//===----------------------------------------------------------------------===//
@@ -20,8 +20,6 @@
namespace clang {
-class DeclRefExpr;
-
/// \brief This represents '#pragma omp threadprivate ...' directive.
/// For example, in the following, both 'a' and 'A::b' are threadprivate:
///
@@ -43,29 +41,29 @@ class OMPThreadPrivateDecl : public Decl {
OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) :
Decl(DK, DC, L), NumVars(0) { }
- ArrayRef getVars() const {
- return ArrayRef(
- reinterpret_cast(this + 1),
+ ArrayRef getVars() const {
+ return ArrayRef(
+ reinterpret_cast(this + 1),
NumVars);
}
- llvm::MutableArrayRef getVars() {
- return llvm::MutableArrayRef(
- reinterpret_cast(this + 1),
+ llvm::MutableArrayRef getVars() {
+ return llvm::MutableArrayRef(
+ reinterpret_cast(this + 1),
NumVars);
}
- void setVars(ArrayRef VL);
+ void setVars(ArrayRef VL);
public:
static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
- ArrayRef VL);
+ ArrayRef VL);
static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
unsigned ID, unsigned N);
- typedef llvm::MutableArrayRef::iterator varlist_iterator;
- typedef ArrayRef::iterator varlist_const_iterator;
+ typedef llvm::MutableArrayRef::iterator varlist_iterator;
+ typedef ArrayRef::iterator varlist_const_iterator;
unsigned varlist_size() const { return NumVars; }
bool varlist_empty() const { return NumVars == 0; }
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index e001bd46a2..a4b8d1810c 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -819,13 +819,14 @@ def err_seh___finally_block : Error<
def warn_pragma_omp_ignored : Warning <
"unexpected '#pragma omp ...' in program">, InGroup, DefaultIgnore;
def warn_omp_extra_tokens_at_eol : Warning <
- "extra tokens at end of '#pragma omp %0' are ignored">,
+ "extra tokens at the end of '#pragma omp %0' are ignored">,
InGroup;
def err_omp_unknown_directive : Error <
"expected an OpenMP directive">;
def err_omp_unexpected_directive : Error <
"unexpected OpenMP directive '#pragma omp %0'">;
-
+def err_omp_expected_var : Error <
+ "expected '#pragma omp %0' argument to be a variable name">;
} // end of Parse Issue category.
let CategoryName = "Modules Issue" in {
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 18d5796ea1..c2728820d4 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6336,24 +6336,26 @@ def err_wrong_sampler_addressspace: Error<
"sampler type cannot be used with the __local and __global address space qualifiers">;
def err_opencl_global_invalid_addr_space : Error<
"global variables must have a constant address space qualifier">;
-
+
+} // end of sema category
+
+let CategoryName = "OpenMP Issue" in {
// OpenMP support.
def err_omp_expected_var_arg_suggest : Error<
"%0 is not a global variable, static local variable or static data member%select{|; did you mean %2?}1">;
def err_omp_global_var_arg : Error<
"arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">;
def err_omp_ref_type_arg : Error<
- "arguments of '#pragma omp %0' cannot be of reference type %1">;
+ "arguments of '#pragma omp %0' cannot be of reference type">;
def err_omp_var_scope : Error<
- "'#pragma omp %0' must appear in the scope of the %1 variable declaration">;
+ "'#pragma omp %0' must appear in the scope of the %q1 variable declaration">;
def err_omp_var_used : Error<
- "'#pragma omp %0' must precede all references to variable %1">;
+ "'#pragma omp %0' must precede all references to variable %q1">;
def err_omp_var_thread_local : Error<
"variable %0 cannot be threadprivate because it is thread-local">;
-def err_omp_incomplete_type : Error<
- "a threadprivate variable must not have incomplete type %0">;
-
-} // end of sema category
+def err_omp_threadprivate_incomplete_type : Error<
+ "threadprivate variable with incomplete type %0">;
+} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
// Objective-C related result type compatibility
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 72acacf5ae..1a1d6d2ae1 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -2138,9 +2138,18 @@ private:
//===--------------------------------------------------------------------===//
// OpenMP: Directives and clauses.
+ /// \brief Parses declarative OpenMP directives.
DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
+ /// \brief Parses simple list of variables.
+ ///
+ /// \param Kind Kind of the directive.
+ /// \param [out] VarList List of referenced variables.
+ /// \param AllowScopeSpecifier true, if the variables can have fully
+ /// qualified names.
+ ///
bool ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
- SmallVectorImpl &IdList);
+ SmallVectorImpl &VarList,
+ bool AllowScopeSpecifier);
public:
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 78152313c8..c2300e977e 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -6682,16 +6682,19 @@ public:
unsigned SpellingListIndex, bool IsPackExpansion);
// OpenMP directives and clauses.
-
+ /// \brief Called on correct id-expression from the '#pragma omp
+ /// threadprivate'.
+ ExprResult ActOnOpenMPIdExpression(Scope *CurScope,
+ CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id);
/// \brief Called on well-formed '#pragma omp threadprivate'.
DeclGroupPtrTy ActOnOpenMPThreadprivateDirective(
- SourceLocation Loc,
- Scope *CurScope,
- ArrayRef IdList);
- /// \brief Build a new OpenMPThreadPrivateDecl and check its correctness.
+ SourceLocation Loc,
+ ArrayRef VarList);
+ // \brief Builds a new OpenMPThreadPrivateDecl and checks its correctness.
OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(
- SourceLocation Loc,
- ArrayRef VarList);
+ SourceLocation Loc,
+ ArrayRef VarList);
/// \brief The kind of conversion being performed.
enum CheckedConversionKind {
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
index c0d10a0f41..522caefe3b 100644
--- a/lib/AST/DeclOpenMP.cpp
+++ b/lib/AST/DeclOpenMP.cpp
@@ -28,9 +28,9 @@ void OMPThreadPrivateDecl::anchor() { }
OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
- ArrayRef VL) {
+ ArrayRef VL) {
unsigned Size = sizeof(OMPThreadPrivateDecl) +
- (VL.size() * sizeof(DeclRefExpr *));
+ (VL.size() * sizeof(Expr *));
void *Mem = C.Allocate(Size, llvm::alignOf());
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@@ -43,7 +43,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned N) {
- unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *));
+ unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *));
void *Mem = AllocateDeserializedDecl(C, ID, Size);
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@@ -52,9 +52,9 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
return D;
}
-void OMPThreadPrivateDecl::setVars(ArrayRef VL) {
+void OMPThreadPrivateDecl::setVars(ArrayRef VL) {
assert(VL.size() == NumVars &&
"Number of variables is not the same as the preallocated buffer");
- DeclRefExpr **Vars = reinterpret_cast(this + 1);
+ Expr **Vars = reinterpret_cast(this + 1);
std::copy(VL.begin(), VL.end(), Vars);
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index d47972bc61..1c9fd2d5f6 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -1180,9 +1180,9 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
if (!D->varlist_empty()) {
for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
E = D->varlist_end();
- I != E; ++I) {
+ I != E; ++I) {
Out << (I == D->varlist_begin() ? '(' : ',')
- << *cast((*I)->getDecl());
+ << *cast(cast(*I)->getDecl());
}
Out << ")";
}
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 835908d2a1..b90fbc7a7c 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -32,7 +32,7 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
assert(Kind < NUM_OPENMP_DIRECTIVES);
switch (Kind) {
case OMPD_unknown:
- return ("unknown");
+ return "unknown";
#define OPENMP_DIRECTIVE(Name) \
case OMPD_##Name : return #Name;
#include "clang/Basic/OpenMPKinds.def"
@@ -41,3 +41,4 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
}
llvm_unreachable("Invalid OpenMP directive kind");
}
+
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 507a6b1bcd..e192ae2e23 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -12,8 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
-#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Scope.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "RAIIObjectsForParser.h"
using namespace clang;
@@ -21,22 +23,24 @@ using namespace clang;
// OpenMP declarative directives.
//===----------------------------------------------------------------------===//
-/// \brief Parses OpenMP declarative directive
-/// threadprivate-directive
-/// annot_pragma_openmp threadprivate simple-variable-list
+/// \brief Parsing of declarative OpenMP directives.
+///
+/// threadprivate-directive:
+/// annot_pragma_openmp 'threadprivate' simple-variable-list
///
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
SourceLocation Loc = ConsumeToken();
- SmallVector Identifiers;
- OpenMPDirectiveKind Kind = Tok.isAnnotation() ?
- OMPD_unknown :
- getOpenMPDirectiveKind(PP.getSpelling(Tok));
- switch(Kind) {
+ SmallVector Identifiers;
+ OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
+ OMPD_unknown :
+ getOpenMPDirectiveKind(PP.getSpelling(Tok));
+
+ switch (DKind) {
case OMPD_threadprivate:
ConsumeToken();
- if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) {
+ if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) {
// The last seen token is annot_pragma_openmp_end - need to check for
// extra tokens.
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
@@ -44,9 +48,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
<< getOpenMPDirectiveName(OMPD_threadprivate);
SkipUntil(tok::annot_pragma_openmp_end, false, true);
}
+ // Skip the last annot_pragma_openmp_end.
ConsumeToken();
return Actions.ActOnOpenMPThreadprivateDirective(Loc,
- getCurScope(),
Identifiers);
}
break;
@@ -55,7 +59,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
break;
default:
Diag(Tok, diag::err_omp_unexpected_directive)
- << getOpenMPDirectiveName(Kind);
+ << getOpenMPDirectiveName(DKind);
break;
}
SkipUntil(tok::annot_pragma_openmp_end, false);
@@ -63,56 +67,69 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
}
/// \brief Parses list of simple variables for '#pragma omp threadprivate'
-/// directive
-/// simple-variable-list:
-/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end
+/// directive.
+///
+/// simple-variable-list:
+/// '(' id-expression {, id-expression} ')'
///
-bool Parser::ParseOpenMPSimpleVarList(
- OpenMPDirectiveKind Kind,
- SmallVectorImpl &IdList) {
+bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
+ SmallVectorImpl &VarList,
+ bool AllowScopeSpecifier) {
+ VarList.clear();
// Parse '('.
- bool IsCorrect = true;
- BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPDirectiveName(Kind))) {
- SkipUntil(tok::annot_pragma_openmp_end, false, true);
- return false;
- }
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ bool LParen = !T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPDirectiveName(Kind));
+ bool IsCorrect = LParen;
+ bool NoIdentIsFound = true;
// Read tokens while ')' or annot_pragma_openmp_end is not found.
- do {
+ while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
CXXScopeSpec SS;
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
// Read var name.
Token PrevTok = Tok;
+ NoIdentIsFound = false;
- if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
- TemplateKWLoc, Name)) {
+ if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
false, true);
- }
- else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
- Tok.isNot(tok::annot_pragma_openmp_end)) {
+ } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
+ TemplateKWLoc, Name)) {
+ IsCorrect = false;
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ false, true);
+ } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
false, true);
- Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id)
- << getLangOpts().CPlusPlus
+ Diag(PrevTok.getLocation(), diag::err_expected_ident)
<< SourceRange(PrevTok.getLocation(), PrevTokLocation);
} else {
- IdList.push_back(Actions.GetNameFromUnqualifiedId(Name));
+ DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name);
+ ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS,
+ NameInfo);
+ if (Res.isUsable())
+ VarList.push_back(Res.take());
}
// Consume ','.
if (Tok.is(tok::comma)) {
ConsumeToken();
}
- } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));
+ }
- if (IsCorrect || Tok.is(tok::r_paren)) {
- IsCorrect = !T.consumeClose() && IsCorrect;
+ if (NoIdentIsFound) {
+ Diag(Tok, diag::err_expected_ident);
+ IsCorrect = false;
}
- return !IsCorrect && IdList.empty();
+ // Parse ')'.
+ IsCorrect = ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose())
+ && IsCorrect;
+
+ return !IsCorrect && VarList.empty();
}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 2117df45f3..a5371f9e61 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -1897,7 +1897,7 @@ bool BalancedDelimiterTracker::diagnoseOverflow() {
P.Diag(P.Tok, diag::err_bracket_depth_exceeded)
<< P.getLangOpts().BracketDepth;
P.Diag(P.Tok, diag::note_bracket_depth);
- P.SkipUntil(tok::eof);
+ P.SkipUntil(tok::eof, FinalToken);
return true;
}
@@ -1927,7 +1927,8 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() {
}
P.Diag(P.Tok, DID);
P.Diag(LOpen, diag::note_matching) << LHSName;
- if (P.SkipUntil(Close, /*StopAtSemi*/ true, /*DontConsume*/ true))
+ if (P.SkipUntil(Close, FinalToken, /*StopAtSemi*/ true, /*DontConsume*/ true)
+ && P.Tok.is(Close))
LClose = P.ConsumeAnyToken();
return true;
}
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 213950a6db..f68a2e09fe 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -358,7 +358,7 @@ namespace clang {
/// pair, such as braces { ... } or parentheses ( ... ).
class BalancedDelimiterTracker : public GreaterThanIsOperatorScope {
Parser& P;
- tok::TokenKind Kind, Close;
+ tok::TokenKind Kind, Close, FinalToken;
SourceLocation (Parser::*Consumer)();
SourceLocation LOpen, LClose;
@@ -377,9 +377,10 @@ namespace clang {
bool diagnoseMissingClose();
public:
- BalancedDelimiterTracker(Parser& p, tok::TokenKind k)
+ BalancedDelimiterTracker(Parser& p, tok::TokenKind k,
+ tok::TokenKind FinalToken = tok::semi)
: GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true),
- P(p), Kind(k)
+ P(p), Kind(k), FinalToken(FinalToken)
{
switch (Kind) {
default: llvm_unreachable("Unexpected balanced token");
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index c815d4f9ab..4953d2d14e 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
/// \file
/// \brief This file implements semantic analysis for OpenMP directives and
-/// clauses
+/// clauses.
///
//===----------------------------------------------------------------------===//
@@ -22,117 +22,121 @@ using namespace clang;
namespace {
- class VarDeclFilterCCC : public CorrectionCandidateCallback {
- private:
- Sema &Actions;
- public:
- VarDeclFilterCCC(Sema &S) : Actions(S) { }
- virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
- NamedDecl *ND = Candidate.getCorrectionDecl();
- if (VarDecl *VD = dyn_cast_or_null(ND)) {
- return VD->hasGlobalStorage() &&
- Actions.isDeclInScope(ND, Actions.getCurLexicalContext(),
- Actions.getCurScope());
- }
- return false;
- }
- };
+class VarDeclFilterCCC : public CorrectionCandidateCallback {
+private:
+ Sema &Actions;
+public:
+ VarDeclFilterCCC(Sema &S) : Actions(S) { }
+ virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
+ NamedDecl *ND = Candidate.getCorrectionDecl();
+ if (VarDecl *VD = dyn_cast_or_null(ND)) {
+ return VD->hasGlobalStorage() &&
+ Actions.isDeclInScope(ND, Actions.getCurLexicalContext(),
+ Actions.getCurScope());
+ }
+ return false;
+ }
+};
}
-Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
- SourceLocation Loc,
- Scope *CurScope,
- ArrayRef IdList) {
- SmallVector Vars;
- for (ArrayRef::iterator I = IdList.begin(),
- E = IdList.end();
- I != E; ++I) {
- LookupResult Lookup(*this, *I, LookupOrdinaryName);
- LookupParsedName(Lookup, CurScope, NULL, true);
- if (Lookup.isAmbiguous())
- continue;
+ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
+ CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id) {
+ LookupResult Lookup(*this, Id, LookupOrdinaryName);
+ LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
- VarDecl *VD;
- if (!Lookup.isSingleResult()) {
- VarDeclFilterCCC Validator(*this);
- TypoCorrection Corrected = CorrectTypo(*I, LookupOrdinaryName, CurScope,
- 0, Validator);
- std::string CorrectedStr = Corrected.getAsString(getLangOpts());
- std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
- if (Lookup.empty()) {
- if (Corrected.isResolved()) {
- Diag(I->getLoc(), diag::err_undeclared_var_use_suggest)
- << I->getName() << CorrectedQuotedStr
- << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
- } else {
- Diag(I->getLoc(), diag::err_undeclared_var_use)
- << I->getName();
- }
+ if (Lookup.isAmbiguous())
+ return ExprError();
+
+ VarDecl *VD;
+ if (!Lookup.isSingleResult()) {
+ VarDeclFilterCCC Validator(*this);
+ TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope,
+ 0, Validator);
+ std::string CorrectedStr = Corrected.getAsString(getLangOpts());
+ std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
+ if (Lookup.empty()) {
+ if (Corrected.isResolved()) {
+ Diag(Id.getLoc(), diag::err_undeclared_var_use_suggest)
+ << Id.getName() << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr);
} else {
- Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
- << I->getName() << Corrected.isResolved() << CorrectedQuotedStr
- << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
+ Diag(Id.getLoc(), diag::err_undeclared_var_use)
+ << Id.getName();
}
- if (!Corrected.isResolved()) continue;
- VD = Corrected.getCorrectionDeclAs();
} else {
- if (!(VD = Lookup.getAsSingle())) {
- Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
- << I->getName() << 0;
- Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
- continue;
- }
+ Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest)
+ << Id.getName() << Corrected.isResolved() << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr);
}
-
- // OpenMP [2.9.2, Syntax, C/C++]
- // Variables must be file-scope, namespace-scope, or static block-scope.
- if (!VD->hasGlobalStorage()) {
- Diag(I->getLoc(), diag::err_omp_global_var_arg)
- << getOpenMPDirectiveName(OMPD_threadprivate)
- << !VD->isStaticLocal();
- Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
- continue;
+ if (!Corrected.isResolved()) return ExprError();
+ VD = Corrected.getCorrectionDeclAs();
+ } else {
+ if (!(VD = Lookup.getAsSingle())) {
+ Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest)
+ << Id.getName() << 0;
+ Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
+ return ExprError();
}
+ }
+ Lookup.suppressDiagnostics();
- // OpenMP [2.9.2, Restrictions, C/C++, p.2]
- // A threadprivate directive for file-scope variables must appear outside
- // any definition or declaration.
- // OpenMP [2.9.2, Restrictions, C/C++, p.3]
- // A threadprivate directive for static class member variables must appear
- // in the class definition, in the same scope in which the member
- // variables are declared.
- // OpenMP [2.9.2, Restrictions, C/C++, p.4]
- // A threadprivate directive for namespace-scope variables must appear
- // outside any definition or declaration other than the namespace
- // definition itself.
- // OpenMP [2.9.2, Restrictions, C/C++, p.6]
- // A threadprivate directive for static block-scope variables must appear
- // in the scope of the variable and not in a nested scope.
- NamedDecl *ND = cast(VD);
- if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
- Diag(I->getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
- Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
- continue;
- }
+ // OpenMP [2.9.2, Syntax, C/C++]
+ // Variables must be file-scope, namespace-scope, or static block-scope.
+ if (!VD->hasGlobalStorage()) {
+ Diag(Id.getLoc(), diag::err_omp_global_var_arg)
+ << getOpenMPDirectiveName(OMPD_threadprivate)
+ << !VD->isStaticLocal();
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD;
+ return ExprError();
+ }
- // OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
- // A threadprivate directive must lexically precede all references to any
- // of the variables in its list.
- if (VD->isUsed()) {
- Diag(I->getLoc(), diag::err_omp_var_used)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
- continue;
- }
+ // OpenMP [2.9.2, Restrictions, C/C++, p.2]
+ // A threadprivate directive for file-scope variables must appear outside
+ // any definition or declaration.
+ // OpenMP [2.9.2, Restrictions, C/C++, p.3]
+ // A threadprivate directive for static class member variables must appear
+ // in the class definition, in the same scope in which the member
+ // variables are declared.
+ // OpenMP [2.9.2, Restrictions, C/C++, p.4]
+ // A threadprivate directive for namespace-scope variables must appear
+ // outside any definition or declaration other than the namespace
+ // definition itself.
+ // OpenMP [2.9.2, Restrictions, C/C++, p.6]
+ // A threadprivate directive for static block-scope variables must appear
+ // in the scope of the variable and not in a nested scope.
+ NamedDecl *ND = cast(VD);
+ if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
+ Diag(Id.getLoc(), diag::err_omp_var_scope)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
+ return ExprError();
+ }
- QualType ExprType = VD->getType().getNonReferenceType();
- DeclRefExpr *Var = cast(BuildDeclRefExpr(VD,
- ExprType,
- VK_RValue,
- I->getLoc()).take());
- Vars.push_back(Var);
+ // OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
+ // A threadprivate directive must lexically precede all references to any
+ // of the variables in its list.
+ if (VD->isUsed()) {
+ Diag(Id.getLoc(), diag::err_omp_var_used)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ return ExprError();
}
- if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) {
+
+ QualType ExprType = VD->getType().getNonReferenceType();
+ ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_RValue, Id.getLoc());
+ return DE;
+}
+
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
+ SourceLocation Loc,
+ ArrayRef VarList) {
+ if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) {
CurContext->addDecl(D);
return DeclGroupPtrTy::make(DeclGroupRef(D));
}
@@ -141,18 +145,19 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
SourceLocation Loc,
- ArrayRef VarList) {
- SmallVector Vars;
- for (ArrayRef::iterator I = VarList.begin(),
+ ArrayRef VarList) {
+ SmallVector Vars;
+ for (ArrayRef::iterator I = VarList.begin(),
E = VarList.end();
I != E; ++I) {
- VarDecl *VD = cast((*I)->getDecl());
- SourceLocation ILoc = (*I)->getLocation();
+ DeclRefExpr *DE = cast(*I);
+ VarDecl *VD = cast(DE->getDecl());
+ SourceLocation ILoc = DE->getExprLoc();
// OpenMP [2.9.2, Restrictions, C/C++, p.10]
// A threadprivate variable must not have an incomplete type.
if (RequireCompleteType(ILoc, VD->getType(),
- diag::err_omp_incomplete_type)) {
+ diag::err_omp_threadprivate_incomplete_type)) {
continue;
}
@@ -160,15 +165,21 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
// A threadprivate variable must not have a reference type.
if (VD->getType()->isReferenceType()) {
Diag(ILoc, diag::err_omp_ref_type_arg)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType();
- Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ << getOpenMPDirectiveName(OMPD_threadprivate);
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
continue;
}
// Check if this is a TLS variable.
if (VD->getTLSKind()) {
Diag(ILoc, diag::err_omp_var_thread_local) << VD;
- Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
+ diag::note_defined_here) << VD;
continue;
}
@@ -179,3 +190,4 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
getCurLexicalContext(),
Loc, Vars);
}
+
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 42e1757bcb..ff59cdcbc4 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2231,13 +2231,13 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
OMPThreadPrivateDecl *D) {
- SmallVector Vars;
- for (ArrayRef::iterator I = D->varlist_begin(),
- E = D->varlist_end();
+ SmallVector Vars;
+ for (ArrayRef::iterator I = D->varlist_begin(),
+ E = D->varlist_end();
I != E; ++I) {
Expr *Var = SemaRef.SubstExpr(*I, TemplateArgs).take();
assert(isa(Var) && "threadprivate arg is not a DeclRefExpr");
- Vars.push_back(cast(Var));
+ Vars.push_back(Var);
}
OMPThreadPrivateDecl *TD =
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index e3f9f43a3b..b117b733a4 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1644,10 +1644,10 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable *D,
void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
VisitDecl(D);
unsigned NumVars = D->varlist_size();
- SmallVector Vars;
+ SmallVector Vars;
Vars.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i) {
- Vars.push_back(cast(Reader.ReadExpr(F)));
+ Vars.push_back(Reader.ReadExpr(F));
}
D->setVars(Vars);
}
diff --git a/test/OpenMP/predefined_macro.c b/test/OpenMP/predefined_macro.c
index cf6c0cc611..3a81186209 100644
--- a/test/OpenMP/predefined_macro.c
+++ b/test/OpenMP/predefined_macro.c
@@ -31,4 +31,3 @@
#error "_OPENMP macro is defined without -fopenmp option"
#endif // _OPENMP
#endif // FOPENMP
-
diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp
index 0c448b2ef2..1bfba6d864 100644
--- a/test/OpenMP/threadprivate_messages.cpp
+++ b/test/OpenMP/threadprivate_messages.cpp
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s
-#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}}
-#pragma omp threadprivate( // expected-error {{expected unqualified-id}}
-#pragma omp threadprivate() // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} expected-error {{expected identifier}}
+#pragma omp threadprivate( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma omp threadprivate() // expected-error {{expected identifier}}
#pragma omp threadprivate(1) // expected-error {{expected unqualified-id}}
struct CompleteSt{
int a;
@@ -11,27 +11,27 @@ struct CompleteSt{
struct CompleteSt1{
#pragma omp threadprivate(1) // expected-error {{expected unqualified-id}}
int a;
-} d; // expected-note {{forward declaration of 'd'}}
+} d; // expected-note {{'d' defined here}}
-int a; // expected-note {{forward declaration of 'a'}}
+int a; // expected-note {{'a' defined here}}
#pragma omp threadprivate(a)
#pragma omp threadprivate(u) // expected-error {{use of undeclared identifier 'u'}}
#pragma omp threadprivate(d, a) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}}
int foo() { // expected-note {{declared here}}
static int l;
-#pragma omp threadprivate(l)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate(l)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
return (a);
}
-#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}}
+#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}}
#pragma omp threadprivate(d // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}}
-#pragma omp threadprivate(d))
+#pragma omp threadprivate(d)) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
int x, y;
-#pragma omp threadprivate(x)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
-#pragma omp threadprivate(y)), // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate(x)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate(y)), // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
#pragma omp threadprivate(a,d) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}}
-#pragma omp threadprivate(d.a) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate(d.a) // expected-error {{expected identifier}}
#pragma omp threadprivate((float)a) // expected-error {{expected unqualified-id}}
int foa;
#pragma omp threadprivate(faa) // expected-error {{use of undeclared identifier 'faa'; did you mean 'foa'?}}
@@ -41,31 +41,31 @@ int foa;
struct IncompleteSt; // expected-note {{forward declaration of 'IncompleteSt'}}
extern IncompleteSt e;
-#pragma omp threadprivate (e) // expected-error {{a threadprivate variable must not have incomplete type 'IncompleteSt'}}
+#pragma omp threadprivate (e) // expected-error {{threadprivate variable with incomplete type 'IncompleteSt'}}
-int &f = a; // expected-note {{forward declaration of 'f'}}
-#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type 'int &'}}
+int &f = a; // expected-note {{'f' defined here}}
+#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type}}
class Class {
private:
int a; // expected-note {{declared here}}
- static int b;
+ static int b; // expected-note {{'b' declared here}}
Class() : a(0){}
public:
Class (int aaa) : a(aaa) {}
#pragma omp threadprivate (b, a) // expected-error {{'a' is not a global variable, static local variable or static data member}}
} g(10);
#pragma omp threadprivate (b) // expected-error {{use of undeclared identifier 'b'}}
-#pragma omp threadprivate (Class::b) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate (Class::b) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'Class::b' variable declaration}}
#pragma omp threadprivate (g)
namespace ns {
- int m;
+ int m; // expected-note 2 {{'m' defined here}}
#pragma omp threadprivate (m)
}
#pragma omp threadprivate (m) // expected-error {{use of undeclared identifier 'm'}}
-#pragma omp threadprivate (ns::m) // expected-error {{expected unqualified-id}}
-#pragma omp threadprivate (ns:m) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate (ns::m) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'ns::m' variable declaration}}
+#pragma omp threadprivate (ns:m) // expected-error {{unexpected ':' in nested name specifier; did you mean '::'?}} expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'ns::m' variable declaration}}
const int h = 12;
const volatile int i = 10;
@@ -84,26 +84,30 @@ class TempClass {
};
#pragma omp threadprivate (s) // expected-error {{use of undeclared identifier 's'}}
-static __thread int t; // expected-note {{forward declaration of 't'}}
+static __thread int t; // expected-note {{'t' defined here}}
#pragma omp threadprivate (t) // expected-error {{variable 't' cannot be threadprivate because it is thread-local}}
int o; // expected-note {{candidate found by name lookup is 'o'}}
+#pragma omp threadprivate (o)
namespace {
int o; // expected-note {{candidate found by name lookup is '::o'}}
+#pragma omp threadprivate (o)
+#pragma omp threadprivate (o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable '::o'}}
}
#pragma omp threadprivate (o) // expected-error {{reference to 'o' is ambiguous}}
+#pragma omp threadprivate (::o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'o'}}
-int main(int argc, char **argv) { // expected-note {{forward declaration of 'argc'}}
+int main(int argc, char **argv) { // expected-note {{'argc' defined here}}
- int x, y = argc; // expected-note {{forward declaration of 'y'}}
+ int x, y = argc; // expected-note {{'y' defined here}}
static double d1;
static double d2;
- static double d3; // expected-note {{forward declaration of 'd3'}}
+ static double d3; // expected-note {{'d3' defined here}}
d.a = a;
d2++;
;
-#pragma omp threadprivate(argc+y) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate(argc+y) // expected-error {{expected identifier}}
#pragma omp threadprivate(argc,y) // expected-error 2 {{arguments of '#pragma omp threadprivate' must have static storage duration}}
#pragma omp threadprivate(d2) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd2'}}
#pragma omp threadprivate(d1)
--
cgit v1.2.3
From f8aa155e40bc98844f46ecbfdbe430696c36ce24 Mon Sep 17 00:00:00 2001
From: David Blaikie
Date: Mon, 13 May 2013 06:57:50 +0000
Subject: Debug Info: PR14992: Support values for non-type template parameters
of function type
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181685 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/CodeGen/CGDebugInfo.cpp | 4 +++-
test/CodeGenCXX/debug-info-template.cpp | 23 +++++++++++++++--------
2 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 13b681edc9..583b23980e 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -1220,9 +1220,11 @@ CollectTemplateParams(const TemplateParameterList *TPList,
V = CGM.GetAddrOfGlobalVar(VD);
// Member function pointers have special support for building them, though
// this is currently unsupported in LLVM CodeGen.
- if (InstanceMember)
+ if (InstanceMember) {
if (const CXXMethodDecl *method = dyn_cast(D))
V = CGM.getCXXABI().EmitMemberPointer(method);
+ } else if (const FunctionDecl *FD = dyn_cast(D))
+ V = CGM.GetAddrOfFunction(FD);
// Member data pointers have special handling too to compute the fixed
// offset within the object.
if (isa(D)) {
diff --git a/test/CodeGenCXX/debug-info-template.cpp b/test/CodeGenCXX/debug-info-template.cpp
index 1d2dc10cf2..a97c991f38 100644
--- a/test/CodeGenCXX/debug-info-template.cpp
+++ b/test/CodeGenCXX/debug-info-template.cpp
@@ -2,6 +2,9 @@
// CHECK: [[EMPTY:![0-9]*]] = metadata !{i32 0}
+// CHECK: [[FUNTYPE:![0-9]*]] = {{.*}}, metadata [[FUNARGS:![0-9]*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[FUNARGS]] = metadata !{null}
+
// func<...> doesn't have any template arguments listed since we don't support
// packs yet. This could be encoded with GNU's
// DW_TAG_GNU_template_parameter_pack extension.
@@ -9,8 +12,8 @@
// CHECK: [[INT:![0-9]*]] = {{.*}} ; [ DW_TAG_base_type ] [int]
// CHECK: metadata [[TCI:![0-9]*]], i32 0, i32 1, %class.TC* @tci, null} ; [ DW_TAG_variable ] [tci]
-// CHECK: [[TC:![0-9]*]] = {{.*}}, metadata [[TCARGS:![0-9]*]]} ; [ DW_TAG_class_type ] [TC]
-// CHECK: [[TCARGS]] = metadata !{metadata [[TCARG1:![0-9]*]], metadata [[TCARG2:![0-9]*]], metadata [[TCARG3:![0-9]*]], metadata [[TCARG4:![0-9]*]], metadata [[TCARG5:![0-9]*]]}
+// CHECK: [[TC:![0-9]*]] = {{.*}}, metadata [[TCARGS:![0-9]*]]} ; [ DW_TAG_class_type ] [TC]
+// CHECK: [[TCARGS]] = metadata !{metadata [[TCARG1:![0-9]*]], metadata [[TCARG2:![0-9]*]], metadata [[TCARG3:![0-9]*]], metadata [[TCARG4:![0-9]*]], metadata [[TCARG5:![0-9]*]], metadata [[TCARG6:![0-9]*]]}
//
// We seem to be missing file/line/col info on template value parameters -
// metadata supports it but it's not populated. GCC doesn't emit it either,
@@ -39,11 +42,13 @@
//
// CHECK: [[TCARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR:![0-9]*]], { i64, i64 } { i64 ptrtoint (void (%struct.foo*)* @_ZN3foo1fEv to i64), i64 0 }, {{.*}} ; [ DW_TAG_template_value_parameter ]
// CHECK: [[MEMFUNPTR]] = {{.*}}, metadata [[FTYPE]], metadata [[FOO]]} ; [ DW_TAG_ptr_to_member_type ]
+// CHECK: [[TCARG6]] = {{.*}}metadata !"f", metadata [[FUNPTR:![0-9]*]], void ()* @_Z4funcv, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[FUNPTR]] = {{.*}}, metadata [[FUNTYPE]]} ; [ DW_TAG_pointer_type ]
// CHECK: metadata [[TCNT:![0-9]*]], i32 0, i32 1, %class.TC.0* @tcn, null} ; [ DW_TAG_variable ] [tcn]
-// CHECK: [[TCNT:![0-9]*]] = {{.*}}, metadata [[TCNARGS:![0-9]*]]} ; [ DW_TAG_class_type ] [TC]
-// CHECK: [[TCNARGS]] = metadata !{metadata [[TCNARG1:![0-9]*]], metadata [[TCNARG2:![0-9]*]], metadata [[TCNARG3:![0-9]*]], metadata [[TCNARG4:![0-9]*]], metadata [[TCNARG5:![0-9]*]]}
+// CHECK: [[TCNT:![0-9]*]] = {{.*}}, metadata [[TCNARGS:![0-9]*]]} ; [ DW_TAG_class_type ] [TC]
+// CHECK: [[TCNARGS]] = metadata !{metadata [[TCNARG1:![0-9]*]], metadata [[TCNARG2:![0-9]*]], metadata [[TCNARG3:![0-9]*]], metadata [[TCNARG4:![0-9]*]], metadata [[TCNARG5:![0-9]*]], metadata [[TCNARG6:![0-9]*]]}
// CHECK: [[TCNARG1]] = {{.*}}metadata !"T", metadata [[INT]], {{.*}} ; [ DW_TAG_template_type_parameter ]
// CHECK: [[TCNARG2]] = {{.*}}metadata !"", metadata [[INT]], i32 -3, {{.*}} ; [ DW_TAG_template_value_parameter ]
// CHECK: [[TCNARG3]] = {{.*}}metadata !"x", metadata [[INTPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ]
@@ -59,21 +64,23 @@
// naturally from the LLVM CodeGen side once we decide how to handle non-null
// member function pointers. For now, it's simpler just to emit the 'i8 0'.
//
-// CHECK: [[TCNARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR:![0-9]*]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCNARG5]] = {{.*}}metadata !"b", metadata [[MEMFUNPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ]
+// CHECK: [[TCNARG6]] = {{.*}}metadata !"f", metadata [[FUNPTR]], i8 0, {{.*}} ; [ DW_TAG_template_value_parameter ]
struct foo {
char pad[8]; // make the member pointer to 'e' a bit more interesting (nonzero)
int e;
void f();
};
-template
+template
class TC {
};
int glb;
+void func();
-TC tci;
-TC tcn;
+TC tci;
+TC tcn;
template int func() { return 0; }
int anchor = func();
--
cgit v1.2.3
From 378d93dcf7ec80661efc65642dc6266c9e13780a Mon Sep 17 00:00:00 2001
From: Daniel Jasper
Date: Mon, 13 May 2013 07:14:40 +0000
Subject: Assume macros to contain declarations.
This seems to be the vastly more common case. If we find enough
examples to the contrary, we can make it smarter.
Before: #define MACRO void f(int * a)
After: #define MACRO void f(int *a)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181687 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/Format/TokenAnnotator.cpp | 1 +
unittests/Format/FormatTest.cpp | 6 ++++++
2 files changed, 7 insertions(+)
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 12031166e2..29eaaa8b58 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -591,6 +591,7 @@ private:
}
} else if (Current.isOneOf(tok::kw_return, tok::kw_throw) ||
(Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
+ !Line.InPPDirective &&
(!Current.Parent || Current.Parent->isNot(tok::kw_for)))) {
Contexts.back().IsExpression = true;
} else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) {
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index f694c5b214..9b3fb9cc06 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -2638,10 +2638,16 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyFormat("for (int i = a * a; i < 10; ++i) {\n}");
verifyFormat("for (int i = 0; i < a * a; ++i) {\n}");
+ verifyFormat("#define MACRO \\\n"
+ " int *i = a * b; \\\n"
+ " void f(a *b);",
+ getLLVMStyleWithColumns(19));
+
verifyIndependentOfContext("A = new SomeType *[Length];");
verifyIndependentOfContext("A = new SomeType *[Length]();");
verifyGoogleFormat("A = new SomeType* [Length]();");
verifyGoogleFormat("A = new SomeType* [Length];");
+
FormatStyle PointerLeft = getLLVMStyle();
PointerLeft.PointerBindsToType = true;
verifyFormat("delete *x;", PointerLeft);
--
cgit v1.2.3
From 07a64eca75d96ce77d1ce8cb73d1cb0877695d06 Mon Sep 17 00:00:00 2001
From: Manuel Klimek
Date: Mon, 13 May 2013 08:42:42 +0000
Subject: Implements IndentWidth.
This is required for various styles that are for example based on
8-indent.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181690 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/Format/Format.h | 6 +++++-
lib/Format/Format.cpp | 14 +++++++++++---
unittests/Format/FormatTest.cpp | 31 +++++++++++++++++++++++++++++++
3 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index 9d17c77db7..dd8f666180 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -94,6 +94,9 @@ struct FormatStyle {
/// Otherwise puts them into the right-most column.
bool AlignEscapedNewlinesLeft;
+ /// \brief The number of characters to use for indentation.
+ unsigned IndentWidth;
+
bool operator==(const FormatStyle &R) const {
return AccessModifierOffset == R.AccessModifierOffset &&
AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft &&
@@ -113,7 +116,8 @@ struct FormatStyle {
PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine &&
PointerBindsToType == R.PointerBindsToType &&
SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
- Standard == R.Standard;
+ Standard == R.Standard &&
+ IndentWidth == IndentWidth;
}
};
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 9a320f94bd..d5676814c1 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -85,6 +85,7 @@ template <> struct MappingTraits {
IO.mapOptional("SpacesBeforeTrailingComments",
Style.SpacesBeforeTrailingComments);
IO.mapOptional("Standard", Style.Standard);
+ IO.mapOptional("IndentWidth", Style.IndentWidth);
}
};
}
@@ -111,6 +112,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.PointerBindsToType = false;
LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.Standard = FormatStyle::LS_Cpp03;
+ LLVMStyle.IndentWidth = 2;
return LLVMStyle;
}
@@ -132,6 +134,7 @@ FormatStyle getGoogleStyle() {
GoogleStyle.PointerBindsToType = true;
GoogleStyle.SpacesBeforeTrailingComments = 2;
GoogleStyle.Standard = FormatStyle::LS_Auto;
+ GoogleStyle.IndentWidth = 2;
return GoogleStyle;
}
@@ -429,7 +432,7 @@ private:
if (Newline) {
unsigned WhitespaceStartColumn = State.Column;
if (Current.is(tok::r_brace)) {
- State.Column = Line.Level * 2;
+ State.Column = Line.Level * Style.IndentWidth;
} else if (Current.is(tok::string_literal) &&
State.StartOfStringLiteral != 0) {
State.Column = State.StartOfStringLiteral;
@@ -604,6 +607,11 @@ private:
Current.LastInChainOfCalls ? 0 : State.Column +
Current.FormatTok.TokenLength;
if (Current.Type == TT_CtorInitializerColon) {
+ // Indent 2 from the column, so:
+ // SomeClass::SomeClass()
+ // : First(...), ...
+ // Next(...)
+ // ^ line up here.
State.Stack.back().Indent = State.Column + 2;
if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
State.Stack.back().AvoidBinPacking = true;
@@ -656,7 +664,7 @@ private:
unsigned NewIndent;
bool AvoidBinPacking;
if (Current.is(tok::l_brace)) {
- NewIndent = 2 + State.Stack.back().LastSpace;
+ NewIndent = Style.IndentWidth + State.Stack.back().LastSpace;
AvoidBinPacking = false;
} else {
NewIndent = 4 + std::max(State.Stack.back().LastSpace,
@@ -1253,7 +1261,7 @@ private:
return IndentForLevel[Level];
if (Level == 0)
return 0;
- return getIndent(IndentForLevel, Level - 1) + 2;
+ return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;
}
/// \brief Get the offset of the line relatively to the level.
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 9b3fb9cc06..f0319d5e48 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -3959,6 +3959,36 @@ TEST_F(FormatTest, DoNotCreateUnreasonableUnwrappedLines) {
"}");
}
+TEST_F(FormatTest, FormatsClosingBracesInEmptyNestedBlocks) {
+ verifyFormat("class X {\n"
+ " void f() {\n"
+ " }\n"
+ "};",
+ getLLVMStyleWithColumns(12));
+}
+
+TEST_F(FormatTest, ConfigurableIndentWidth) {
+ FormatStyle EightIndent = getLLVMStyleWithColumns(18);
+ EightIndent.IndentWidth = 8;
+ verifyFormat("void f() {\n"
+ " someFunction();\n"
+ " if (true) {\n"
+ " f();\n"
+ " }\n"
+ "}",
+ EightIndent);
+ verifyFormat("class X {\n"
+ " void f() {\n"
+ " }\n"
+ "};",
+ EightIndent);
+ verifyFormat("int x[] = {\n"
+ " call(),\n"
+ " call(),\n"
+ "};",
+ EightIndent);
+}
+
bool allStylesEqual(ArrayRef Styles) {
for (size_t i = 1; i < Styles.size(); ++i)
if (!(Styles[0] == Styles[i]))
@@ -4022,6 +4052,7 @@ TEST_F(FormatTest, ParsesConfiguration) {
PenaltyReturnTypeOnItsOwnLine, 1234u);
CHECK_PARSE("SpacesBeforeTrailingComments: 1234",
SpacesBeforeTrailingComments, 1234u);
+ CHECK_PARSE("IndentWidth: 32", IndentWidth, 32u);
Style.Standard = FormatStyle::LS_Auto;
CHECK_PARSE("Standard: C++03", Standard, FormatStyle::LS_Cpp03);
--
cgit v1.2.3
From c3df5ffb52cb656c3a4d0b4d70f8f28ed2390e78 Mon Sep 17 00:00:00 2001
From: Daniel Jasper
Date: Mon, 13 May 2013 09:19:24 +0000
Subject: Further improve optimization for nested calls.
Fake parentheses (i.e. emulated parentheses used to correctly handle
binary expressions) used to prevent the optimization implemented in
r180264.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181692 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/Format/Format.cpp | 32 ++++++++++++++++++++++----------
unittests/Format/FormatTest.cpp | 27 +++++++++++++++++++++++++++
2 files changed, 49 insertions(+), 10 deletions(-)
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index d5676814c1..f3ca9c371f 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -270,7 +270,7 @@ private:
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
NestedNameSpecifierContinuation(0), CallContinuation(0),
- VariablePos(0) {}
+ VariablePos(0), ForFakeParenthesis(false) {}
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
@@ -329,6 +329,13 @@ private:
/// Used to align further variables if necessary.
unsigned VariablePos;
+ /// \brief \c true if this \c ParenState was created for a fake parenthesis.
+ ///
+ /// Does not need to be considered for memoization / the comparison function
+ /// as otherwise identical states will have the same fake/non-fake
+ /// \c ParenStates.
+ bool ForFakeParenthesis;
+
bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
@@ -641,6 +648,7 @@ private:
E = Current.FakeLParens.rend();
I != E; ++I) {
ParenState NewParenState = State.Stack.back();
+ NewParenState.ForFakeParenthesis = true;
NewParenState.Indent =
std::max(std::max(State.Column, NewParenState.Indent),
State.Stack.back().LastSpace);
@@ -662,27 +670,31 @@ private:
// prepare for the following tokens.
if (Current.opensScope()) {
unsigned NewIndent;
+ unsigned LastSpace = State.Stack.back().LastSpace;
bool AvoidBinPacking;
if (Current.is(tok::l_brace)) {
- NewIndent = Style.IndentWidth + State.Stack.back().LastSpace;
+ NewIndent = Style.IndentWidth + LastSpace;
AvoidBinPacking = false;
} else {
- NewIndent = 4 + std::max(State.Stack.back().LastSpace,
- State.Stack.back().StartOfFunctionCall);
+ NewIndent =
+ 4 + std::max(LastSpace, State.Stack.back().StartOfFunctionCall);
AvoidBinPacking = !Style.BinPackParameters;
}
- State.Stack.push_back(
- ParenState(NewIndent, State.Stack.back().LastSpace, AvoidBinPacking,
- State.Stack.back().NoLineBreak));
if (Current.NoMoreTokensOnLevel && Current.FakeLParens.empty()) {
// This parenthesis was the last token possibly making use of Indent and
- // LastSpace of the next higher ParenLevel. Thus, erase them to acieve
+ // LastSpace of the next higher ParenLevel. Thus, erase them to achieve
// better memoization results.
- State.Stack[State.Stack.size() - 2].Indent = 0;
- State.Stack[State.Stack.size() - 2].LastSpace = 0;
+ for (unsigned i = State.Stack.size() - 1; i > 0; --i) {
+ State.Stack[i].Indent = 0;
+ State.Stack[i].LastSpace = 0;
+ if (!State.Stack[i].ForFakeParenthesis)
+ break;
+ }
}
+ State.Stack.push_back(ParenState(NewIndent, LastSpace, AvoidBinPacking,
+ State.Stack.back().NoLineBreak));
++State.ParenLevel;
}
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index f0319d5e48..931d29dd3e 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -1761,6 +1761,33 @@ TEST_F(FormatTest, MemoizationTests) {
" aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(aaaaa(\n"
" aaaaa())))))))))))))))))))))))))))))))))))))));",
getLLVMStyleWithColumns(65));
+ verifyFormat(
+ "aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa(\n"
+ " aaaaa,\n"
+ " aaaaa))))))))))));",
+ getLLVMStyleWithColumns(65));
// This test takes VERY long when memoization is broken.
FormatStyle OnePerLine = getLLVMStyle();
--
cgit v1.2.3
From 7c9a93ec7cea816e94a0674909c312f3d0227864 Mon Sep 17 00:00:00 2001
From: Manuel Klimek
Date: Mon, 13 May 2013 09:22:11 +0000
Subject: Implements UseTab for clang-format.
This is required for kernel linux kernel style formatting.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181693 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/Format/Format.h | 7 ++++++-
lib/Format/Format.cpp | 3 +++
lib/Format/WhitespaceManager.cpp | 12 ++++++++++--
lib/Format/WhitespaceManager.h | 2 ++
unittests/Format/FormatTest.cpp | 22 ++++++++++++++++++++++
5 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index dd8f666180..79e26d0a0c 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -97,6 +97,10 @@ struct FormatStyle {
/// \brief The number of characters to use for indentation.
unsigned IndentWidth;
+ /// \brief If true, \c IndentWidth consecutive spaces will be replaced with
+ /// tab characters.
+ bool UseTab;
+
bool operator==(const FormatStyle &R) const {
return AccessModifierOffset == R.AccessModifierOffset &&
AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft &&
@@ -117,7 +121,8 @@ struct FormatStyle {
PointerBindsToType == R.PointerBindsToType &&
SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
Standard == R.Standard &&
- IndentWidth == IndentWidth;
+ IndentWidth == R.IndentWidth &&
+ UseTab == R.UseTab;
}
};
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index f3ca9c371f..2f2f095780 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -86,6 +86,7 @@ template <> struct MappingTraits {
Style.SpacesBeforeTrailingComments);
IO.mapOptional("Standard", Style.Standard);
IO.mapOptional("IndentWidth", Style.IndentWidth);
+ IO.mapOptional("UseTab", Style.UseTab);
}
};
}
@@ -113,6 +114,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.Standard = FormatStyle::LS_Cpp03;
LLVMStyle.IndentWidth = 2;
+ LLVMStyle.UseTab = false;
return LLVMStyle;
}
@@ -135,6 +137,7 @@ FormatStyle getGoogleStyle() {
GoogleStyle.SpacesBeforeTrailingComments = 2;
GoogleStyle.Standard = FormatStyle::LS_Auto;
GoogleStyle.IndentWidth = 2;
+ GoogleStyle.UseTab = false;
return GoogleStyle;
}
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index a75c592bfe..21e38b1e97 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -122,7 +122,7 @@ void WhitespaceManager::addUntouchableComment(unsigned Column) {
std::string WhitespaceManager::getNewLineText(unsigned NewLines,
unsigned Spaces) {
- return std::string(NewLines, '\n') + std::string(Spaces, ' ');
+ return std::string(NewLines, '\n') + getIndentText(Spaces);
}
std::string WhitespaceManager::getNewLineText(unsigned NewLines,
@@ -139,7 +139,15 @@ std::string WhitespaceManager::getNewLineText(unsigned NewLines,
Offset = 0;
}
}
- return NewLineText + std::string(Spaces, ' ');
+ return NewLineText + getIndentText(Spaces);
+}
+
+std::string WhitespaceManager::getIndentText(unsigned Spaces) {
+ if (!Style.UseTab) {
+ return std::string(Spaces, ' ');
+ }
+ return std::string(Spaces / Style.IndentWidth, '\t') +
+ std::string(Spaces % Style.IndentWidth, ' ');
}
void WhitespaceManager::alignComments() {
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index 5f3dc55eda..1b24b3f6d7 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -78,6 +78,8 @@ private:
unsigned WhitespaceStartColumn,
unsigned EscapedNewlineColumn);
+ std::string getIndentText(unsigned Spaces);
+
/// \brief Structure to store tokens for later layout and alignment.
struct StoredToken {
StoredToken(SourceLocation ReplacementLoc, unsigned ReplacementLength,
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 931d29dd3e..ce79a1c97b 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -4016,6 +4016,27 @@ TEST_F(FormatTest, ConfigurableIndentWidth) {
EightIndent);
}
+TEST_F(FormatTest, ConfigurableUseOfTab) {
+ FormatStyle Tab = getLLVMStyleWithColumns(42);
+ Tab.IndentWidth = 8;
+ Tab.UseTab = true;
+ Tab.AlignEscapedNewlinesLeft = true;
+ verifyFormat("class X {\n"
+ "\tvoid f() {\n"
+ "\t\tsomeFunction(parameter1,\n"
+ "\t\t\t parameter2);\n"
+ "\t}\n"
+ "};",
+ Tab);
+ verifyFormat("#define A \\\n"
+ "\tvoid f() { \\\n"
+ "\t\tsomeFunction( \\\n"
+ "\t\t parameter1, \\\n"
+ "\t\t parameter2); \\\n"
+ "\t}",
+ Tab);
+}
+
bool allStylesEqual(ArrayRef Styles) {
for (size_t i = 1; i < Styles.size(); ++i)
if (!(Styles[0] == Styles[i]))
@@ -4070,6 +4091,7 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE_BOOL(IndentCaseLabels);
CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
CHECK_PARSE_BOOL(PointerBindsToType);
+ CHECK_PARSE_BOOL(UseTab);
CHECK_PARSE("AccessModifierOffset: -1234", AccessModifierOffset, -1234);
CHECK_PARSE("ColumnLimit: 1234", ColumnLimit, 1234u);
--
cgit v1.2.3
From af64032b085d3711405dbe8d98f71c463e0fb52b Mon Sep 17 00:00:00 2001
From: Alexander Kornienko
Date: Mon, 13 May 2013 12:41:08 +0000
Subject: =?UTF-8?q?Fixes=20[Bug=2015960]=20YAMLTraits=20doesn't=20roundtri?=
=?UTF-8?q?p=20on=20Windows.=20Thanks=20to=20Kim=20Gr=C3=A4sman=20for=20he?=
=?UTF-8?q?lp!?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181699 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/Format/Format.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 2f2f095780..a62fa379ab 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -191,6 +191,7 @@ std::string configurationAsText(const FormatStyle &Style) {
// reference here.
FormatStyle NonConstStyle = Style;
Output << NonConstStyle;
+ Stream.flush();
return Text;
}
--
cgit v1.2.3
From 44135b8836fc3ffb84e540d8a097955271ccbc23 Mon Sep 17 00:00:00 2001
From: Manuel Klimek
Date: Mon, 13 May 2013 12:51:40 +0000
Subject: Implements brace breaking styles.
We now support "Linux" and "Stroustrup" brace breaking styles, which
gets us one step closer to support formatting WebKit, KDE & Linux code.
Linux brace breaking style:
namespace a
{
class A
{
void f()
{
if (x) {
f();
} else {
g();
}
}
}
}
Stroustrup brace breaking style:
namespace a {
class A {
void f()
{
if (x) {
f();
} else {
g();
}
}
}
}
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181700 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/Format/Format.h | 17 ++++++++++++++-
lib/Format/Format.cpp | 23 +++++++++++++++-----
lib/Format/UnwrappedLineParser.cpp | 13 ++++++++++-
unittests/Format/FormatTest.cpp | 44 ++++++++++++++++++++++++++++++++++++++
4 files changed, 90 insertions(+), 7 deletions(-)
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index 79e26d0a0c..47b5bb6907 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -101,6 +101,20 @@ struct FormatStyle {
/// tab characters.
bool UseTab;
+ /// \brief Different ways to attach braces to their surrounding context.
+ enum BraceBreakingStyle {
+ /// Always attach braces to surrounding context.
+ BS_Attach,
+ /// Like \c Attach, but break before braces on function, namespace and
+ /// class definitions.
+ BS_Linux,
+ /// Like \c Attach, but break before function definitions.
+ BS_Stroustrup
+ };
+
+ /// \brief The brace breaking style to use.
+ BraceBreakingStyle BreakBeforeBraces;
+
bool operator==(const FormatStyle &R) const {
return AccessModifierOffset == R.AccessModifierOffset &&
AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft &&
@@ -122,7 +136,8 @@ struct FormatStyle {
SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
Standard == R.Standard &&
IndentWidth == R.IndentWidth &&
- UseTab == R.UseTab;
+ UseTab == R.UseTab &&
+ BreakBeforeBraces == R.BreakBeforeBraces;
}
};
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index a62fa379ab..b8c40cf263 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -36,11 +36,21 @@ namespace llvm {
namespace yaml {
template <>
struct ScalarEnumerationTraits {
- static void enumeration(IO &io,
- clang::format::FormatStyle::LanguageStandard &value) {
- io.enumCase(value, "C++03", clang::format::FormatStyle::LS_Cpp03);
- io.enumCase(value, "C++11", clang::format::FormatStyle::LS_Cpp11);
- io.enumCase(value, "Auto", clang::format::FormatStyle::LS_Auto);
+ static void enumeration(IO &IO,
+ clang::format::FormatStyle::LanguageStandard &Value) {
+ IO.enumCase(Value, "C++03", clang::format::FormatStyle::LS_Cpp03);
+ IO.enumCase(Value, "C++11", clang::format::FormatStyle::LS_Cpp11);
+ IO.enumCase(Value, "Auto", clang::format::FormatStyle::LS_Auto);
+ }
+};
+
+template<>
+struct ScalarEnumerationTraits {
+ static void
+ enumeration(IO &IO, clang::format::FormatStyle::BraceBreakingStyle &Value) {
+ IO.enumCase(Value, "Attach", clang::format::FormatStyle::BS_Attach);
+ IO.enumCase(Value, "Linux", clang::format::FormatStyle::BS_Linux);
+ IO.enumCase(Value, "Stroustrup", clang::format::FormatStyle::BS_Stroustrup);
}
};
@@ -87,6 +97,7 @@ template <> struct MappingTraits {
IO.mapOptional("Standard", Style.Standard);
IO.mapOptional("IndentWidth", Style.IndentWidth);
IO.mapOptional("UseTab", Style.UseTab);
+ IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
}
};
}
@@ -115,6 +126,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.Standard = FormatStyle::LS_Cpp03;
LLVMStyle.IndentWidth = 2;
LLVMStyle.UseTab = false;
+ LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
return LLVMStyle;
}
@@ -138,6 +150,7 @@ FormatStyle getGoogleStyle() {
GoogleStyle.Standard = FormatStyle::LS_Auto;
GoogleStyle.IndentWidth = 2;
GoogleStyle.UseTab = false;
+ GoogleStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
return GoogleStyle;
}
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 722af5d2b7..a08790d80d 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -402,6 +402,10 @@ void UnwrappedLineParser::parseStructuralElement() {
// structural element.
// FIXME: Figure out cases where this is not true, and add projections for
// them (the one we know is missing are lambdas).
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
+ Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup)
+ addUnwrappedLine();
+
parseBlock(/*MustBeDeclaration=*/ false);
addUnwrappedLine();
return;
@@ -577,6 +581,9 @@ void UnwrappedLineParser::parseNamespace() {
if (FormatTok.Tok.is(tok::identifier))
nextToken();
if (FormatTok.Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Linux)
+ addUnwrappedLine();
+
parseBlock(/*MustBeDeclaration=*/ true, 0);
// Munch the semicolon after a namespace. This is more common than one would
// think. Puttin the semicolon into its own line is very ugly.
@@ -751,8 +758,12 @@ void UnwrappedLineParser::parseRecord() {
}
}
}
- if (FormatTok.Tok.is(tok::l_brace))
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Linux)
+ addUnwrappedLine();
+
parseBlock(/*MustBeDeclaration=*/ true);
+ }
// We fall through to parsing a structural element afterwards, so
// class A {} n, m;
// will end up in one unwrapped line.
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index ce79a1c97b..9624ac9224 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -4037,6 +4037,42 @@ TEST_F(FormatTest, ConfigurableUseOfTab) {
Tab);
}
+TEST_F(FormatTest, LinuxBraceBreaking) {
+ FormatStyle BreakBeforeBrace = getLLVMStyle();
+ BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Linux;
+ verifyFormat("namespace a\n"
+ "{\n"
+ "class A\n"
+ "{\n"
+ " void f()\n"
+ " {\n"
+ " if (true) {\n"
+ " a();\n"
+ " b();\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "}",
+ BreakBeforeBrace);
+}
+
+TEST_F(FormatTest, StroustrupBraceBreaking) {
+ FormatStyle BreakBeforeBrace = getLLVMStyle();
+ BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
+ verifyFormat("namespace a {\n"
+ "class A {\n"
+ " void f()\n"
+ " {\n"
+ " if (true) {\n"
+ " a();\n"
+ " b();\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "}",
+ BreakBeforeBrace);
+}
+
bool allStylesEqual(ArrayRef Styles) {
for (size_t i = 1; i < Styles.size(); ++i)
if (!(Styles[0] == Styles[i]))
@@ -4113,6 +4149,14 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE("BasedOnStyle: LLVM", ColumnLimit, BaseStyle.ColumnLimit);
CHECK_PARSE("BasedOnStyle: LLVM\nColumnLimit: 1234", ColumnLimit, 1234u);
+ Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
+ CHECK_PARSE("BreakBeforeBraces: Attach", BreakBeforeBraces,
+ FormatStyle::BS_Attach);
+ CHECK_PARSE("BreakBeforeBraces: Linux", BreakBeforeBraces,
+ FormatStyle::BS_Linux);
+ CHECK_PARSE("BreakBeforeBraces: Stroustrup", BreakBeforeBraces,
+ FormatStyle::BS_Stroustrup);
+
#undef CHECK_PARSE
#undef CHECK_PARSE_BOOL
}
--
cgit v1.2.3
From 967d9e935d2379ea00726dc51fac5feeca50a4d0 Mon Sep 17 00:00:00 2001
From: Manuel Klimek
Date: Mon, 13 May 2013 12:53:04 +0000
Subject: Fix style according to post-commit review comments.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181701 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/Format/WhitespaceManager.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 21e38b1e97..7ffebacba5 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -143,9 +143,9 @@ std::string WhitespaceManager::getNewLineText(unsigned NewLines,
}
std::string WhitespaceManager::getIndentText(unsigned Spaces) {
- if (!Style.UseTab) {
+ if (!Style.UseTab)
return std::string(Spaces, ' ');
- }
+
return std::string(Spaces / Style.IndentWidth, '\t') +
std::string(Spaces % Style.IndentWidth, ' ');
}
--
cgit v1.2.3
From 2b6acb69f04ac5339fd39a9c03a0f5d076d51ac3 Mon Sep 17 00:00:00 2001
From: Alexander Kornienko
Date: Mon, 13 May 2013 12:56:35 +0000
Subject: A better version of r181699: use raw_string_ostream.str() instead of
manually calling .flush().
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181702 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/Format/Format.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index b8c40cf263..384c4628bf 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -204,8 +204,7 @@ std::string configurationAsText(const FormatStyle &Style) {
// reference here.
FormatStyle NonConstStyle = Style;
Output << NonConstStyle;
- Stream.flush();
- return Text;
+ return Stream.str();
}
// Returns the length of everything up to the first possible line break after
--
cgit v1.2.3
From 77b502580d2d3a04ee0a83e9e22eb6b8d8be3ea6 Mon Sep 17 00:00:00 2001
From: Rafael Espindola
Date: Mon, 13 May 2013 14:05:53 +0000
Subject: Fix a gcc warning.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In r181677 I removed this llvm_unreachable and it introduced a gcc
warning. Add it back.
Thanks to Patrik Hägglund for noticing it.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181704 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/AST/ASTContext.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 9901080101..49e3639e93 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -7838,6 +7838,8 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
case TSK_ImplicitInstantiation:
return GVA_TemplateInstantiation;
}
+
+ llvm_unreachable("Invalid Linkage!");
}
bool ASTContext::DeclMustBeEmitted(const Decl *D) {
--
cgit v1.2.3
From 52a4693e1e3943465f52e702e1731340052d5f46 Mon Sep 17 00:00:00 2001
From: Ben Langmuir
Date: Mon, 13 May 2013 14:45:11 +0000
Subject: Fix test/CodeGenCXX/captured-statements.cpp on powerpc64
Generalize some attributes that differ on powerpc64 (i32 vs signext i32). Also
fix some copy-and-pasted code that didn't get updated properly.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181707 91177308-0d34-0410-b5e6-96231b3b80d8
---
test/CodeGenCXX/captured-statements.cpp | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/test/CodeGenCXX/captured-statements.cpp b/test/CodeGenCXX/captured-statements.cpp
index 91c7ff28f0..cfa6936111 100644
--- a/test/CodeGenCXX/captured-statements.cpp
+++ b/test/CodeGenCXX/captured-statements.cpp
@@ -55,9 +55,9 @@ void test2(int x) {
}();
// CHECK-2: define void @_Z5test2i
- // CHECK-2: call i32 @[[Lambda:["$\w]+]]
+ // CHECK-2: call {{.*}} @[[Lambda:["$\w]+]]
//
- // CHECK-2: define internal i32 @[[Lambda]]
+ // CHECK-2: define internal {{.*}} @[[Lambda]]
// CHECK-2: call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]*
//
// CHECK-2: define internal void @[[HelperName]]
@@ -74,7 +74,7 @@ void test3(int x) {
// CHECK-3: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* }
- // CHECK-3: define void @_Z5test3i(i32 %x)
+ // CHECK-3: define void @_Z5test3i
// CHECK-3: store i32*
// CHECK-3: call void @{{.*}}__captured_stmt
// CHECK-3: ret void
@@ -86,10 +86,7 @@ void test4() {
Foo f;
f.x = 5;
}
- // CHECK-4: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* }
-
- // CHECK-4: define void @_Z5test3i(i32 %x)
- // CHECK-4: store i32*
+ // CHECK-4: define void @_Z5test4v
// CHECK-4: call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]*
// CHECK-4: ret void
//
--
cgit v1.2.3
From fbff0c4510c7f0e0f30a005960e434b973f5bd21 Mon Sep 17 00:00:00 2001
From: Fariborz Jahanian
Date: Mon, 13 May 2013 17:27:00 +0000
Subject: Objective-C error recovery. This patch makes a quick recovery form
duplicate method definition error thus preventing doc parsing to loop trying
to find comment for the invalid redefinition in a previous declaration. //
rdar://13836387
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181710 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/AST/ASTContext.cpp | 2 ++
lib/Sema/SemaDeclObjC.cpp | 2 ++
test/Sema/warn-documentation.m | 21 +++++++++++++++++++++
3 files changed, 25 insertions(+)
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 49e3639e93..21a16a6d98 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -409,6 +409,8 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
comments::FullComment *ASTContext::getCommentForDecl(
const Decl *D,
const Preprocessor *PP) const {
+ if (D->isInvalidDecl())
+ return NULL;
D = adjustDeclToTemplate(D);
const Decl *Canonical = D->getCanonicalDecl();
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index f33e7bcb16..07610585c5 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -3052,6 +3052,8 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl)
<< ObjCMethod->getDeclName();
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
+ ObjCMethod->setInvalidDecl();
+ return ObjCMethod;
}
// If this Objective-C method does not have a related result type, but we
diff --git a/test/Sema/warn-documentation.m b/test/Sema/warn-documentation.m
index 14e0c347e3..2720480509 100644
--- a/test/Sema/warn-documentation.m
+++ b/test/Sema/warn-documentation.m
@@ -176,3 +176,24 @@ struct S;
// expected-warning@+1 {{unknown command tag name}}
/// \t bbb IS_DOXYGEN_END
int FooBar();
+
+// rdar://13836387
+/** \brief Module handling the incoming notifications from the system.
+ *
+ * This includes:
+ * - Network Reachability
+ * - Power State
+ * - Low Disk
+ */
+@interface BRC : NSObject
+- (void)removeReach:(NSObject*)observer;
+@end
+
+@implementation BRC : NSObject
+- (void)removeReach:(NSObject*)observer // expected-note {{previous declaration is here}}
+{
+}
+- (void)removeReach:(NSObject*)observer // expected-error {{duplicate declaration of method 'removeReach:'}}
+{
+}
+@end
--
cgit v1.2.3
From 620c0afe5ea7185688d066de9e3b3680067934d3 Mon Sep 17 00:00:00 2001
From: Rafael Espindola
Date: Mon, 13 May 2013 20:09:47 +0000
Subject: Use atomic instructions on ARM linux.
This is safe given how the pre-v6 atomic ops funcions in libgcc are
implemented.
This fixes pr15429.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181728 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/Basic/Targets.cpp | 17 ++++++++++++++++-
test/CodeGen/linux-arm-atomic.c | 10 ++++++++++
2 files changed, 26 insertions(+), 1 deletion(-)
create mode 100644 test/CodeGen/linux-arm-atomic.c
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 96b12bac1f..841ca62ab6 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -3527,6 +3527,20 @@ class ARMTargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
+ static bool shouldUseInlineAtomic(const llvm::Triple &T) {
+ // On linux, binaries targeting old cpus call functions in libgcc to
+ // perform atomic operations. The implementation in libgcc then calls into
+ // the kernel which on armv6 and newer uses ldrex and strex. The net result
+ // is that if we assume the kernel is at least as recent as the hardware,
+ // it is safe to use atomic instructions on armv6 and newer.
+ if (T.getOS() != llvm::Triple::Linux)
+ return false;
+ StringRef ArchName = T.getArchName();
+ if (ArchName.startswith("armv6") || ArchName.startswith("armv7"))
+ return true;
+ return false;
+ }
+
public:
ARMTargetInfo(const std::string &TripleStr)
: TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s"), IsAAPCS(true)
@@ -3559,8 +3573,9 @@ public:
TheCXXABI.set(TargetCXXABI::GenericARM);
// ARM has atomics up to 8 bytes
- // FIXME: Set MaxAtomicInlineWidth if we have the feature v6e
MaxAtomicPromoteWidth = 64;
+ if (shouldUseInlineAtomic(getTriple()))
+ MaxAtomicInlineWidth = 64;
// Do force alignment of members that follow zero length bitfields. If
// the alignment of the zero-length bitfield is greater than the member
diff --git a/test/CodeGen/linux-arm-atomic.c b/test/CodeGen/linux-arm-atomic.c
new file mode 100644
index 0000000000..3fda7f688c
--- /dev/null
+++ b/test/CodeGen/linux-arm-atomic.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-linux | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv6-unknown-linux | FileCheck %s
+
+typedef int _Atomic_word;
+_Atomic_word exchange_and_add(volatile _Atomic_word *__mem, int __val) {
+ return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL);
+}
+
+// CHECK: define {{.*}} @exchange_and_add
+// CHECK: atomicrmw {{.*}} add
--
cgit v1.2.3
From 7e17fdc617ee9db8270f3f6fb4ecd392fed47d80 Mon Sep 17 00:00:00 2001
From: Richard Smith
Date: Mon, 13 May 2013 20:28:15 +0000
Subject: Fix a wrong and confusing comment in CharUnits.h. Neither C nor C++
allows bytes and character units to be different sizes.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181730 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/AST/CharUnits.h | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index 082c672c21..09ff6828ef 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -19,21 +19,20 @@
#include "llvm/Support/MathExtras.h"
namespace clang {
-
+
/// CharUnits - This is an opaque type for sizes expressed in character units.
- /// Instances of this type represent a quantity as a multiple of the size
+ /// Instances of this type represent a quantity as a multiple of the size
/// of the standard C type, char, on the target architecture. As an opaque
/// type, CharUnits protects you from accidentally combining operations on
- /// quantities in bit units and character units.
+ /// quantities in bit units and character units.
+ ///
+ /// In both C and C++, an object of type 'char', 'signed char', or 'unsigned
+ /// char' occupies exactly one byte, so 'character unit' and 'byte' refer to
+ /// the same quantity of storage. However, we use the term 'character unit'
+ /// rather than 'byte' to avoid an implication that a character unit is
+ /// exactly 8 bits.
///
- /// It should be noted that characters and bytes are distinct concepts. Bytes
- /// refer to addressable units of data storage on the target machine, and
- /// characters are members of a set of elements used for the organization,
- /// control, or representation of data. According to C99, bytes are allowed
- /// to exceed characters in size, although currently, clang only supports
- /// architectures where the two are the same size.
- ///
- /// For portability, never assume that a target character is 8 bits wide. Use
+ /// For portability, never assume that a target character is 8 bits wide. Use
/// CharUnit values wherever you calculate sizes, offsets, or alignments
/// in character units.
class CharUnits {
--
cgit v1.2.3
From 1071b9f2d38f8177e54f20412a36450462c19186 Mon Sep 17 00:00:00 2001
From: Richard Smith
Date: Mon, 13 May 2013 20:33:30 +0000
Subject: Suppress GCC warning for no return after covered switch, and remove
some debugging code from an unreachable codepath.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181731 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/AST/ExprConstant.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 339e78bbe9..0f44985471 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -2869,10 +2869,9 @@ static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info,
case ESR_Returned:
return ESR;
case ESR_CaseNotFound:
- Found->dump();
- SS->getBody()->dump();
llvm_unreachable("couldn't find switch case");
}
+ llvm_unreachable("Invalid EvalStmtResult!");
}
// Evaluate a statement.
--
cgit v1.2.3
From 27c7f54cf7d18276be2979d5c795533cc5592675 Mon Sep 17 00:00:00 2001
From: Daniel Jasper
Date: Mon, 13 May 2013 20:50:15 +0000
Subject: Align a multiline string literal with the first part.
Before:
#define A(X) \
"aaaaa" #X "bbbbbb" \
"ccccc"
After:
#define A(X) \
"aaaaa" #X "bbbbbb" \
"ccccc"
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181732 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/Format/Format.cpp | 6 +++---
unittests/Format/FormatTest.cpp | 8 ++++++++
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 384c4628bf..50567a6f84 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -738,10 +738,10 @@ private:
State.Stack.back().VariablePos = VariablePos;
}
- if (Current.is(tok::string_literal)) {
+ if (Current.is(tok::string_literal) && State.StartOfStringLiteral == 0) {
State.StartOfStringLiteral = State.Column;
- } else if (Current.isNot(tok::comment)) {
- State.StartOfStringLiteral = 0;
+ } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash,
+ tok::string_literal)) {
}
State.Column += Current.FormatTok.TokenLength;
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 9624ac9224..697cc53820 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -2231,6 +2231,14 @@ TEST_F(FormatTest, AlignsStringLiterals) {
"#define LL_FORMAT \"ll\"\n"
"printf(\"aaaaa: %d, bbbbbb: %\" LL_FORMAT \"d, cccccccc: %\" LL_FORMAT\n"
" \"d, ddddddddd: %\" LL_FORMAT \"d\");");
+
+ verifyFormat("#define A(X) \\\n"
+ " \"aaaaa\" #X \"bbbbbb\" \\\n"
+ " \"ccccc\"",
+ getLLVMStyleWithColumns(23));
+ verifyFormat("#define A \"def\"\n"
+ "f(\"abc\" A \"ghi\"\n"
+ " \"jkl\");");
}
TEST_F(FormatTest, AlignsPipes) {
--
cgit v1.2.3
From b834a78f9b79cb71b093ebbbb381b92f9d4bbf3b Mon Sep 17 00:00:00 2001
From: Anna Zaks
Date: Mon, 13 May 2013 21:48:20 +0000
Subject: [analyzer] Warn about nil elements/keys/values in array and
dictionary literals.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181738 91177308-0d34-0410-b5e6-96231b3b80d8
---
.../Checkers/BasicObjCFoundationChecks.cpp | 95 +++++++++++++++++-----
test/Analysis/NSContainers.m | 33 ++++++++
2 files changed, 109 insertions(+), 19 deletions(-)
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 6388a8df64..c723e4f29b 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -90,20 +90,53 @@ static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
//===----------------------------------------------------------------------===//
namespace {
- class NilArgChecker : public Checker {
+ class NilArgChecker : public Checker,
+ check::PostStmt > {
mutable OwningPtr BT;
- void WarnIfNilArg(CheckerContext &C,
- const ObjCMethodCall &msg, unsigned Arg,
- FoundationClass Class,
- bool CanBeSubscript = false) const;
+ void warnIfNilExpr(const Expr *E,
+ const char *Msg,
+ CheckerContext &C) const;
+
+ void warnIfNilArg(CheckerContext &C,
+ const ObjCMethodCall &msg, unsigned Arg,
+ FoundationClass Class,
+ bool CanBeSubscript = false) const;
+
+ void generateBugReport(ExplodedNode *N,
+ llvm::raw_svector_ostream &os,
+ SourceRange Range,
+ const Expr *Expr,
+ CheckerContext &C) const;
public:
void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
+ void checkPostStmt(const ObjCDictionaryLiteral *DL,
+ CheckerContext &C) const;
+ void checkPostStmt(const ObjCArrayLiteral *AL,
+ CheckerContext &C) const;
};
}
-void NilArgChecker::WarnIfNilArg(CheckerContext &C,
+void NilArgChecker::warnIfNilExpr(const Expr *E,
+ const char *Msg,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SVal SV = State->getSVal(E, C.getLocationContext());
+ if (State->isNull(SV).isConstrainedTrue()) {
+
+ if (ExplodedNode *N = C.generateSink()) {
+ SmallString<128> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+ os << Msg;
+ generateBugReport(N, os, E->getSourceRange(), E, C);
+ }
+
+ }
+}
+
+void NilArgChecker::warnIfNilArg(CheckerContext &C,
const ObjCMethodCall &msg,
unsigned int Arg,
FoundationClass Class,
@@ -113,9 +146,6 @@ void NilArgChecker::WarnIfNilArg(CheckerContext &C,
if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
return;
- if (!BT)
- BT.reset(new APIMisuse("nil argument"));
-
if (ExplodedNode *N = C.generateSink()) {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
@@ -149,14 +179,26 @@ void NilArgChecker::WarnIfNilArg(CheckerContext &C,
<< msg.getSelector().getAsString() << "' cannot be nil";
}
}
-
- BugReport *R = new BugReport(*BT, os.str(), N);
- R->addRange(msg.getArgSourceRange(Arg));
- bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R);
- C.emitReport(R);
+
+ generateBugReport(N, os, msg.getArgSourceRange(Arg),
+ msg.getArgExpr(Arg), C);
}
}
+void NilArgChecker::generateBugReport(ExplodedNode *N,
+ llvm::raw_svector_ostream &os,
+ SourceRange Range,
+ const Expr *Expr,
+ CheckerContext &C) const {
+ if (!BT)
+ BT.reset(new APIMisuse("nil argument"));
+
+ BugReport *R = new BugReport(*BT, os.str(), N);
+ R->addRange(Range);
+ bugreporter::trackNullOrUndefValue(N, Expr, *R);
+ C.emitReport(R);
+}
+
void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
@@ -225,28 +267,43 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
S.getNameForSlot(1).equals("forKey")) {
Arg = 0;
- WarnIfNilArg(C, msg, /* Arg */1, Class);
+ warnIfNilArg(C, msg, /* Arg */1, Class);
} else if (S.getNameForSlot(0).equals("setObject") &&
S.getNameForSlot(1).equals("forKey")) {
Arg = 0;
- WarnIfNilArg(C, msg, /* Arg */1, Class);
+ warnIfNilArg(C, msg, /* Arg */1, Class);
} else if (S.getNameForSlot(0).equals("setObject") &&
S.getNameForSlot(1).equals("forKeyedSubscript")) {
CanBeSubscript = true;
Arg = 0;
- WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
+ warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
} else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
Arg = 0;
}
}
-
// If argument is '0', report a warning.
if ((Arg != InvalidArgIndex))
- WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
+ warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
}
+void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
+ CheckerContext &C) const {
+ for (unsigned i = 0; i < AL->getNumElements(); ++i) {
+ warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
+ }
+}
+
+void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
+ CheckerContext &C) const {
+ for (unsigned i = 0; i < DL->getNumElements(); ++i) {
+ ObjCDictionaryElement Element = DL->getKeyValueElement(i);
+ warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
+ warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
+ }
+}
+
//===----------------------------------------------------------------------===//
// Error reporting.
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/NSContainers.m b/test/Analysis/NSContainers.m
index 6b4089b3e5..959f367d28 100644
--- a/test/Analysis/NSContainers.m
+++ b/test/Analysis/NSContainers.m
@@ -36,6 +36,10 @@ typedef struct _NSZone NSZone;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx __attribute__((availability(macosx,introduced=10.8)));
@end
+@interface NSArray (NSArrayCreation)
++ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+@end
+
@interface NSMutableArray : NSArray
- (void)addObject:(id)anObject;
@@ -58,6 +62,8 @@ typedef struct _NSZone NSZone;
+ (id)dictionary;
+ (id)dictionaryWithObject:(id)object forKey:(id )key;
++ (instancetype)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(NSUInteger)cnt;
+
@end
@interface NSMutableDictionary : NSDictionary
@@ -147,6 +153,33 @@ NSDictionary *testNilArgNSDictionary2(NSObject *obj) {
return [NSDictionary dictionaryWithObject:obj forKey:0]; // expected-warning {{Key argument to 'dictionaryWithObject:forKey:' cannot be nil}}
}
+id testCreateDictionaryLiteralKey(id value, id nilKey) {
+ if (nilKey)
+ ;
+ return @{@"abc":value, nilKey:@"abc"}; // expected-warning {{Dictionary key cannot be nil}}
+}
+
+id testCreateDictionaryLiteralValue(id nilValue) {
+ if (nilValue)
+ ;
+ return @{@"abc":nilValue}; // expected-warning {{Dictionary value cannot be nil}}
+}
+
+id testCreateDictionaryLiteral(id nilValue, id nilKey) {
+ if (nilValue)
+ ;
+ if (nilKey)
+ ;
+ return @{@"abc":nilValue, nilKey:@"abc"}; // expected-warning {{Dictionary key cannot be nil}}
+ // expected-warning@-1 {{Dictionary value cannot be nil}}
+}
+
+id testCreateArrayLiteral(id myNil) {
+ if (myNil)
+ ;
+ return @[ @"a", myNil, @"c" ]; // expected-warning {{Array element cannot be nil}}
+}
+
// Test inline defensive checks suppression.
void idc(id x) {
if (x)
--
cgit v1.2.3
From ef202c35b37c137e32fe30f4453915b6d3b525d7 Mon Sep 17 00:00:00 2001
From: Anna Zaks
Date: Mon, 13 May 2013 23:49:51 +0000
Subject: =?UTF-8?q?[analyzer]=20Refactor:=20address=20Jordan=E2=80=99s=20c?=
=?UTF-8?q?ode=20review=20of=20r181738.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
(Modifying the checker to record that the values are no longer nil will be done separately.)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181744 91177308-0d34-0410-b5e6-96231b3b80d8
---
.../Checkers/BasicObjCFoundationChecks.cpp | 26 +-
test/Analysis/inlining/path-notes.m | 492 +++++++++++++++------
2 files changed, 375 insertions(+), 143 deletions(-)
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index c723e4f29b..ba779ff191 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -105,7 +105,7 @@ namespace {
bool CanBeSubscript = false) const;
void generateBugReport(ExplodedNode *N,
- llvm::raw_svector_ostream &os,
+ StringRef Msg,
SourceRange Range,
const Expr *Expr,
CheckerContext &C) const;
@@ -123,14 +123,10 @@ void NilArgChecker::warnIfNilExpr(const Expr *E,
const char *Msg,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
- SVal SV = State->getSVal(E, C.getLocationContext());
- if (State->isNull(SV).isConstrainedTrue()) {
+ if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
if (ExplodedNode *N = C.generateSink()) {
- SmallString<128> sbuf;
- llvm::raw_svector_ostream os(sbuf);
- os << Msg;
- generateBugReport(N, os, E->getSourceRange(), E, C);
+ generateBugReport(N, Msg, E->getSourceRange(), E, C);
}
}
@@ -180,22 +176,22 @@ void NilArgChecker::warnIfNilArg(CheckerContext &C,
}
}
- generateBugReport(N, os, msg.getArgSourceRange(Arg),
+ generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
msg.getArgExpr(Arg), C);
}
}
void NilArgChecker::generateBugReport(ExplodedNode *N,
- llvm::raw_svector_ostream &os,
+ StringRef Msg,
SourceRange Range,
- const Expr *Expr,
+ const Expr *E,
CheckerContext &C) const {
if (!BT)
BT.reset(new APIMisuse("nil argument"));
- BugReport *R = new BugReport(*BT, os.str(), N);
+ BugReport *R = new BugReport(*BT, Msg, N);
R->addRange(Range);
- bugreporter::trackNullOrUndefValue(N, Expr, *R);
+ bugreporter::trackNullOrUndefValue(N, E, *R);
C.emitReport(R);
}
@@ -290,14 +286,16 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
CheckerContext &C) const {
- for (unsigned i = 0; i < AL->getNumElements(); ++i) {
+ unsigned NumOfElements = AL->getNumElements();
+ for (unsigned i = 0; i < NumOfElements; ++i) {
warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
}
}
void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
CheckerContext &C) const {
- for (unsigned i = 0; i < DL->getNumElements(); ++i) {
+ unsigned NumOfElements = DL->getNumElements();
+ for (unsigned i = 0; i < NumOfElements; ++i) {
ObjCDictionaryElement Element = DL->getKeyValueElement(i);
warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
diff --git a/test/Analysis/inlining/path-notes.m b/test/Analysis/inlining/path-notes.m
index 74f088a382..602bad188a 100644
--- a/test/Analysis/inlining/path-notes.m
+++ b/test/Analysis/inlining/path-notes.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config suppress-null-return-paths=false -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -fblocks %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg -analyzer-output=text -analyzer-config suppress-null-return-paths=false -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -fblocks %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
typedef struct dispatch_queue_s *dispatch_queue_t;
@@ -11,6 +11,57 @@ void dispatch_sync(dispatch_queue_t, dispatch_block_t);
@property int *p;
@end
+typedef unsigned long NSUInteger;
+typedef signed char BOOL;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@protocol NSFastEnumeration
+@end
+@protocol NSSecureCoding
+@required
++ (BOOL)supportsSecureCoding;
+@end
+@interface NSObject {}
+- (id)init;
++ (id)alloc;
+@end
+@interface NSArray : NSObject
+
+- (NSUInteger)count;
+- (id)objectAtIndex:(NSUInteger)index;
+
+@end
+
+@interface NSArray (NSExtendedArray)
+- (NSArray *)arrayByAddingObject:(id)anObject;
+- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx __attribute__((availability(macosx,introduced=10.8)));
+@end
+
+@interface NSArray (NSArrayCreation)
++ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+@end
+
+@interface NSMutableArray : NSArray
+
+- (void)addObject:(id)anObject;
+- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
+- (void)removeLastObject;
+- (void)removeObjectAtIndex:(NSUInteger)index;
+- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
+
+@end
+
int *getZeroIfNil(Test *x) {
return x.p;
// expected-note@-1 {{'p' not called because the receiver is nil}}
@@ -89,6 +140,12 @@ void testNilReceiver(id *x) {
// expected-note@-3 {{Calling 'testNilReceiverHelper'}}
}
+id testCreateArrayLiteral(id myNil) {
+ if (myNil) // expected-note {{Assuming 'myNil' is nil}}
+ ; // expected-note@-1 {{Taking false branch}}
+ return @[ @"a", myNil, @"c" ]; // expected-warning {{Array element cannot be nil}}
+ //expected-note@-1 {{Array element cannot be nil}}
+}
// CHECK: diagnostics
// CHECK-NEXT:
@@ -103,12 +160,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -116,12 +173,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col17
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col17
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -133,7 +190,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col17
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -141,12 +198,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col17
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col17
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -166,12 +223,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col17
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col17
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -179,12 +236,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col15
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -196,7 +253,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -204,12 +261,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col18
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -225,7 +282,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line14
+// CHECK-NEXT: line65
// CHECK-NEXT: col1
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -243,12 +300,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line14
+// CHECK-NEXT: line65
// CHECK-NEXT: col1
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line14
+// CHECK-NEXT: line65
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -256,12 +313,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col8
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -277,12 +334,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col8
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -290,12 +347,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col10
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col10
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -307,7 +364,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col10
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -315,12 +372,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col10
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col10
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -340,12 +397,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col10
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col10
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -353,12 +410,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col8
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -370,7 +427,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -378,12 +435,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line15
+// CHECK-NEXT: line66
// CHECK-NEXT: col12
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -399,7 +456,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -407,12 +464,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col18
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -432,12 +489,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col15
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -445,12 +502,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col20
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col20
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -462,7 +519,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col20
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -470,12 +527,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col22
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -496,7 +553,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: issue_hash1
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line21
+// CHECK-NEXT: line72
// CHECK-NEXT: col20
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -512,12 +569,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line30
+// CHECK-NEXT: line81
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line30
+// CHECK-NEXT: line81
// CHECK-NEXT: col8
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -525,12 +582,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col15
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -542,7 +599,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -550,12 +607,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line41
+// CHECK-NEXT: line92
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -599,7 +656,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col30
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -617,12 +674,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col30
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col30
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -630,12 +687,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line38
+// CHECK-NEXT: line89
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line38
+// CHECK-NEXT: line89
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -647,7 +704,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line38
+// CHECK-NEXT: line89
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -655,12 +712,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line38
+// CHECK-NEXT: line89
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line38
+// CHECK-NEXT: line89
// CHECK-NEXT: col9
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -690,7 +747,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -698,12 +755,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line41
+// CHECK-NEXT: line92
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -723,12 +780,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line36
+// CHECK-NEXT: line87
// CHECK-NEXT: col15
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -736,12 +793,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line43
+// CHECK-NEXT: line94
// CHECK-NEXT: col12
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line43
+// CHECK-NEXT: line94
// CHECK-NEXT: col12
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -753,7 +810,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line43
+// CHECK-NEXT: line94
// CHECK-NEXT: col12
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -761,12 +818,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line43
+// CHECK-NEXT: line94
// CHECK-NEXT: col10
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line43
+// CHECK-NEXT: line94
// CHECK-NEXT: col14
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -787,7 +844,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: issue_hash14
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line43
+// CHECK-NEXT: line94
// CHECK-NEXT: col12
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -803,12 +860,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line51
+// CHECK-NEXT: line102
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line51
+// CHECK-NEXT: line102
// CHECK-NEXT: col8
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -816,12 +873,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line56
+// CHECK-NEXT: line107
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line56
+// CHECK-NEXT: line107
// CHECK-NEXT: col15
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -833,7 +890,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line56
+// CHECK-NEXT: line107
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -841,12 +898,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line56
+// CHECK-NEXT: line107
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line62
+// CHECK-NEXT: line113
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -890,7 +947,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line56
+// CHECK-NEXT: line107
// CHECK-NEXT: col30
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -908,12 +965,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line56
+// CHECK-NEXT: line107
// CHECK-NEXT: col30
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line56
+// CHECK-NEXT: line107
// CHECK-NEXT: col30
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -921,12 +978,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line58
+// CHECK-NEXT: line109
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line58
+// CHECK-NEXT: line109
// CHECK-NEXT: col7
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -938,7 +995,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line58
+// CHECK-NEXT: line109
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -946,12 +1003,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line58
+// CHECK-NEXT: line109
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line58
+// CHECK-NEXT: line109
// CHECK-NEXT: col9
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -971,12 +1028,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line58
+// CHECK-NEXT: line109
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line58
+// CHECK-NEXT: line109
// CHECK-NEXT: col7
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -984,12 +1041,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line60
+// CHECK-NEXT: line111
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line60
+// CHECK-NEXT: line111
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1001,7 +1058,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line60
+// CHECK-NEXT: line111
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1009,12 +1066,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line60
+// CHECK-NEXT: line111
// CHECK-NEXT: col12
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line60
+// CHECK-NEXT: line111
// CHECK-NEXT: col12
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1032,7 +1089,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: typeuninitialized variable captured by block
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line60
+// CHECK-NEXT: line111
// CHECK-NEXT: col5
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1048,12 +1105,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line82
+// CHECK-NEXT: line133
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line82
+// CHECK-NEXT: line133
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1061,12 +1118,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col23
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1082,12 +1139,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col23
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1095,12 +1152,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col26
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col26
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1112,7 +1169,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col26
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1120,12 +1177,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col26
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col27
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1145,12 +1202,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col26
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col26
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1158,12 +1215,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col25
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col25
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1175,7 +1232,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col25
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1183,12 +1240,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col25
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col35
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1204,7 +1261,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1212,12 +1269,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line86
+// CHECK-NEXT: line137
// CHECK-NEXT: col36
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1233,7 +1290,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line76
+// CHECK-NEXT: line127
// CHECK-NEXT: col1
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1251,12 +1308,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line76
+// CHECK-NEXT: line127
// CHECK-NEXT: col1
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line76
+// CHECK-NEXT: line127
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1264,12 +1321,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line77
+// CHECK-NEXT: line128
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line77
+// CHECK-NEXT: line128
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1285,12 +1342,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: start
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line77
+// CHECK-NEXT: line128
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line77
+// CHECK-NEXT: line128
// CHECK-NEXT: col3
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1298,12 +1355,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: end
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line77
+// CHECK-NEXT: line128
// CHECK-NEXT: col6
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line77
+// CHECK-NEXT: line128
// CHECK-NEXT: col6
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1315,7 +1372,7 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: kindevent
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line77
+// CHECK-NEXT: line128
// CHECK-NEXT: col6
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1323,12 +1380,12 @@ void testNilReceiver(id *x) {
// CHECK-NEXT:
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line77
+// CHECK-NEXT: line128
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
-// CHECK-NEXT: line77
+// CHECK-NEXT: line128
// CHECK-NEXT: col4
// CHECK-NEXT: file0
// CHECK-NEXT:
@@ -1349,9 +1406,186 @@ void testNilReceiver(id *x) {
// CHECK-NEXT: issue_hash1
// CHECK-NEXT: location
// CHECK-NEXT:
-// CHECK-NEXT: line77
+// CHECK-NEXT: line128
// CHECK-NEXT: col6
// CHECK-NEXT: file0
// CHECK-NEXT:
// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: path
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: kindcontrol
+// CHECK-NEXT: edges
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line144
+// CHECK-NEXT: col3
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line144
+// CHECK-NEXT: col4
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: end
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line144
+// CHECK-NEXT: col7
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line144
+// CHECK-NEXT: col11
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: kindevent
+// CHECK-NEXT: location
+// CHECK-NEXT:
+// CHECK-NEXT: line144
+// CHECK-NEXT: col7
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT: ranges
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line144
+// CHECK-NEXT: col7
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line144
+// CHECK-NEXT: col11
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: depth0
+// CHECK-NEXT: extended_message
+// CHECK-NEXT: Assuming 'myNil' is nil
+// CHECK-NEXT: message
+// CHECK-NEXT: Assuming 'myNil' is nil
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: kindcontrol
+// CHECK-NEXT: edges
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line144
+// CHECK-NEXT: col7
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line144
+// CHECK-NEXT: col11
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: end
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line146
+// CHECK-NEXT: col3
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line146
+// CHECK-NEXT: col8
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: kindcontrol
+// CHECK-NEXT: edges
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line146
+// CHECK-NEXT: col3
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line146
+// CHECK-NEXT: col8
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: end
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line146
+// CHECK-NEXT: col10
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line146
+// CHECK-NEXT: col10
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: kindevent
+// CHECK-NEXT: location
+// CHECK-NEXT:
+// CHECK-NEXT: line146
+// CHECK-NEXT: col10
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT: ranges
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line146
+// CHECK-NEXT: col19
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: line146
+// CHECK-NEXT: col23
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: depth0
+// CHECK-NEXT: extended_message
+// CHECK-NEXT: Array element cannot be nil
+// CHECK-NEXT: message
+// CHECK-NEXT: Array element cannot be nil
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: descriptionArray element cannot be nil
+// CHECK-NEXT: categoryAPI Misuse (Apple)
+// CHECK-NEXT: typenil argument
+// CHECK-NEXT: issue_context_kindfunction
+// CHECK-NEXT: issue_contexttestCreateArrayLiteral
+// CHECK-NEXT: issue_hash3
+// CHECK-NEXT: location
+// CHECK-NEXT:
+// CHECK-NEXT: line146
+// CHECK-NEXT: col10
+// CHECK-NEXT: file0
+// CHECK-NEXT:
+// CHECK-NEXT:
// CHECK-NEXT:
--
cgit v1.2.3
From 7be62a87abf60d4c13ab60ee8fb896aebac188a8 Mon Sep 17 00:00:00 2001
From: David Blaikie
Date: Tue, 14 May 2013 00:34:20 +0000
Subject: PR15956: Debug Info: Include the appropriate file location in types
created due to using declarations
We might benefit from API refactoring here (why pass in a value that's
derived from another parameter?) but this is the immediate issue.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181747 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/CodeGen/CGDebugInfo.cpp | 6 ++++--
test/CodeGenCXX/debug-info-namespace.cpp | 27 ++++++++++++++++-----------
2 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 583b23980e..f6ad8f2cc5 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -2178,8 +2178,10 @@ llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
// we would otherwise do to get a type for a pointee. (forward declarations in
// limited debug info, full definitions (if the type definition is available)
// in unlimited debug info)
- if (const TypeDecl *RD = dyn_cast(D))
- return CreatePointeeType(QualType(RD->getTypeForDecl(), 0), llvm::DIFile());
+ if (const TypeDecl *TD = dyn_cast(D)) {
+ llvm::DIFile DefUnit = getOrCreateFile(TD->getLocation());
+ return CreatePointeeType(CGM.getContext().getTypeDeclType(TD), DefUnit);
+ }
// Otherwise fall back to a fairly rudimentary cache of existing declarations.
// This doesn't handle providing declarations (for functions or variables) for
// entities without definitions in this TU, nor when the definition proceeds
diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp
index 4b44661eb1..9eff818f87 100644
--- a/test/CodeGenCXX/debug-info-namespace.cpp
+++ b/test/CodeGenCXX/debug-info-namespace.cpp
@@ -8,6 +8,7 @@ void f1() { }
void f1(int) { }
struct foo;
struct bar { };
+typedef bar baz;
}
using namespace B;
}
@@ -24,6 +25,7 @@ int func(bool b) {
using B::bar;
using B::f1;
using B::i;
+ using B::baz;
bar x;
return i;
}
@@ -33,24 +35,27 @@ int func(bool b) {
// CHECK: [[CU:![0-9]*]] = {{.*}}[[MODULES:![0-9]*]], metadata !""} ; [ DW_TAG_compile_unit ]
// CHECK: [[FILE:![0-9]*]] {{.*}}debug-info-namespace.cpp"
+// CHECK: [[FOOCPP:![0-9]*]] = metadata !{metadata !"foo.cpp", {{.*}}
// CHECK: [[NS:![0-9]*]] = {{.*}}, metadata [[FILE2:![0-9]*]], metadata [[CTXT:![0-9]*]], {{.*}} ; [ DW_TAG_namespace ] [B] [line 1]
// CHECK: [[CTXT]] = {{.*}}, metadata [[FILE]], null, {{.*}} ; [ DW_TAG_namespace ] [A] [line 3]
// CHECK: [[F1:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 4] [def] [f1]
-// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 13] [def] [func]
+// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 14] [def] [func]
// CHECK: [[FILE2]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp]
// CHECK: [[I:![0-9]*]] = {{.*}}, metadata [[NS]], metadata !"i", {{.*}} ; [ DW_TAG_variable ] [i]
-// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]], metadata [[M5:![0-9]*]], metadata [[M6:![0-9]*]], metadata [[M7:![0-9]*]], metadata [[M8:![0-9]*]]}
-// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 8} ; [ DW_TAG_imported_module ]
-// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 11} ; [ DW_TAG_imported_module ]
-// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX:![0-9]*]], metadata [[NS]], i32 15} ; [ DW_TAG_imported_module ]
-// CHECK: [[LEX]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 14, i32 0, i32 0} ; [ DW_TAG_lexical_block ]
-// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 18} ; [ DW_TAG_imported_module ]
-// CHECK: [[M5]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[FOO:![0-9]*]], i32 19} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]], metadata [[M5:![0-9]*]], metadata [[M6:![0-9]*]], metadata [[M7:![0-9]*]], metadata [[M8:![0-9]*]], metadata [[M9:![0-9]*]]}
+// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 9} ; [ DW_TAG_imported_module ]
+// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 12} ; [ DW_TAG_imported_module ]
+// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX:![0-9]*]], metadata [[NS]], i32 16} ; [ DW_TAG_imported_module ]
+// CHECK: [[LEX]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 15, i32 0, i32 0} ; [ DW_TAG_lexical_block ]
+// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 19} ; [ DW_TAG_imported_module ]
+// CHECK: [[M5]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[FOO:![0-9]*]], i32 20} ; [ DW_TAG_imported_declaration ]
// CHECK: [[FOO]] {{.*}} ; [ DW_TAG_structure_type ] [foo] [line 5, size 0, align 0, offset 0] [fwd] [from ]
-// CHECK: [[M6]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAR:![0-9]*]], i32 20} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M6]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAR:![0-9]*]], i32 21} ; [ DW_TAG_imported_declaration ]
// CHECK: [[BAR]] {{.*}} ; [ DW_TAG_structure_type ] [bar] [line 6, {{.*}}] [from ]
-// CHECK: [[M7]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[F1]], i32 21} ; [ DW_TAG_imported_declaration ]
-// CHECK: [[M8]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[I]], i32 22} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M7]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[F1]], i32 22} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M8]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[I]], i32 23} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M9]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAZ:![0-9]*]], i32 24} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[BAZ]] = metadata !{i32 {{[0-9]*}}, metadata [[FOOCPP]], metadata [[NS]], {{.*}} ; [ DW_TAG_typedef ] [baz] {{.*}} [from bar]
// FIXME: It is confused on win32 to generate file entry when dosish filename is given.
// REQUIRES: shell
--
cgit v1.2.3
From 69db555a7a4d0aa11d65001ffc25669c354a5de0 Mon Sep 17 00:00:00 2001
From: Rafael Espindola
Date: Tue, 14 May 2013 00:44:24 +0000
Subject: Use atomic instructions on linux thumb v7.
This matches gcc's behaviour. The patch also explicitly parses the version so
that this keeps working when we add support for v8.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181750 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/Basic/Targets.cpp | 20 +++++++++++++++++---
test/CodeGen/linux-arm-atomic.c | 1 +
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 841ca62ab6..a622a11aa5 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -3536,9 +3536,23 @@ class ARMTargetInfo : public TargetInfo {
if (T.getOS() != llvm::Triple::Linux)
return false;
StringRef ArchName = T.getArchName();
- if (ArchName.startswith("armv6") || ArchName.startswith("armv7"))
- return true;
- return false;
+ if (T.getArch() == llvm::Triple::arm) {
+ if (!ArchName.startswith("armv"))
+ return false;
+ StringRef VersionStr = ArchName.substr(4);
+ unsigned Version;
+ if (VersionStr.getAsInteger(10, Version))
+ return false;
+ return Version >= 6;
+ }
+ assert(T.getArch() == llvm::Triple::thumb);
+ if (!ArchName.startswith("thumbv"))
+ return false;
+ StringRef VersionStr = ArchName.substr(6);
+ unsigned Version;
+ if (VersionStr.getAsInteger(10, Version))
+ return false;
+ return Version >= 7;
}
public:
diff --git a/test/CodeGen/linux-arm-atomic.c b/test/CodeGen/linux-arm-atomic.c
index 3fda7f688c..c7ce1d228b 100644
--- a/test/CodeGen/linux-arm-atomic.c
+++ b/test/CodeGen/linux-arm-atomic.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-linux | FileCheck %s
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv6-unknown-linux | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-unknown-linux | FileCheck %s
typedef int _Atomic_word;
_Atomic_word exchange_and_add(volatile _Atomic_word *__mem, int __val) {
--
cgit v1.2.3
From f039e3eb0ffa87aae0e38cec48f367ee179b4de6 Mon Sep 17 00:00:00 2001
From: Richard Smith
Date: Tue, 14 May 2013 05:18:44 +0000
Subject: Suppress bogus "use of undefined constexpr function" error if the
function body was erroneous and got discarded.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181758 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/AST/ExprConstant.cpp | 5 +++++
test/SemaCXX/constant-expression-cxx11.cpp | 8 ++++++++
test/SemaCXX/enum-unscoped-nonexistent.cpp | 4 ++--
3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 0f44985471..2a3efb225b 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -3161,6 +3161,11 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
Declaration->isConstexpr())
return false;
+ // Bail out with no diagnostic if the function declaration itself is invalid.
+ // We will have produced a relevant diagnostic while parsing it.
+ if (Declaration->isInvalidDecl())
+ return false;
+
// Can we evaluate this function call?
if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
return true;
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 09a9cb5dd8..97b0b91b99 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1503,3 +1503,11 @@ namespace PR15884 {
// expected-note@-3 {{pointer to temporary is not a constant expression}}
// expected-note@-4 {{temporary created here}}
}
+
+namespace AfterError {
+ // FIXME: Suppress the 'no return statements' diagnostic if the body is invalid.
+ constexpr int error() { // expected-error {{no return statement}}
+ return foobar; // expected-error {{undeclared identifier}}
+ }
+ constexpr int k = error(); // expected-error {{must be initialized by a constant expression}}
+}
diff --git a/test/SemaCXX/enum-unscoped-nonexistent.cpp b/test/SemaCXX/enum-unscoped-nonexistent.cpp
index e9da38f558..7da9a96d60 100644
--- a/test/SemaCXX/enum-unscoped-nonexistent.cpp
+++ b/test/SemaCXX/enum-unscoped-nonexistent.cpp
@@ -6,7 +6,7 @@ struct Base {
template struct S : Base {
enum E : int;
constexpr int f() const;
- constexpr int g() const; // expected-note {{declared here}}
+ constexpr int g() const;
void h();
};
template<> enum S::E : int {}; // expected-note {{enum 'S::E' was explicitly specialized here}}
@@ -23,7 +23,7 @@ static_assert(S().f() == 1, "");
// The unqualified-id here names a member of the current instantiation, which
// bizarrely might not exist in some instantiations.
template constexpr int S::g() const { return b; } // expected-error {{enumerator 'b' does not exist in instantiation of 'S'}}
-static_assert(S().g() == 1, ""); // expected-note {{here}} expected-error {{not an integral constant expression}} expected-note {{undefined}}
+static_assert(S().g() == 1, ""); // expected-note {{here}} expected-error {{not an integral constant expression}}
static_assert(S().g() == 2, "");
static_assert(S().g() == 8, "");
--
cgit v1.2.3
From 3371711aabc154acb4bffee4dc9491632379857d Mon Sep 17 00:00:00 2001
From: Patrik Hagglund
Date: Tue, 14 May 2013 07:53:53 +0000
Subject: Replace EXPECT_EQ with EXPECT_FALSE to avoid gcc warning
[-Wconversion-null], introduced in r181326.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181761 91177308-0d34-0410-b5e6-96231b3b80d8
---
unittests/Format/FormatTest.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 697cc53820..b2ae3d2560 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -4122,9 +4122,9 @@ TEST_F(FormatTest, ParsesConfiguration) {
#define CHECK_PARSE_BOOL(FIELD) \
Style.FIELD = false; \
EXPECT_EQ(0, parseConfiguration(#FIELD ": true", &Style).value()); \
- EXPECT_EQ(true, Style.FIELD); \
+ EXPECT_TRUE(Style.FIELD); \
EXPECT_EQ(0, parseConfiguration(#FIELD ": false", &Style).value()); \
- EXPECT_EQ(false, Style.FIELD);
+ EXPECT_FALSE(Style.FIELD);
CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft);
CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
--
cgit v1.2.3
From 028d59c9e5ef3c46ff26fe106050d750cf8bc2cc Mon Sep 17 00:00:00 2001
From: Tim Northover
Date: Tue, 14 May 2013 08:26:14 +0000
Subject: AArch64: correct definition of __clear_cache
According to libgcc document __clear_cache takes two char*
pointers. I suspect GCC's actual behaviour is more subtle than that,
but char* should clearly be preferred to void*.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181762 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/Basic/BuiltinsAArch64.def | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/clang/Basic/BuiltinsAArch64.def b/include/clang/Basic/BuiltinsAArch64.def
index 9e9f6d0875..939c080cc5 100644
--- a/include/clang/Basic/BuiltinsAArch64.def
+++ b/include/clang/Basic/BuiltinsAArch64.def
@@ -15,4 +15,4 @@
// The format of this database matches clang/Basic/Builtins.def.
// In libgcc
-BUILTIN(__clear_cache, "vv*v*", "")
+BUILTIN(__clear_cache, "vc*c*", "")
--
cgit v1.2.3
From 7424d79613a67ba200b6801468f2b59cde7ab087 Mon Sep 17 00:00:00 2001
From: Daniel Jasper
Date: Tue, 14 May 2013 08:34:47 +0000
Subject: Don't format sizeof/alignof as function types.
Before: A