[llvm-branch-commits] [cfe-branch] r148545 [2/3] - in /cfe/branches/tooling: ./ bindings/python/clang/ docs/ examples/PrintFunctionNames/ examples/clang-interpreter/ include/clang-c/ include/clang/AST/ include/clang/Analysis/ include/clang/Analysis/Analyses/ include/clang/Analysis/Visitors/ include/clang/Basic/ include/clang/CodeGen/ include/clang/Driver/ include/clang/Frontend/ include/clang/Lex/ include/clang/Parse/ include/clang/Sema/ include/clang/Serialization/ include/clang/StaticAnalyzer/Core/ include/clang/StaticAnaly...
Manuel Klimek
klimek at google.com
Fri Jan 20 08:14:26 PST 2012
Modified: cfe/branches/tooling/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Driver/Tools.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Driver/Tools.cpp (original)
+++ cfe/branches/tooling/lib/Driver/Tools.cpp Fri Jan 20 10:14:22 2012
@@ -395,8 +395,6 @@
CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache));
}
- Args.AddAllArgs(CmdArgs, options::OPT_fauto_module_import);
-
// Parse additional include paths from environment variables.
// FIXME: We should probably sink the logic for handling these from the
// frontend into the driver. It will allow deleting 4 otherwise unused flags.
@@ -519,6 +517,7 @@
} else {
// Select the default based on the platform.
switch(Triple.getEnvironment()) {
+ case llvm::Triple::ANDROIDEABI:
case llvm::Triple::GNUEABI:
ABIName = "aapcs-linux";
break;
@@ -591,6 +590,15 @@
// EABI is always AAPCS, and if it was not marked 'hard', it's softfp
FloatABI = "softfp";
break;
+ case llvm::Triple::ANDROIDEABI: {
+ StringRef ArchName =
+ getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
+ if (ArchName.startswith("v7"))
+ FloatABI = "softfp";
+ else
+ FloatABI = "soft";
+ break;
+ }
default:
// Assume "soft", but warn the user we are guessing.
FloatABI = "soft";
@@ -652,12 +660,23 @@
CmdArgs.push_back("-vfp3");
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("-neon");
+ } else if (FPU == "vfp3-d16" || FPU == "vfpv3-d16") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+vfp3");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+d16");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-neon");
} else if (FPU == "vfp") {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+vfp2");
- } else if (FPU == "vfp3") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-neon");
+ } else if (FPU == "vfp3" || FPU == "vfpv3") {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+vfp3");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-neon");
} else if (FPU == "neon") {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+neon");
@@ -800,9 +819,8 @@
const Driver &D = getToolChain().getDriver();
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- StringRef MArch = A->getValue(Args);
CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(MArch.str().c_str());
+ CmdArgs.push_back(A->getValue(Args));
}
// Select the float ABI as determined by -msoft-float, -mhard-float, and
@@ -948,49 +966,39 @@
{
Arg * A = NULL;
- for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- if ((*it)->getOption().matches(options::OPT_mv2) ||
- (*it)->getOption().matches(options::OPT_mv3) ||
- (*it)->getOption().matches(options::OPT_mv4) ||
- (*it)->getOption().matches(options::OPT_march_EQ) ||
+ for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
+ it != ie; ++it) {
+ if ((*it)->getOption().matches(options::OPT_march_EQ) ||
(*it)->getOption().matches(options::OPT_mcpu_EQ)) {
A = *it;
A->claim();
}
+ else if ((*it)->getOption().matches(options::OPT_m_Joined)){
+ StringRef Value = (*it)->getValue(Args,0);
+ if (Value.startswith("v")) {
+ A = *it;
+ A->claim();
+ }
+ }
}
return A;
}
-static const char *getHexagonTargetCPU(const ArgList &Args)
+static StringRef getHexagonTargetCPU(const ArgList &Args)
{
Arg *A;
llvm::StringRef WhichHexagon;
+ // Select the default CPU (v4) if none was given or detection failed.
if ((A = getLastHexagonArchArg (Args))) {
- if ((A->getOption().matches(options::OPT_march_EQ)) ||
- (A->getOption().matches(options::OPT_mcpu_EQ))) {
- WhichHexagon = A->getValue(Args);
- if (WhichHexagon == "v2")
- return "hexagonv2";
- else if (WhichHexagon == "v3")
- return "hexagonv3";
- else if (WhichHexagon == "v4")
- return "hexagonv4";
- else
- assert (0 && "Unknown -march or -mcpu value");
- }
- else {
- if (A->getOption().matches(options::OPT_mv2))
- return "hexagonv2";
- else if (A->getOption().matches(options::OPT_mv3))
- return "hexagonv3";
- else if (A->getOption().matches(options::OPT_mv4))
- return "hexagonv4";
- else
- assert(0 && "Unknown -m argument.");
- }
+ WhichHexagon = A->getValue(Args);
+ if (WhichHexagon == "")
+ return "v4";
+ else
+ return WhichHexagon;
}
- return "hexagonv2";
+ else
+ return "v4";
}
void Clang::AddHexagonTargetArgs(const ArgList &Args,
@@ -998,7 +1006,7 @@
llvm::Triple Triple = getToolChain().getTriple();
CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(getHexagonTargetCPU(Args));
+ CmdArgs.push_back(Args.MakeArgString("hexagon" + getHexagonTargetCPU(Args)));
CmdArgs.push_back("-fno-signed-char");
CmdArgs.push_back("-nobuiltininc");
@@ -1342,14 +1350,14 @@
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-analyzer-checker=core");
- CmdArgs.push_back("-analyzer-checker=deadcode");
- CmdArgs.push_back("-analyzer-checker=security");
if (getToolChain().getTriple().getOS() != llvm::Triple::Win32)
CmdArgs.push_back("-analyzer-checker=unix");
if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
CmdArgs.push_back("-analyzer-checker=osx");
+
+ CmdArgs.push_back("-analyzer-checker=deadcode");
}
// Set the output format. The default is plist, for (lame) historical
@@ -1425,7 +1433,6 @@
if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
CmdArgs.push_back("-mrtd");
- // FIXME: Set --enable-unsafe-fp-math.
if (shouldUseFramePointer(Args, getToolChain().getTriple()))
CmdArgs.push_back("-mdisable-fp-elim");
if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
@@ -1436,18 +1443,90 @@
getToolChain().IsStrictAliasingDefault()))
CmdArgs.push_back("-relaxed-aliasing");
- // Handle -f{no-}honor-infinities, -f{no-}honor-nans, and -ffinite-math-only.
- bool HonorInfinities = Args.hasFlag(options::OPT_fhonor_infinities,
- options::OPT_fno_honor_infinities);
- bool HonorNaNs = Args.hasFlag(options::OPT_fhonor_nans,
- options::OPT_fno_honor_nans);
- if (Args.hasArg(options::OPT_ffinite_math_only))
- HonorInfinities = HonorNaNs = false;
- if (!HonorInfinities)
- CmdArgs.push_back("-menable-no-infs");
- if (!HonorNaNs)
- CmdArgs.push_back("-menable-no-nans");
-
+ // Handle various floating point optimization flags, mapping them to the
+ // appropriate LLVM code generation flags. The pattern for all of these is to
+ // default off the codegen optimizations, and if any flag enables them and no
+ // flag disables them after the flag enabling them, enable the codegen
+ // optimization. This is complicated by several "umbrella" flags.
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_ffinite_math_only,
+ options::OPT_fno_finite_math_only,
+ options::OPT_fhonor_infinities,
+ options::OPT_fno_honor_infinities))
+ if (A->getOption().getID() != options::OPT_fno_finite_math_only &&
+ A->getOption().getID() != options::OPT_fhonor_infinities)
+ CmdArgs.push_back("-menable-no-infs");
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_ffinite_math_only,
+ options::OPT_fno_finite_math_only,
+ options::OPT_fhonor_nans,
+ options::OPT_fno_honor_nans))
+ if (A->getOption().getID() != options::OPT_fno_finite_math_only &&
+ A->getOption().getID() != options::OPT_fhonor_nans)
+ CmdArgs.push_back("-menable-no-nans");
+
+ // -fno-math-errno is default.
+ bool MathErrno = false;
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fmath_errno,
+ options::OPT_fno_math_errno)) {
+ if (A->getOption().getID() == options::OPT_fmath_errno) {
+ CmdArgs.push_back("-fmath-errno");
+ MathErrno = true;
+ }
+ }
+
+ // There are several flags which require disabling very specific
+ // optimizations. Any of these being disabled forces us to turn off the
+ // entire set of LLVM optimizations, so collect them through all the flag
+ // madness.
+ bool AssociativeMath = false;
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_funsafe_math_optimizations,
+ options::OPT_fno_unsafe_math_optimizations,
+ options::OPT_fassociative_math,
+ options::OPT_fno_associative_math))
+ if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ A->getOption().getID() != options::OPT_fno_associative_math)
+ AssociativeMath = true;
+ bool ReciprocalMath = false;
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_funsafe_math_optimizations,
+ options::OPT_fno_unsafe_math_optimizations,
+ options::OPT_freciprocal_math,
+ options::OPT_fno_reciprocal_math))
+ if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ A->getOption().getID() != options::OPT_fno_reciprocal_math)
+ ReciprocalMath = true;
+ bool SignedZeros = true;
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_funsafe_math_optimizations,
+ options::OPT_fno_unsafe_math_optimizations,
+ options::OPT_fsigned_zeros,
+ options::OPT_fno_signed_zeros))
+ if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ A->getOption().getID() != options::OPT_fsigned_zeros)
+ SignedZeros = false;
+ bool TrappingMath = true;
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_funsafe_math_optimizations,
+ options::OPT_fno_unsafe_math_optimizations,
+ options::OPT_ftrapping_math,
+ options::OPT_fno_trapping_math))
+ if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ A->getOption().getID() != options::OPT_ftrapping_math)
+ TrappingMath = false;
+ if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
+ !TrappingMath)
+ CmdArgs.push_back("-menable-unsafe-fp-math");
+
+ // We separately look for the '-ffast-math' flag, and if we find it, tell the
+ // frontend to provide the appropriate preprocessor macros. This is distinct
+ // from enabling any optimizations as it induces a language change which must
+ // survive serialization and deserialization, etc.
+ if (Args.hasArg(options::OPT_ffast_math))
+ CmdArgs.push_back("-ffast-math");
+
// Decide whether to use verbose asm. Verbose assembly is the default on
// toolchains which have the integrated assembler on by default.
bool IsVerboseAsmDefault = getToolChain().IsIntegratedAssemblerDefault();
@@ -1549,12 +1628,6 @@
!getToolChain().getTriple().isOSDarwin()))
CmdArgs.push_back("-momit-leaf-frame-pointer");
- // -fno-math-errno is default.
- if (Args.hasFlag(options::OPT_fmath_errno,
- options::OPT_fno_math_errno,
- false))
- CmdArgs.push_back("-fmath-errno");
-
// Explicitly error on some things we know we don't support and can't just
// ignore.
types::ID InputType = Inputs[0].getType();
@@ -1844,6 +1917,7 @@
Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info);
Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info);
Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
+ Args.AddLastArg(CmdArgs, options::OPT_faltivec);
if (getToolChain().SupportsProfiling())
Args.AddLastArg(CmdArgs, options::OPT_pg);
@@ -1957,6 +2031,17 @@
CmdArgs.push_back("-fblocks-runtime-optional");
}
+ // -fmodules enables modules (off by default). However, for C++/Objective-C++,
+ // users must also pass -fcxx-modules. The latter flag will disappear once the
+ // modules implementation is solid for C++/Objective-C++ programs as well.
+ if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
+ bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
+ options::OPT_fno_cxx_modules,
+ false);
+ if (AllowedInCXX || !types::isCXX(InputType))
+ CmdArgs.push_back("-fmodules");
+ }
+
// -faccess-control is default.
if (Args.hasFlag(options::OPT_fno_access_control,
options::OPT_faccess_control,
@@ -2501,7 +2586,40 @@
// Ignore explicit -force_cpusubtype_ALL option.
(void) Args.hasArg(options::OPT_force__cpusubtype__ALL);
- // FIXME: Add -g support, once we have it.
+ // Determine the original source input.
+ const Action *SourceAction = &JA;
+ while (SourceAction->getKind() != Action::InputClass) {
+ assert(!SourceAction->getInputs().empty() && "unexpected root action!");
+ SourceAction = SourceAction->getInputs()[0];
+ }
+
+ // Forward -g, assuming we are dealing with an actual assembly file.
+ if (SourceAction->getType() == types::TY_Asm ||
+ SourceAction->getType() == types::TY_PP_Asm) {
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ if (Arg *A = Args.getLastArg(options::OPT_g_Group))
+ if (!A->getOption().matches(options::OPT_g0))
+ CmdArgs.push_back("-g");
+ }
+
+ // Optionally embed the -cc1as level arguments into the debug info, for build
+ // analysis.
+ if (getToolChain().UseDwarfDebugFlags()) {
+ ArgStringList OriginalArgs;
+ for (ArgList::const_iterator it = Args.begin(),
+ ie = Args.end(); it != ie; ++it)
+ (*it)->render(Args, OriginalArgs);
+
+ llvm::SmallString<256> Flags;
+ const char *Exec = getToolChain().getDriver().getClangProgramPath();
+ Flags += Exec;
+ for (unsigned i = 0, e = OriginalArgs.size(); i != e; ++i) {
+ Flags += " ";
+ Flags += OriginalArgs[i];
+ }
+ CmdArgs.push_back("-dwarf-debug-flags");
+ CmdArgs.push_back(Args.MakeArgString(Flags.str()));
+ }
// FIXME: Add -static support, once we have it.
@@ -2780,29 +2898,16 @@
// Add Arch Information
Arg *A;
- if ((A = getLastHexagonArchArg (Args))) {
- if ((A->getOption().matches(options::OPT_march_EQ)) ||
- (A->getOption().matches(options::OPT_mcpu_EQ))) {
- llvm::StringRef WhichHexagon = A->getValue(Args);
- if (WhichHexagon == "v2")
- CmdArgs.push_back("-mv2");
- else if (WhichHexagon == "v3")
- CmdArgs.push_back ("-mv3");
- else if (WhichHexagon == "v4")
- CmdArgs.push_back ("-mv4");
+ if ((A = getLastHexagonArchArg(Args))) {
+ if (A->getOption().matches(options::OPT_m_Joined))
+ A->render(Args, CmdArgs);
else
- assert (0 && "Unknown -march or -mcpu value");
- }
- else {
- if (A->getOption().matches(options::OPT_mv2) ||
- A->getOption().matches(options::OPT_mv3) ||
- A->getOption().matches(options::OPT_mv4))
- A->render(Args, CmdArgs);
- else
- assert(0 && "Unknown -m argument.");
- }
-
+ CmdArgs.push_back (Args.MakeArgString("-m" + getHexagonTargetCPU(Args)));
+ }
+ else {
+ CmdArgs.push_back (Args.MakeArgString("-m" + getHexagonTargetCPU(Args)));
}
+
CmdArgs.push_back("-mqdsp6-compat");
const char *GCCName;
@@ -2865,6 +2970,8 @@
}
}
+void darwin::CC1::anchor() {}
+
const char *darwin::CC1::getBaseInputName(const ArgList &Args,
const InputInfoList &Inputs) {
return Args.MakeArgString(
@@ -3509,6 +3616,8 @@
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
+void darwin::DarwinTool::anchor() {}
+
void darwin::DarwinTool::AddDarwinArch(const ArgList &Args,
ArgStringList &CmdArgs) const {
StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args);
@@ -3540,13 +3649,7 @@
// Newer linkers support -demangle, pass it if supported and not disabled by
// the user.
- //
- // FIXME: We temporarily avoid passing -demangle to any iOS linker, because
- // unfortunately we can't be guaranteed that the linker version used there
- // will match the linker version detected at configure time. We need the
- // universal driver.
- if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle) &&
- !DarwinTC.isTargetIPhoneOS()) {
+ if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) {
// Don't pass -demangle to ld_classic.
//
// FIXME: This is a temporary workaround, ld should be handling this.
@@ -4213,11 +4316,12 @@
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-lpthread");
- if (!Args.hasArg(options::OPT_shared))
+ if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lc_p");
else
CmdArgs.push_back("-lc");
+ }
CmdArgs.push_back("-lgcc");
}
Modified: cfe/branches/tooling/lib/Driver/Tools.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Driver/Tools.h?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Driver/Tools.h (original)
+++ cfe/branches/tooling/lib/Driver/Tools.h Fri Jan 20 10:14:22 2012
@@ -192,6 +192,7 @@
namespace darwin {
class LLVM_LIBRARY_VISIBILITY DarwinTool : public Tool {
+ virtual void anchor();
protected:
void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const;
@@ -205,6 +206,7 @@
};
class LLVM_LIBRARY_VISIBILITY CC1 : public DarwinTool {
+ virtual void anchor();
public:
static const char *getBaseInputName(const ArgList &Args,
const InputInfoList &Input);
Modified: cfe/branches/tooling/lib/Frontend/ASTUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/ASTUnit.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/ASTUnit.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/ASTUnit.cpp Fri Jan 20 10:14:22 2012
@@ -262,6 +262,8 @@
}
}
+void ASTUnit::setPreprocessor(Preprocessor *pp) { PP = pp; }
+
/// \brief Determine the set of code-completion contexts in which this
/// declaration should be shown.
static unsigned getDeclShowContexts(NamedDecl *ND,
@@ -667,7 +669,8 @@
AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
AST->getFileManager());
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(),
- AST->getDiagnostics()));
+ AST->getDiagnostics(),
+ AST->ASTFileLangOpts));
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
@@ -826,22 +829,7 @@
Hash = llvm::HashString(NameStr, Hash);
}
return;
- }
-
- if (ObjCForwardProtocolDecl *Forward
- = dyn_cast<ObjCForwardProtocolDecl>(D)) {
- for (ObjCForwardProtocolDecl::protocol_iterator
- P = Forward->protocol_begin(),
- PEnd = Forward->protocol_end();
- P != PEnd; ++P)
- AddTopLevelDeclarationToHash(*P, Hash);
- return;
- }
-
- if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(D)) {
- AddTopLevelDeclarationToHash(Class->getForwardInterfaceDecl(), Hash);
- return;
- }
+ }
}
class TopLevelDeclTrackerConsumer : public ASTConsumer {
@@ -2406,7 +2394,7 @@
if (Out.has_error())
return CXSaveError_Unknown;
- if (llvm::error_code ec = llvm::sys::fs::rename(TempPath.str(), File)) {
+ if (llvm::sys::fs::rename(TempPath.str(), File)) {
bool exists;
llvm::sys::fs::remove(TempPath.str(), exists);
return CXSaveError_Unknown;
Modified: cfe/branches/tooling/lib/Frontend/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/CMakeLists.txt?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/CMakeLists.txt (original)
+++ cfe/branches/tooling/lib/Frontend/CMakeLists.txt Fri Jan 20 10:14:22 2012
@@ -13,6 +13,7 @@
ASTMerge.cpp
ASTUnit.cpp
CacheTokens.cpp
+ ChainedDiagnosticConsumer.cpp
ChainedIncludesSource.cpp
CompilerInstance.cpp
CompilerInvocation.cpp
Modified: cfe/branches/tooling/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/CompilerInstance.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/CompilerInstance.cpp Fri Jan 20 10:14:22 2012
@@ -252,7 +252,8 @@
// Create the Preprocessor.
HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager(),
- getDiagnostics());
+ getDiagnostics(),
+ getLangOpts());
PP = new Preprocessor(getDiagnostics(), getLangOpts(), &getTarget(),
getSourceManager(), *HeaderInfo, *this, PTHMgr,
/*OwnsHeaderSearch=*/true);
@@ -1221,25 +1222,26 @@
if (Path.size() > 1) {
for (unsigned I = 1, N = Path.size(); I != N; ++I) {
StringRef Name = Path[I].first->getName();
- llvm::StringMap<clang::Module *>::iterator Pos
- = Module->SubModules.find(Name);
+ clang::Module *Sub = Module->findSubmodule(Name);
- if (Pos == Module->SubModules.end()) {
+ if (!Sub) {
// Attempt to perform typo correction to find a module name that works.
llvm::SmallVector<StringRef, 2> Best;
unsigned BestEditDistance = (std::numeric_limits<unsigned>::max)();
- for (llvm::StringMap<clang::Module *>::iterator
- J = Module->SubModules.begin(),
- JEnd = Module->SubModules.end();
+ for (clang::Module::submodule_iterator J = Module->submodule_begin(),
+ JEnd = Module->submodule_end();
J != JEnd; ++J) {
- unsigned ED = Name.edit_distance(J->getValue()->Name,
+ unsigned ED = Name.edit_distance((*J)->Name,
/*AllowReplacements=*/true,
BestEditDistance);
if (ED <= BestEditDistance) {
- if (ED < BestEditDistance)
+ if (ED < BestEditDistance) {
Best.clear();
- Best.push_back(J->getValue()->Name);
+ BestEditDistance = ED;
+ }
+
+ Best.push_back((*J)->Name);
}
}
@@ -1251,11 +1253,12 @@
<< SourceRange(Path[0].second, Path[I-1].second)
<< FixItHint::CreateReplacement(SourceRange(Path[I].second),
Best[0]);
- Pos = Module->SubModules.find(Best[0]);
+
+ Sub = Module->findSubmodule(Best[0]);
}
}
- if (Pos == Module->SubModules.end()) {
+ if (!Sub) {
// No submodule by this name. Complain, and don't look for further
// submodules.
getDiagnostics().Report(Path[I].second, diag::err_no_submodule)
@@ -1264,15 +1267,42 @@
break;
}
- Module = Pos->getValue();
+ Module = Sub;
}
}
// Make the named module visible, if it's not already part of the module
// we are parsing.
- if (ModuleName != getLangOpts().CurrentModule)
- ModuleManager->makeModuleVisible(Module, Visibility);
+ if (ModuleName != getLangOpts().CurrentModule) {
+ if (!Module->IsFromModuleFile) {
+ // We have an umbrella header or directory that doesn't actually include
+ // all of the headers within the directory it covers. Complain about
+ // this missing submodule and recover by forgetting that we ever saw
+ // this submodule.
+ // FIXME: Should we detect this at module load time? It seems fairly
+ // expensive (and rare).
+ getDiagnostics().Report(ImportLoc, diag::warn_missing_submodule)
+ << Module->getFullModuleName()
+ << SourceRange(Path.front().second, Path.back().second);
+
+ return 0;
+ }
+
+ // Check whether this module is available.
+ StringRef Feature;
+ if (!Module->isAvailable(getLangOpts(), Feature)) {
+ getDiagnostics().Report(ImportLoc, diag::err_module_unavailable)
+ << Module->getFullModuleName()
+ << Feature
+ << SourceRange(Path.front().second, Path.back().second);
+ LastModuleImportLoc = ImportLoc;
+ LastModuleImportResult = 0;
+ return 0;
+ }
+ ModuleManager->makeModuleVisible(Module, Visibility);
+ }
+
// If this module import was due to an inclusion directive, create an
// implicit import declaration to capture it in the AST.
if (IsInclusionDirective && hasASTContext()) {
Modified: cfe/branches/tooling/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/CompilerInvocation.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/CompilerInvocation.cpp Fri Jan 20 10:14:22 2012
@@ -716,6 +716,8 @@
Res.push_back("-fblocks");
if (Opts.BlocksRuntimeOptional)
Res.push_back("-fblocks-runtime-optional");
+ if (Opts.Modules)
+ Res.push_back("-fmodules");
if (Opts.EmitAllDecls)
Res.push_back("-femit-all-decls");
if (Opts.MathErrno)
@@ -735,6 +737,8 @@
Res.push_back("-fheinous-gnu-extensions");
// Optimize is implicit.
// OptimizeSize is implicit.
+ if (Opts.FastMath)
+ Res.push_back("-ffast-math");
if (Opts.Static)
Res.push_back("-static-define");
if (Opts.DumpRecordLayouts)
@@ -944,10 +948,10 @@
Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags);
}
-static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
+static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
DiagnosticsEngine &Diags) {
using namespace cc1options;
-
+ bool Success = true;
if (Arg *A = Args.getLastArg(OPT_analyzer_store)) {
StringRef Name = A->getValue(Args);
AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name)
@@ -955,12 +959,13 @@
.Case(CMDFLAG, NAME##Model)
#include "clang/Frontend/Analyses.def"
.Default(NumStores);
- // FIXME: Error handling.
- if (Value == NumStores)
+ if (Value == NumStores) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << Name;
- else
+ Success = false;
+ } else {
Opts.AnalysisStoreOpt = Value;
+ }
}
if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) {
@@ -970,12 +975,13 @@
.Case(CMDFLAG, NAME##Model)
#include "clang/Frontend/Analyses.def"
.Default(NumConstraints);
- // FIXME: Error handling.
- if (Value == NumConstraints)
+ if (Value == NumConstraints) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << Name;
- else
+ Success = false;
+ } else {
Opts.AnalysisConstraintsOpt = Value;
+ }
}
if (Arg *A = Args.getLastArg(OPT_analyzer_output)) {
@@ -985,12 +991,13 @@
.Case(CMDFLAG, PD_##NAME)
#include "clang/Frontend/Analyses.def"
.Default(NUM_ANALYSIS_DIAG_CLIENTS);
- // FIXME: Error handling.
- if (Value == NUM_ANALYSIS_DIAG_CLIENTS)
+ if (Value == NUM_ANALYSIS_DIAG_CLIENTS) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << Name;
- else
+ Success = false;
+ } else {
Opts.AnalysisDiagOpt = Value;
+ }
}
if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) {
@@ -1000,12 +1007,13 @@
.Case(CMDFLAG, NAME)
#include "clang/Frontend/Analyses.def"
.Default(NumPurgeModes);
- // FIXME: Error handling.
- if (Value == NumPurgeModes)
+ if (Value == NumPurgeModes) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << Name;
- else
+ Success = false;
+ } else {
Opts.AnalysisPurgeOpt = Value;
+ }
}
Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
@@ -1041,17 +1049,21 @@
for (unsigned i = 0, e = checkers.size(); i != e; ++i)
Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable));
}
+
+ return Success;
}
-static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
+static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
using namespace cc1options;
+ bool Success = true;
Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags);
if (Opts.OptimizationLevel > 3) {
Diags.Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel;
Opts.OptimizationLevel = 3;
+ Success = false;
}
// We must always run at least the always inlining pass.
@@ -1109,7 +1121,8 @@
Opts.NoDwarf2CFIAsm = Args.hasArg(OPT_fno_dwarf2_cfi_asm);
Opts.NoDwarfDirectoryAsm = Args.hasArg(OPT_fno_dwarf_directory_asm);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
- Opts.UnsafeFPMath = Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
+ Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) ||
+ Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
@@ -1140,11 +1153,15 @@
.Case("non-legacy", CodeGenOptions::NonLegacy)
.Case("mixed", CodeGenOptions::Mixed)
.Default(~0U);
- if (Method == ~0U)
+ if (Method == ~0U) {
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
- else
+ Success = false;
+ } else {
Opts.ObjCDispatchMethod = Method;
+ }
}
+
+ return Success;
}
static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
@@ -1159,9 +1176,11 @@
Opts.AddMissingHeaderDeps = Args.hasArg(OPT_MG);
}
-static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
+static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
DiagnosticsEngine &Diags) {
using namespace cc1options;
+ bool Success = true;
+
Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file);
Opts.DiagnosticSerializationFile =
Args.getLastArgValue(OPT_diagnostic_serialized_file);
@@ -1192,10 +1211,12 @@
Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best;
else if (ShowOverloads == "all")
Opts.ShowOverloads = DiagnosticsEngine::Ovl_All;
- else
+ else {
Diags.Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args)
<< ShowOverloads;
+ Success = false;
+ }
StringRef ShowCategory =
Args.getLastArgValue(OPT_fdiagnostics_show_category, "none");
@@ -1205,23 +1226,27 @@
Opts.ShowCategories = 1;
else if (ShowCategory == "name")
Opts.ShowCategories = 2;
- else
+ else {
Diags.Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args)
<< ShowCategory;
+ Success = false;
+ }
StringRef Format =
Args.getLastArgValue(OPT_fdiagnostics_format, "clang");
if (Format == "clang")
Opts.Format = DiagnosticOptions::Clang;
- else if (Format == "msvc")
+ else if (Format == "msvc")
Opts.Format = DiagnosticOptions::Msvc;
- else if (Format == "vi")
+ else if (Format == "vi")
Opts.Format = DiagnosticOptions::Vi;
- else
+ else {
Diags.Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_fdiagnostics_format)->getAsString(Args)
<< Format;
+ Success = false;
+ }
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
@@ -1248,6 +1273,8 @@
Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags);
Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information);
Opts.Warnings = Args.getAllArgValues(OPT_W);
+
+ return Success;
}
static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) {
@@ -1593,7 +1620,7 @@
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
Opts.BCPLComment = Std.hasBCPLComments();
Opts.C99 = Std.isC99();
- Opts.C1X = Std.isC1X();
+ Opts.C11 = Std.isC11();
Opts.CPlusPlus = Std.isCPlusPlus();
Opts.CPlusPlus0x = Std.isCPlusPlus0x();
Opts.Digraphs = Std.hasDigraphs();
@@ -1789,6 +1816,7 @@
Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
Opts.Blocks = Args.hasArg(OPT_fblocks);
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
+ Opts.Modules = Args.hasArg(OPT_fmodules);
Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
@@ -1852,6 +1880,8 @@
// FIXME: This is affected by other options (-fno-inline).
Opts.NoInline = !Opt;
+ Opts.FastMath = Args.hasArg(OPT_ffast_math);
+
unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags);
switch (SSP) {
default:
@@ -1876,7 +1906,6 @@
Opts.TokenCache = Opts.ImplicitPTHInclude;
Opts.UsePredefines = !Args.hasArg(OPT_undef);
Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
- Opts.AutoModuleImport = Args.hasArg(OPT_fauto_module_import);
Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch);
Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls);
@@ -1994,10 +2023,12 @@
//
-void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
+bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
const char *const *ArgBegin,
const char *const *ArgEnd,
DiagnosticsEngine &Diags) {
+ bool Success = true;
+
// Parse the arguments.
llvm::OwningPtr<OptTable> Opts(createCC1OptTable());
unsigned MissingArgIndex, MissingArgCount;
@@ -2005,22 +2036,28 @@
Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));
// Check for missing argument error.
- if (MissingArgCount)
+ if (MissingArgCount) {
Diags.Report(diag::err_drv_missing_argument)
<< Args->getArgString(MissingArgIndex) << MissingArgCount;
+ Success = false;
+ }
// Issue errors on unknown arguments.
for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
- ie = Args->filtered_end(); it != ie; ++it)
+ ie = Args->filtered_end(); it != ie; ++it) {
Diags.Report(diag::err_drv_unknown_argument) << (*it)->getAsString(*Args);
+ Success = false;
+ }
- ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags);
+ Success = ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags) && Success;
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
- ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags);
+ Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags)
+ && Success;
ParseFileSystemArgs(Res.getFileSystemOpts(), *Args);
// FIXME: We shouldn't have to pass the DashX option around here
InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
- ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags);
+ Success = ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags)
+ && Success;
ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args);
if (DashX != IK_AST && DashX != IK_LLVM_IR) {
ParseLangArgs(*Res.getLangOpts(), *Args, DashX, Diags);
@@ -2035,6 +2072,8 @@
ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
ParseTargetArgs(Res.getTargetOpts(), *Args);
+
+ return Success;
}
namespace {
Modified: cfe/branches/tooling/lib/Frontend/CreateInvocationFromCommandLine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/CreateInvocationFromCommandLine.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/CreateInvocationFromCommandLine.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/CreateInvocationFromCommandLine.cpp Fri Jan 20 10:14:22 2012
@@ -80,11 +80,12 @@
}
const driver::ArgStringList &CCArgs = Cmd->getArguments();
- CompilerInvocation *CI = new CompilerInvocation();
- CompilerInvocation::CreateFromArgs(*CI,
+ llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation());
+ if (!CompilerInvocation::CreateFromArgs(*CI,
const_cast<const char **>(CCArgs.data()),
const_cast<const char **>(CCArgs.data()) +
CCArgs.size(),
- *Diags);
- return CI;
+ *Diags))
+ return 0;
+ return CI.take();
}
Modified: cfe/branches/tooling/lib/Frontend/DiagnosticRenderer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/DiagnosticRenderer.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/DiagnosticRenderer.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/DiagnosticRenderer.cpp Fri Jan 20 10:14:22 2012
@@ -69,35 +69,6 @@
return SM.getImmediateSpellingLoc(Loc);
}
-/// \brief Retrieve the name of the immediate macro expansion.
-///
-/// This routine starts from a source location, and finds the name of the macro
-/// responsible for its immediate expansion. It looks through any intervening
-/// macro argument expansions to compute this. It returns a StringRef which
-/// refers to the SourceManager-owned buffer of the source where that macro
-/// name is spelled. Thus, the result shouldn't out-live that SourceManager.
-///
-static StringRef getImmediateMacroName(SourceLocation Loc,
- const SourceManager &SM,
- const LangOptions &LangOpts) {
- assert(Loc.isMacroID() && "Only reasonble to call this on macros");
- // Walk past macro argument expanions.
- while (SM.isMacroArgExpansion(Loc))
- Loc = SM.getImmediateExpansionRange(Loc).first;
-
- // Find the spelling location of the start of the non-argument expansion
- // range. This is where the macro name was spelled in order to begin
- // expanding this macro.
- Loc = SM.getSpellingLoc(SM.getImmediateExpansionRange(Loc).first);
-
- // Dig out the buffer where the macro name was spelled and the extents of the
- // name so that we can render it into the expansion note.
- std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc);
- unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
- StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first);
- return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
-}
-
/// Get the presumed location of a diagnostic message. This computes the
/// presumed location for the top of any macro backtrace when present.
static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM,
@@ -289,7 +260,7 @@
llvm::SmallString<100> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
Message << "expanded from macro '"
- << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'";
+ << Lexer::getImmediateMacroName(MacroLoc, SM, LangOpts) << "'";
emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note,
Message.str(),
Ranges, ArrayRef<FixItHint>());
Modified: cfe/branches/tooling/lib/Frontend/FrontendAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/FrontendAction.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/FrontendAction.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/FrontendAction.cpp Fri Jan 20 10:14:22 2012
@@ -310,16 +310,7 @@
// Initialize the main file entry. This needs to be delayed until after PCH
// has loaded.
- if (isCurrentFileAST()) {
- // Set the main file ID to an empty file.
- //
- // FIXME: We probably shouldn't need this, but for now this is the
- // simplest way to reuse the logic in ParseAST.
- const char *EmptyStr = "";
- llvm::MemoryBuffer *SB =
- llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
- CI.getSourceManager().createMainFileIDForMemBuffer(SB);
- } else {
+ if (!isCurrentFileAST()) {
if (!CI.InitializeSourceManager(getCurrentFile()))
return;
}
@@ -411,6 +402,8 @@
ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats);
}
+void PluginASTAction::anchor() { }
+
ASTConsumer *
PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
Modified: cfe/branches/tooling/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/FrontendActions.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/FrontendActions.cpp Fri Jan 20 10:14:22 2012
@@ -134,8 +134,14 @@
/// \param Includes Will be augmented with the set of #includes or #imports
/// needed to load all of the named headers.
static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
+ FileManager &FileMgr,
+ ModuleMap &ModMap,
clang::Module *Module,
llvm::SmallString<256> &Includes) {
+ // Don't collect any headers for unavailable modules.
+ if (!Module->isAvailable())
+ return;
+
// Add includes for each of these headers.
for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
if (LangOpts.ObjC1)
@@ -157,7 +163,7 @@
Includes += "\"\n";
}
} else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) {
- // Add all of the headers we find in this subdirectory (FIXME: recursively!).
+ // Add all of the headers we find in this subdirectory.
llvm::error_code EC;
llvm::SmallString<128> DirNative;
llvm::sys::path::native(UmbrellaDir->getName(), DirNative);
@@ -171,6 +177,12 @@
.Default(false))
continue;
+ // If this header is marked 'unavailable' in this module, don't include
+ // it.
+ if (const FileEntry *Header = FileMgr.getFile(Dir->path()))
+ if (ModMap.isHeaderInUnavailableModule(Header))
+ continue;
+
// Include this header umbrella header for submodules.
if (LangOpts.ObjC1)
Includes += "#import \"";
@@ -182,11 +194,10 @@
}
// Recurse into submodules.
- for (llvm::StringMap<clang::Module *>::iterator
- Sub = Module->SubModules.begin(),
- SubEnd = Module->SubModules.end();
+ for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
+ SubEnd = Module->submodule_end();
Sub != SubEnd; ++Sub)
- collectModuleHeaderIncludes(LangOpts, Sub->getValue(), Includes);
+ collectModuleHeaderIncludes(LangOpts, FileMgr, ModMap, *Sub, Includes);
}
bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
@@ -222,13 +233,25 @@
return false;
}
-
+
+ // Check whether we can build this module at all.
+ StringRef Feature;
+ if (!Module->isAvailable(CI.getLangOpts(), Feature)) {
+ CI.getDiagnostics().Report(diag::err_module_unavailable)
+ << Module->getFullModuleName()
+ << Feature;
+
+ return false;
+ }
+
// Do we have an umbrella header for this module?
const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader();
// Collect the set of #includes we need to build the module.
llvm::SmallString<256> HeaderContents;
- collectModuleHeaderIncludes(CI.getLangOpts(), Module, HeaderContents);
+ collectModuleHeaderIncludes(CI.getLangOpts(), CI.getFileManager(),
+ CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
+ Module, HeaderContents);
if (UmbrellaHeader && HeaderContents.empty()) {
// Simple case: we have an umbrella header and there are no additional
// includes, we can just parse the umbrella header directly.
Modified: cfe/branches/tooling/lib/Frontend/InitPreprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/InitPreprocessor.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/InitPreprocessor.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/InitPreprocessor.cpp Fri Jan 20 10:14:22 2012
@@ -267,11 +267,8 @@
Builder.defineMacro("__STDC_HOSTED__");
if (!LangOpts.CPlusPlus) {
- // FIXME: C1x doesn't have a defined version number yet, so pick something
- // that is the minimum possible according to their placeholder scheme
- // 201ymmL.
- if (LangOpts.C1X)
- Builder.defineMacro("__STDC_VERSION__", "201001L");
+ if (LangOpts.C11)
+ Builder.defineMacro("__STDC_VERSION__", "201112L");
else if (LangOpts.C99)
Builder.defineMacro("__STDC_VERSION__", "199901L");
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
@@ -328,6 +325,14 @@
Builder.defineMacro("__GNUC__", "4");
Builder.defineMacro("__GXX_ABI_VERSION", "1002");
+ // Define macros for the C11 / C++11 memory orderings
+ Builder.defineMacro("__ATOMIC_RELAXED", "0");
+ Builder.defineMacro("__ATOMIC_CONSUME", "1");
+ Builder.defineMacro("__ATOMIC_ACQUIRE", "2");
+ Builder.defineMacro("__ATOMIC_RELEASE", "3");
+ Builder.defineMacro("__ATOMIC_ACQ_REL", "4");
+ Builder.defineMacro("__ATOMIC_SEQ_CST", "5");
+
// As sad as it is, enough software depends on the __VERSION__ for version
// checks that it is necessary to report 4.2.1 (the base GCC version we claim
// compatibility with) first.
@@ -414,6 +419,9 @@
if (LangOpts.OptimizeSize)
Builder.defineMacro("__OPTIMIZE_SIZE__");
+ if (LangOpts.FastMath)
+ Builder.defineMacro("__FAST_MATH__");
+
// Initialize target-specific preprocessor defines.
// Define type sizing macros based on the target properties.
@@ -516,7 +524,7 @@
}
// Macros to control C99 numerics and <float.h>
- Builder.defineMacro("__FLT_EVAL_METHOD__", "0");
+ Builder.defineMacro("__FLT_EVAL_METHOD__", Twine(TI.getFloatEvalMethod()));
Builder.defineMacro("__FLT_RADIX__", "2");
int Dig = PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36);
Builder.defineMacro("__DECIMAL_DIG__", Twine(Dig));
@@ -627,10 +635,6 @@
InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
PP.getFileManager(), InitOpts);
- // Specify whether the preprocessor should replace #include/#import with
- // module imports when plausible.
- PP.setAutoModuleImport(InitOpts.AutoModuleImport);
-
// Emit line markers for various builtin sections of the file. We don't do
// this in asm preprocessor mode, because "# 4" is not a line marker directive
// in this mode.
Modified: cfe/branches/tooling/lib/Frontend/LangStandards.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/LangStandards.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/LangStandards.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/LangStandards.cpp Fri Jan 20 10:14:22 2012
@@ -19,14 +19,13 @@
const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
switch (K) {
- default:
- llvm_unreachable("Invalid language kind!");
case lang_unspecified:
llvm::report_fatal_error("getLangStandardForKind() on unspecified kind");
#define LANGSTANDARD(id, name, desc, features) \
case lang_##id: return Lang_##id;
#include "clang/Frontend/LangStandards.def"
}
+ llvm_unreachable("Invalid language kind!");
}
const LangStandard *LangStandard::getLangStandardForName(StringRef Name) {
Modified: cfe/branches/tooling/lib/Frontend/LogDiagnosticPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/LogDiagnosticPrinter.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/LogDiagnosticPrinter.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/LogDiagnosticPrinter.cpp Fri Jan 20 10:14:22 2012
@@ -12,6 +12,7 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
@@ -28,14 +29,13 @@
static StringRef getLevelName(DiagnosticsEngine::Level Level) {
switch (Level) {
- default:
- return "<unknown>";
case DiagnosticsEngine::Ignored: return "ignored";
case DiagnosticsEngine::Note: return "note";
case DiagnosticsEngine::Warning: return "warning";
case DiagnosticsEngine::Error: return "error";
case DiagnosticsEngine::Fatal: return "fatal error";
}
+ llvm_unreachable("Invalid DiagnosticsEngine level!");
}
// Escape XML characters inside the raw string.
Modified: cfe/branches/tooling/lib/Frontend/PrintPreprocessedOutput.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/PrintPreprocessedOutput.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/PrintPreprocessedOutput.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/PrintPreprocessedOutput.cpp Fri Jan 20 10:14:22 2012
@@ -24,7 +24,6 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Config/config.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstdio>
@@ -390,7 +389,6 @@
MoveToLine(Loc);
OS << "#pragma " << Namespace << " diagnostic ";
switch (Map) {
- default: llvm_unreachable("unexpected diagnostic kind");
case diag::MAP_WARNING:
OS << "warning";
break;
Modified: cfe/branches/tooling/lib/Frontend/VerifyDiagnosticConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/VerifyDiagnosticConsumer.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/VerifyDiagnosticConsumer.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/VerifyDiagnosticConsumer.cpp Fri Jan 20 10:14:22 2012
@@ -459,10 +459,10 @@
}
}
// Now all that's left in Right are those that were not matched.
-
- return (PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true) +
- PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(),
- Label, false));
+ unsigned num = PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true);
+ num += PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(),
+ Label, false);
+ return num;
}
/// CheckResults - This compares the expected results to those that
Modified: cfe/branches/tooling/lib/Frontend/Warnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Frontend/Warnings.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Frontend/Warnings.cpp (original)
+++ cfe/branches/tooling/lib/Frontend/Warnings.cpp Fri Jan 20 10:14:22 2012
@@ -83,6 +83,10 @@
for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
StringRef Opt = Opts.Warnings[i];
+ // Treat -Wformat=0 as an alias for -Wno-format.
+ if (Opt == "format=0")
+ Opt = "no-format";
+
// Check to see if this warning starts with "no-", if so, this is a
// negative form of the option.
bool isPositive = true;
Modified: cfe/branches/tooling/lib/FrontendTool/ExecuteCompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/FrontendTool/ExecuteCompilerInvocation.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/FrontendTool/ExecuteCompilerInvocation.cpp (original)
+++ cfe/branches/tooling/lib/FrontendTool/ExecuteCompilerInvocation.cpp Fri Jan 20 10:14:22 2012
@@ -32,9 +32,6 @@
using namespace clang::frontend;
switch (CI.getFrontendOpts().ProgramAction) {
- default:
- llvm_unreachable("Invalid program action!");
-
case ASTDump: return new ASTDumpAction();
case ASTDumpXML: return new ASTDumpXMLAction();
case ASTPrint: return new ASTPrintAction();
@@ -81,6 +78,7 @@
case RunAnalysis: return new ento::AnalysisAction();
case RunPreprocessorOnly: return new PreprocessOnlyAction();
}
+ llvm_unreachable("Invalid program action!");
}
static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
Modified: cfe/branches/tooling/lib/Headers/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Headers/CMakeLists.txt?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Headers/CMakeLists.txt (original)
+++ cfe/branches/tooling/lib/Headers/CMakeLists.txt Fri Jan 20 10:14:22 2012
@@ -1,16 +1,22 @@
set(files
altivec.h
avxintrin.h
+ avx2intrin.h
+ bmiintrin.h
+ bmi2intrin.h
emmintrin.h
float.h
+ fma4intrin.h
immintrin.h
iso646.h
limits.h
+ lzcntintrin.h
mm3dnow.h
mmintrin.h
mm_malloc.h
nmmintrin.h
pmmintrin.h
+ popcntintrin.h
smmintrin.h
stdalign.h
stdarg.h
Modified: cfe/branches/tooling/lib/Headers/avxintrin.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Headers/avxintrin.h?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Headers/avxintrin.h (original)
+++ cfe/branches/tooling/lib/Headers/avxintrin.h Fri Jan 20 10:14:22 2012
@@ -147,11 +147,11 @@
#define _mm256_round_pd(V, M) __extension__ ({ \
__m256d __V = (V); \
- (__m256d)__builtin_ia32_roundpd256((__v4df)__V, M); })
+ (__m256d)__builtin_ia32_roundpd256((__v4df)__V, (M)); })
#define _mm256_round_ps(V, M) __extension__ ({ \
__m256 __V = (V); \
- (__m256)__builtin_ia32_roundps256((__v8sf)__V, M); })
+ (__m256)__builtin_ia32_roundps256((__v8sf)__V, (M)); })
#define _mm256_ceil_pd(V) _mm256_round_pd((V), _MM_FROUND_CEIL)
#define _mm256_floor_pd(V) _mm256_round_pd((V), _MM_FROUND_FLOOR)
@@ -260,45 +260,45 @@
#define _mm_permute_pd(A, C) __extension__ ({ \
__m128d __A = (A); \
- (__m128d)__builtin_ia32_vpermilpd((__v2df)__A, C); })
+ (__m128d)__builtin_ia32_vpermilpd((__v2df)__A, (C)); })
#define _mm256_permute_pd(A, C) __extension__ ({ \
__m256d __A = (A); \
- (__m256d)__builtin_ia32_vpermilpd256((__v4df)__A, C); })
+ (__m256d)__builtin_ia32_vpermilpd256((__v4df)__A, (C)); })
#define _mm_permute_ps(A, C) __extension__ ({ \
__m128 __A = (A); \
- (__m128)__builtin_ia32_vpermilps((__v4sf)__A, C); })
+ (__m128)__builtin_ia32_vpermilps((__v4sf)__A, (C)); })
#define _mm256_permute_ps(A, C) __extension__ ({ \
__m256 __A = (A); \
- (__m256)__builtin_ia32_vpermilps256((__v8sf)__A, C); })
+ (__m256)__builtin_ia32_vpermilps256((__v8sf)__A, (C)); })
#define _mm256_permute2f128_pd(V1, V2, M) __extension__ ({ \
__m256d __V1 = (V1); \
__m256d __V2 = (V2); \
- (__m256d)__builtin_ia32_vperm2f128_pd256((__v4df)__V1, (__v4df)__V2, M); })
+ (__m256d)__builtin_ia32_vperm2f128_pd256((__v4df)__V1, (__v4df)__V2, (M)); })
#define _mm256_permute2f128_ps(V1, V2, M) __extension__ ({ \
__m256 __V1 = (V1); \
__m256 __V2 = (V2); \
- (__m256)__builtin_ia32_vperm2f128_ps256((__v8sf)__V1, (__v8sf)__V2, M); })
+ (__m256)__builtin_ia32_vperm2f128_ps256((__v8sf)__V1, (__v8sf)__V2, (M)); })
#define _mm256_permute2f128_si256(V1, V2, M) __extension__ ({ \
__m256i __V1 = (V1); \
__m256i __V2 = (V2); \
- (__m256i)__builtin_ia32_vperm2f128_si256((__v8si)__V1, (__v8si)__V2, M); })
+ (__m256i)__builtin_ia32_vperm2f128_si256((__v8si)__V1, (__v8si)__V2, (M)); })
/* Vector Blend */
#define _mm256_blend_pd(V1, V2, M) __extension__ ({ \
__m256d __V1 = (V1); \
__m256d __V2 = (V2); \
- (__m256d)__builtin_ia32_blendpd256((__v4df)__V1, (__v4df)__V2, M); })
+ (__m256d)__builtin_ia32_blendpd256((__v4df)__V1, (__v4df)__V2, (M)); })
#define _mm256_blend_ps(V1, V2, M) __extension__ ({ \
__m256 __V1 = (V1); \
__m256 __V2 = (V2); \
- (__m256)__builtin_ia32_blendps256((__v8sf)__V1, (__v8sf)__V2, M); })
+ (__m256)__builtin_ia32_blendps256((__v8sf)__V1, (__v8sf)__V2, (M)); })
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
_mm256_blendv_pd(__m256d a, __m256d b, __m256d c)
@@ -316,7 +316,7 @@
#define _mm256_dp_ps(V1, V2, M) __extension__ ({ \
__m256 __V1 = (V1); \
__m256 __V2 = (V2); \
- (__m256)__builtin_ia32_dpps256((__v8sf)__V1, (__v8sf)__V2, M); })
+ (__m256)__builtin_ia32_dpps256((__v8sf)__V1, (__v8sf)__V2, (M)); })
/* Vector shuffle */
#define _mm256_shuffle_ps(a, b, mask) __extension__ ({ \
@@ -404,15 +404,15 @@
/* Vector extract */
#define _mm256_extractf128_pd(A, O) __extension__ ({ \
__m256d __A = (A); \
- (__m128d)__builtin_ia32_vextractf128_pd256((__v4df)__A, O); })
+ (__m128d)__builtin_ia32_vextractf128_pd256((__v4df)__A, (O)); })
#define _mm256_extractf128_ps(A, O) __extension__ ({ \
__m256 __A = (A); \
- (__m128)__builtin_ia32_vextractf128_ps256((__v8sf)__A, O); })
+ (__m128)__builtin_ia32_vextractf128_ps256((__v8sf)__A, (O)); })
#define _mm256_extractf128_si256(A, O) __extension__ ({ \
__m256i __A = (A); \
- (__m128i)__builtin_ia32_vextractf128_si256((__v8si)__A, O); })
+ (__m128i)__builtin_ia32_vextractf128_si256((__v8si)__A, (O)); })
static __inline int __attribute__((__always_inline__, __nodebug__))
_mm256_extract_epi32(__m256i a, int const imm)
@@ -448,17 +448,17 @@
#define _mm256_insertf128_pd(V1, V2, O) __extension__ ({ \
__m256d __V1 = (V1); \
__m128d __V2 = (V2); \
- (__m256d)__builtin_ia32_vinsertf128_pd256((__v4df)__V1, (__v2df)__V2, O); })
+ (__m256d)__builtin_ia32_vinsertf128_pd256((__v4df)__V1, (__v2df)__V2, (O)); })
#define _mm256_insertf128_ps(V1, V2, O) __extension__ ({ \
__m256 __V1 = (V1); \
__m128 __V2 = (V2); \
- (__m256)__builtin_ia32_vinsertf128_ps256((__v8sf)__V1, (__v4sf)__V2, O); })
+ (__m256)__builtin_ia32_vinsertf128_ps256((__v8sf)__V1, (__v4sf)__V2, (O)); })
#define _mm256_insertf128_si256(V1, V2, O) __extension__ ({ \
__m256i __V1 = (V1); \
__m128i __V2 = (V2); \
- (__m256i)__builtin_ia32_vinsertf128_si256((__v8si)__V1, (__v4si)__V2, O); })
+ (__m256i)__builtin_ia32_vinsertf128_si256((__v8si)__V1, (__v4si)__V2, (O)); })
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
_mm256_insert_epi32(__m256i a, int b, int const imm)
Modified: cfe/branches/tooling/lib/Headers/immintrin.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Headers/immintrin.h?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Headers/immintrin.h (original)
+++ cfe/branches/tooling/lib/Headers/immintrin.h Fri Jan 20 10:14:22 2012
@@ -48,7 +48,7 @@
#include <smmintrin.h>
#endif
-#if defined (__AES__) || defined (__PCLMUL__)
+#if defined (__AES__)
#include <wmmintrin.h>
#endif
@@ -56,4 +56,20 @@
#include <avxintrin.h>
#endif
+#ifdef __AVX2__
+#include <avx2intrin.h>
+#endif
+
+#ifdef __BMI__
+#include <bmiintrin.h>
+#endif
+
+#ifdef __BMI2__
+#include <bmi2intrin.h>
+#endif
+
+#ifdef __LZCNT__
+#include <lzcntintrin.h>
+#endif
+
#endif /* __IMMINTRIN_H */
Modified: cfe/branches/tooling/lib/Headers/smmintrin.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Headers/smmintrin.h?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Headers/smmintrin.h (original)
+++ cfe/branches/tooling/lib/Headers/smmintrin.h Fri Jan 20 10:14:22 2012
@@ -245,7 +245,7 @@
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_epi64(__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pcmpeqq((__v2di)__V1, (__v2di)__V2);
+ return (__m128i)((__v2di)__V1 == (__v2di)__V2);
}
/* SSE4 Packed Integer Sign-Extension. */
@@ -398,7 +398,7 @@
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_epi64(__m128i __V1, __m128i __V2)
{
- return __builtin_ia32_pcmpgtq((__v2di)__V1, (__v2di)__V2);
+ return (__m128i)((__v2di)__V1 > (__v2di)__V2);
}
/* SSE4.2 Accumulate CRC32. */
@@ -428,20 +428,9 @@
}
#endif /* __x86_64__ */
-/* SSE4.2 Population Count. */
-static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_popcnt_u32(unsigned int __A)
-{
- return __builtin_popcount(__A);
-}
-
-#ifdef __x86_64__
-static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_popcnt_u64(unsigned long long __A)
-{
- return __builtin_popcountll(__A);
-}
-#endif /* __x86_64__ */
+#ifdef __POPCNT__
+#include <popcntintrin.h>
+#endif
#endif /* __SSE4_2__ */
#endif /* __SSE4_1__ */
Modified: cfe/branches/tooling/lib/Headers/unwind.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Headers/unwind.h?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Headers/unwind.h (original)
+++ cfe/branches/tooling/lib/Headers/unwind.h Fri Jan 20 10:14:22 2012
@@ -23,7 +23,8 @@
/* See "Data Definitions for libgcc_s" in the Linux Standard Base.*/
-#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1070
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1070
/* Starting in OS X Lion the SDK includes a unwind.h. We should just use it. */
#include_next <unwind.h>
#else
@@ -54,7 +55,42 @@
_URC_CONTINUE_UNWIND = 8
} _Unwind_Reason_Code;
+
+#ifdef __arm__
+
+typedef enum {
+ _UVRSC_CORE = 0, /* integer register */
+ _UVRSC_VFP = 1, /* vfp */
+ _UVRSC_WMMXD = 3, /* Intel WMMX data register */
+ _UVRSC_WMMXC = 4 /* Intel WMMX control register */
+} _Unwind_VRS_RegClass;
+
+typedef enum {
+ _UVRSD_UINT32 = 0,
+ _UVRSD_VFPX = 1,
+ _UVRSD_UINT64 = 3,
+ _UVRSD_FLOAT = 4,
+ _UVRSD_DOUBLE = 5
+} _Unwind_VRS_DataRepresentation;
+
+typedef enum {
+ _UVRSR_OK = 0,
+ _UVRSR_NOT_IMPLEMENTED = 1,
+ _UVRSR_FAILED = 2
+} _Unwind_VRS_Result;
+
+_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
+ _Unwind_VRS_RegClass regclass,
+ uint32_t regno,
+ _Unwind_VRS_DataRepresentation representation,
+ void *valuep);
+
+#else
+
uintptr_t _Unwind_GetIP(struct _Unwind_Context* context);
+
+#endif
+
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context*, void*);
_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*);
Modified: cfe/branches/tooling/lib/Headers/x86intrin.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Headers/x86intrin.h?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Headers/x86intrin.h (original)
+++ cfe/branches/tooling/lib/Headers/x86intrin.h Fri Jan 20 10:14:22 2012
@@ -26,6 +26,26 @@
#include <immintrin.h>
-// FIXME: SSE4A, 3dNOW, FMA4, XOP, LWP, ABM, POPCNT
+#ifdef __BMI__
+#include <bmiintrin.h>
+#endif
+
+#ifdef __BMI2__
+#include <bmi2intrin.h>
+#endif
+
+#ifdef __LZCNT__
+#include <lzcntintrin.h>
+#endif
+
+#ifdef __POPCNT__
+#include <popcntintrin.h>
+#endif
+
+#ifdef __FMA4__
+#include <fma4intrin.h>
+#endif
+
+// FIXME: SSE4A, 3dNOW, XOP, LWP, ABM
#endif /* __X86INTRIN_H */
Modified: cfe/branches/tooling/lib/Headers/xmmintrin.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Headers/xmmintrin.h?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Headers/xmmintrin.h (original)
+++ cfe/branches/tooling/lib/Headers/xmmintrin.h Fri Jan 20 10:14:22 2012
@@ -664,7 +664,7 @@
/* FIXME: We have to #define this because "sel" must be a constant integer, and
Sema doesn't do any form of constant propagation yet. */
-#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), 0, sel))
+#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), 0, (sel)))
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_stream_pi(__m64 *p, __m64 a)
Modified: cfe/branches/tooling/lib/Index/ASTLocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Index/ASTLocation.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Index/ASTLocation.cpp (original)
+++ cfe/branches/tooling/lib/Index/ASTLocation.cpp Fri Jan 20 10:14:22 2012
@@ -41,7 +41,6 @@
return 0;
switch (getKind()) {
- default: llvm_unreachable("Invalid Kind");
case N_Type:
return 0;
case N_Decl:
@@ -60,7 +59,6 @@
return SourceRange();
switch (getKind()) {
- default: llvm_unreachable("Invalid Kind");
case N_Decl:
return D->getSourceRange();
case N_Stmt:
Modified: cfe/branches/tooling/lib/Lex/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/CMakeLists.txt?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/CMakeLists.txt (original)
+++ cfe/branches/tooling/lib/Lex/CMakeLists.txt Fri Jan 20 10:14:22 2012
@@ -13,6 +13,7 @@
MacroInfo.cpp
ModuleMap.cpp
PPCaching.cpp
+ PPCallbacks.cpp
PPDirectives.cpp
PPExpressions.cpp
PPLexerChange.cpp
Modified: cfe/branches/tooling/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/HeaderSearch.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/branches/tooling/lib/Lex/HeaderSearch.cpp Fri Jan 20 10:14:22 2012
@@ -38,9 +38,10 @@
ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
-HeaderSearch::HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags)
+HeaderSearch::HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags,
+ const LangOptions &LangOpts)
: FileMgr(FM), Diags(Diags), FrameworkMap(64),
- ModMap(FileMgr, *Diags.getClient())
+ ModMap(FileMgr, *Diags.getClient(), LangOpts)
{
AngledDirIdx = 0;
SystemDirIdx = 0;
@@ -798,13 +799,11 @@
// having module maps if we eventually do find a module map.
FixUpDirectories.push_back(Dir);
} while (true);
-
- return false;
}
Module *HeaderSearch::findModuleForHeader(const FileEntry *File) {
- if (Module *Module = ModMap.findModuleForHeader(File))
- return Module;
+ if (Module *Mod = ModMap.findModuleForHeader(File))
+ return Mod;
return 0;
}
@@ -859,7 +858,7 @@
}
Module *HeaderSearch::getFrameworkModule(StringRef Name,
- const DirectoryEntry *Dir) {
+ const DirectoryEntry *Dir) {
if (Module *Module = ModMap.findModule(Name))
return Module;
@@ -875,9 +874,50 @@
case LMM_NewlyLoaded:
return ModMap.findModule(Name);
}
+
+ // The top-level framework directory, from which we'll infer a framework
+ // module.
+ const DirectoryEntry *TopFrameworkDir = Dir;
+
+ // The path from the module we're actually looking for back to the top-level
+ // framework name.
+ llvm::SmallVector<StringRef, 2> SubmodulePath;
+ SubmodulePath.push_back(Name);
- // Try to infer a module map.
- return ModMap.inferFrameworkModule(Name, Dir, /*Parent=*/0);
+ // Walk the directory structure to find any enclosing frameworks.
+ StringRef DirName = Dir->getName();
+ do {
+ // Get the parent directory name.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ break;
+
+ // Determine whether this directory exists.
+ Dir = FileMgr.getDirectory(DirName);
+ if (!Dir)
+ break;
+
+ // If this is a framework directory, then we're a subframework of this
+ // framework.
+ if (llvm::sys::path::extension(DirName) == ".framework") {
+ SubmodulePath.push_back(llvm::sys::path::stem(DirName));
+ TopFrameworkDir = Dir;
+ }
+ } while (true);
+
+ // Try to infer a module map from the top-level framework directory.
+ Module *Result = ModMap.inferFrameworkModule(SubmodulePath.back(),
+ TopFrameworkDir,
+ /*Parent=*/0);
+
+ // Follow the submodule path to find the requested (sub)framework module
+ // within the top-level framework module.
+ SubmodulePath.pop_back();
+ while (!SubmodulePath.empty() && Result) {
+ Result = ModMap.lookupModuleQualified(SubmodulePath.back(), Result);
+ SubmodulePath.pop_back();
+ }
+ return Result;
}
Modified: cfe/branches/tooling/lib/Lex/Lexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/Lexer.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/Lexer.cpp (original)
+++ cfe/branches/tooling/lib/Lex/Lexer.cpp Fri Jan 20 10:14:22 2012
@@ -59,6 +59,8 @@
// Lexer Class Implementation
//===----------------------------------------------------------------------===//
+void Lexer::anchor() { }
+
void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
const char *BufEnd) {
InitCharacterInfo();
@@ -487,11 +489,11 @@
SourceLocation FileLoc = SM.getSpellingLoc(Loc);
SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts);
std::pair<FileID, unsigned> FileLocInfo = SM.getDecomposedLoc(FileLoc);
- std::pair<FileID, unsigned> BeginFileLocInfo= SM.getDecomposedLoc(BeginFileLoc);
+ std::pair<FileID, unsigned> BeginFileLocInfo
+ = SM.getDecomposedLoc(BeginFileLoc);
assert(FileLocInfo.first == BeginFileLocInfo.first &&
FileLocInfo.second >= BeginFileLocInfo.second);
- return Loc.getLocWithOffset(SM.getDecomposedLoc(BeginFileLoc).second -
- SM.getDecomposedLoc(FileLoc).second);
+ return Loc.getLocWithOffset(BeginFileLocInfo.second - FileLocInfo.second);
}
namespace {
@@ -718,11 +720,8 @@
return SourceLocation();
if (Loc.isMacroID()) {
- if (Offset > 0 || !isAtEndOfMacroExpansion(Loc, SM, Features))
+ if (Offset > 0 || !isAtEndOfMacroExpansion(Loc, SM, Features, &Loc))
return SourceLocation(); // Points inside the macro expansion.
-
- // Continue and find the location just after the macro expansion.
- Loc = SM.getExpansionRange(Loc).second;
}
unsigned Len = Lexer::MeasureTokenLength(Loc, SM, Features);
@@ -738,7 +737,8 @@
/// token of the macro expansion.
bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc,
const SourceManager &SM,
- const LangOptions &LangOpts) {
+ const LangOptions &LangOpts,
+ SourceLocation *MacroBegin) {
assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
std::pair<FileID, unsigned> infoLoc = SM.getDecomposedLoc(loc);
@@ -749,17 +749,22 @@
SourceLocation expansionLoc =
SM.getSLocEntry(infoLoc.first).getExpansion().getExpansionLocStart();
- if (expansionLoc.isFileID())
- return true; // No other macro expansions, this is the first.
+ if (expansionLoc.isFileID()) {
+ // No other macro expansions, this is the first.
+ if (MacroBegin)
+ *MacroBegin = expansionLoc;
+ return true;
+ }
- return isAtStartOfMacroExpansion(expansionLoc, SM, LangOpts);
+ return isAtStartOfMacroExpansion(expansionLoc, SM, LangOpts, MacroBegin);
}
/// \brief Returns true if the given MacroID location points at the last
/// token of the macro expansion.
bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc,
- const SourceManager &SM,
- const LangOptions &LangOpts) {
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ SourceLocation *MacroEnd) {
assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
SourceLocation spellLoc = SM.getSpellingLoc(loc);
@@ -777,10 +782,106 @@
SourceLocation expansionLoc =
SM.getSLocEntry(FID).getExpansion().getExpansionLocEnd();
- if (expansionLoc.isFileID())
- return true; // No other macro expansions.
+ if (expansionLoc.isFileID()) {
+ // No other macro expansions.
+ if (MacroEnd)
+ *MacroEnd = expansionLoc;
+ return true;
+ }
- return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts);
+ return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts, MacroEnd);
+}
+
+/// \brief Accepts a token source range and returns a character range with
+/// file locations.
+/// Returns a null range if a part of the range resides inside a macro
+/// expansion or the range does not reside on the same FileID.
+CharSourceRange Lexer::makeFileCharRange(SourceRange TokenRange,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ SourceLocation Begin = TokenRange.getBegin();
+ if (Begin.isInvalid())
+ return CharSourceRange();
+
+ if (Begin.isMacroID())
+ if (!isAtStartOfMacroExpansion(Begin, SM, LangOpts, &Begin))
+ return CharSourceRange();
+
+ SourceLocation End = getLocForEndOfToken(TokenRange.getEnd(), 0, SM,LangOpts);
+ if (End.isInvalid())
+ return CharSourceRange();
+
+ // Break down the source locations.
+ std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(Begin);
+ if (beginInfo.first.isInvalid())
+ return CharSourceRange();
+
+ unsigned EndOffs;
+ if (!SM.isInFileID(End, beginInfo.first, &EndOffs) ||
+ beginInfo.second > EndOffs)
+ return CharSourceRange();
+
+ return CharSourceRange::getCharRange(Begin, End);
+}
+
+StringRef Lexer::getSourceText(CharSourceRange Range,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ bool *Invalid) {
+ if (Range.isTokenRange())
+ Range = makeFileCharRange(Range.getAsRange(), SM, LangOpts);
+
+ if (Range.isInvalid() ||
+ Range.getBegin().isMacroID() || Range.getEnd().isMacroID()) {
+ if (Invalid) *Invalid = true;
+ return StringRef();
+ }
+
+ // Break down the source location.
+ std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(Range.getBegin());
+ if (beginInfo.first.isInvalid()) {
+ if (Invalid) *Invalid = true;
+ return StringRef();
+ }
+
+ unsigned EndOffs;
+ if (!SM.isInFileID(Range.getEnd(), beginInfo.first, &EndOffs) ||
+ beginInfo.second > EndOffs) {
+ if (Invalid) *Invalid = true;
+ return StringRef();
+ }
+
+ // Try to the load the file buffer.
+ bool invalidTemp = false;
+ StringRef file = SM.getBufferData(beginInfo.first, &invalidTemp);
+ if (invalidTemp) {
+ if (Invalid) *Invalid = true;
+ return StringRef();
+ }
+
+ if (Invalid) *Invalid = false;
+ return file.substr(beginInfo.second, EndOffs - beginInfo.second);
+}
+
+StringRef Lexer::getImmediateMacroName(SourceLocation Loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ assert(Loc.isMacroID() && "Only reasonble to call this on macros");
+ // Walk past macro argument expanions.
+ while (SM.isMacroArgExpansion(Loc))
+ Loc = SM.getImmediateExpansionRange(Loc).first;
+
+ // Find the spelling location of the start of the non-argument expansion
+ // range. This is where the macro name was spelled in order to begin
+ // expanding this macro.
+ Loc = SM.getSpellingLoc(SM.getImmediateExpansionRange(Loc).first);
+
+ // Dig out the buffer where the macro name was spelled and the extents of the
+ // name so that we can render it into the expansion note.
+ std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc);
+ unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
+ StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first);
+ return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
}
//===----------------------------------------------------------------------===//
@@ -1085,9 +1186,8 @@
const LangOptions &LangOpts,
bool SkipTrailingWhitespaceAndNewLine) {
if (Loc.isMacroID()) {
- if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts))
+ if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
return SourceLocation();
- Loc = SM.getExpansionRange(Loc).second;
}
Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
@@ -1169,6 +1269,13 @@
// Found backslash<whitespace><newline>. Parse the char after it.
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
+
+ // If the char that we finally got was a \n, then we must have had
+ // something like \<newline><newline>. We don't want to consume the
+ // second newline.
+ if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
+ return ' ';
+
// Use slow version to accumulate a correct size field.
return getCharAndSizeSlow(Ptr, Size, Tok);
}
@@ -1220,6 +1327,12 @@
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
+ // If the char that we finally got was a \n, then we must have had
+ // something like \<newline><newline>. We don't want to consume the
+ // second newline.
+ if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
+ return ' ';
+
// Use slow version to accumulate a correct size field.
return getCharAndSizeSlowNoWarn(Ptr, Size, Features);
}
@@ -1687,14 +1800,6 @@
break;
}
- // If the char that we finally got was a \n, then we must have had something
- // like \<newline><newline>. We don't want to have consumed the second
- // newline, we want CurPtr, to end up pointing to it down below.
- if (C == '\n' || C == '\r') {
- --CurPtr;
- C = 'x'; // doesn't matter what this is.
- }
-
// If we read multiple characters, and one of those characters was a \r or
// \n, then we had an escaped newline within the comment. Emit diagnostic
// unless the next line is also a // comment.
Modified: cfe/branches/tooling/lib/Lex/LiteralSupport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/LiteralSupport.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/LiteralSupport.cpp (original)
+++ cfe/branches/tooling/lib/Lex/LiteralSupport.cpp Fri Jan 20 10:14:22 2012
@@ -182,7 +182,8 @@
static bool ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
uint32_t &UcnVal, unsigned short &UcnLen,
FullSourceLoc Loc, DiagnosticsEngine *Diags,
- const LangOptions &Features) {
+ const LangOptions &Features,
+ bool in_char_string_literal = false) {
if (!Features.CPlusPlus && !Features.C99 && Diags)
Diags->Report(Loc, diag::warn_ucn_not_valid_in_c89);
@@ -216,11 +217,20 @@
}
return false;
}
- // Check UCN constraints (C99 6.4.3p2).
- if ((UcnVal < 0xa0 &&
- (UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60 )) // $, @, `
- || (UcnVal >= 0xD800 && UcnVal <= 0xDFFF)
- || (UcnVal > 0x10FFFF)) /* the maximum legal UTF32 value */ {
+ // Check UCN constraints (C99 6.4.3p2) [C++11 lex.charset p2]
+ bool invalid_ucn = (0xD800<=UcnVal && UcnVal<=0xDFFF) // surrogate codepoints
+ || 0x10FFFF < UcnVal; // maximum legal UTF32 value
+
+ // C++11 allows UCNs that refer to control characters and basic source
+ // characters inside character and string literals
+ if (!Features.CPlusPlus0x || !in_char_string_literal) {
+ if ((UcnVal < 0xa0 &&
+ (UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60 ))) { // $, @, `
+ invalid_ucn = true;
+ }
+ }
+
+ if (invalid_ucn) {
if (Diags)
Diags->Report(Loc, diag::err_ucn_escape_invalid);
return false;
@@ -271,8 +281,6 @@
ResultBuf += 2;
return;
}
- // FIXME: We shouldn't print a diagnostic for UTF-16 mode.
- if (Diags) Diags->Report(Loc, diag::warn_ucn_escape_too_large);
// Convert to UTF16.
UcnVal -= 0x10000;
@@ -747,14 +755,13 @@
CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
SourceLocation Loc, Preprocessor &PP,
tok::TokenKind kind) {
- // At this point we know that the character matches the regex "L?'.*'".
+ // At this point we know that the character matches the regex "(L|u|U)?'.*'".
HadError = false;
Kind = kind;
- // Determine if this is a wide or UTF character.
- if (Kind == tok::wide_char_constant || Kind == tok::utf16_char_constant ||
- Kind == tok::utf32_char_constant) {
+ // Skip over wide character determinant.
+ if (Kind != tok::char_constant) {
++begin;
}
@@ -762,6 +769,10 @@
assert(begin[0] == '\'' && "Invalid token lexed");
++begin;
+ // Trim the ending quote.
+ assert(end[-1] == '\'' && "Invalid token lexed");
+ --end;
+
// FIXME: The "Value" is an uint64_t so we can handle char literals of
// up to 64-bits.
// FIXME: This extensively assumes that 'char' is 8-bits.
@@ -773,76 +784,114 @@
assert(PP.getTargetInfo().getWCharWidth() <= 64 &&
"Assumes sizeof(wchar) on target is <= 64");
- // This is what we will use for overflow detection
- llvm::APInt LitVal(PP.getTargetInfo().getIntWidth(), 0);
-
- unsigned NumCharsSoFar = 0;
- bool Warned = false;
- while (begin[0] != '\'') {
- uint64_t ResultChar;
-
- // Is this a Universal Character Name escape?
- if (begin[0] != '\\') // If this is a normal character, consume it.
- ResultChar = (unsigned char)*begin++;
- else { // Otherwise, this is an escape character.
- unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo());
- // Check for UCN.
- if (begin[1] == 'u' || begin[1] == 'U') {
- uint32_t utf32 = 0;
- unsigned short UcnLen = 0;
- if (!ProcessUCNEscape(begin, end, utf32, UcnLen,
- FullSourceLoc(Loc, PP.getSourceManager()),
- &PP.getDiagnostics(), PP.getLangOptions())) {
- HadError = 1;
- }
- ResultChar = utf32;
- if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
- PP.Diag(Loc, diag::warn_ucn_escape_too_large);
- ResultChar &= ~0U >> (32-CharWidth);
- }
+ SmallVector<uint32_t,4> codepoint_buffer;
+ codepoint_buffer.resize(end-begin);
+ uint32_t *buffer_begin = &codepoint_buffer.front();
+ uint32_t *buffer_end = buffer_begin + codepoint_buffer.size();
+
+ // Unicode escapes representing characters that cannot be correctly
+ // represented in a single code unit are disallowed in character literals
+ // by this implementation.
+ uint32_t largest_character_for_kind;
+ if (tok::wide_char_constant == Kind) {
+ largest_character_for_kind = 0xFFFFFFFFu >> (32-PP.getTargetInfo().getWCharWidth());
+ } else if (tok::utf16_char_constant == Kind) {
+ largest_character_for_kind = 0xFFFF;
+ } else if (tok::utf32_char_constant == Kind) {
+ largest_character_for_kind = 0x10FFFF;
+ } else {
+ largest_character_for_kind = 0x7Fu;
+ }
+
+ while (begin!=end) {
+ // Is this a span of non-escape characters?
+ if (begin[0] != '\\') {
+ char const *start = begin;
+ do {
+ ++begin;
+ } while (begin != end && *begin != '\\');
+
+ uint32_t *tmp_begin = buffer_begin;
+ ConversionResult res =
+ ConvertUTF8toUTF32(reinterpret_cast<UTF8 const **>(&start),
+ reinterpret_cast<UTF8 const *>(begin),
+ &buffer_begin,buffer_end,strictConversion);
+ if (res!=conversionOK) {
+ PP.Diag(Loc, diag::err_bad_character_encoding);
+ HadError = true;
} else {
- // Otherwise, this is a non-UCN escape character. Process it.
- ResultChar = ProcessCharEscape(begin, end, HadError,
- FullSourceLoc(Loc,PP.getSourceManager()),
- CharWidth, &PP.getDiagnostics());
- }
- }
-
- // If this is a multi-character constant (e.g. 'abc'), handle it. These are
- // implementation defined (C99 6.4.4.4p10).
- if (NumCharsSoFar) {
- if (!isAscii()) {
- // Emulate GCC's (unintentional?) behavior: L'ab' -> L'b'.
- LitVal = 0;
- } else {
- // Narrow character literals act as though their value is concatenated
- // in this implementation, but warn on overflow.
- if (LitVal.countLeadingZeros() < 8 && !Warned) {
- PP.Diag(Loc, diag::warn_char_constant_too_large);
- Warned = true;
+ for (; tmp_begin<buffer_begin; ++tmp_begin) {
+ if (*tmp_begin > largest_character_for_kind) {
+ HadError = true;
+ PP.Diag(Loc, diag::err_character_too_large);
+ }
}
- LitVal <<= 8;
}
+
+ continue;
}
+ // Is this a Universal Character Name excape?
+ if (begin[1] == 'u' || begin[1] == 'U') {
+ unsigned short UcnLen = 0;
+ if (!ProcessUCNEscape(begin, end, *buffer_begin, UcnLen,
+ FullSourceLoc(Loc, PP.getSourceManager()),
+ &PP.getDiagnostics(), PP.getLangOptions(),
+ true))
+ {
+ HadError = true;
+ } else if (*buffer_begin > largest_character_for_kind) {
+ HadError = true;
+ PP.Diag(Loc,diag::err_character_too_large);
+ }
- LitVal = LitVal + ResultChar;
- ++NumCharsSoFar;
+ ++buffer_begin;
+ continue;
+ }
+ unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo());
+ uint64_t result =
+ ProcessCharEscape(begin, end, HadError,
+ FullSourceLoc(Loc,PP.getSourceManager()),
+ CharWidth, &PP.getDiagnostics());
+ *buffer_begin++ = result;
}
- // If this is the second character being processed, do special handling.
+ unsigned NumCharsSoFar = buffer_begin-&codepoint_buffer.front();
+
if (NumCharsSoFar > 1) {
- // Warn about discarding the top bits for multi-char wide-character
- // constants (L'abcd').
- if (!isAscii())
+ if (isWide())
PP.Diag(Loc, diag::warn_extraneous_char_constant);
- else if (NumCharsSoFar != 4)
+ else if (isAscii() && NumCharsSoFar == 4)
+ PP.Diag(Loc, diag::ext_four_char_character_literal);
+ else if (isAscii())
PP.Diag(Loc, diag::ext_multichar_character_literal);
else
- PP.Diag(Loc, diag::ext_four_char_character_literal);
+ PP.Diag(Loc, diag::err_multichar_utf_character_literal);
IsMultiChar = true;
} else
IsMultiChar = false;
+ llvm::APInt LitVal(PP.getTargetInfo().getIntWidth(), 0);
+
+ // Narrow character literals act as though their value is concatenated
+ // in this implementation, but warn on overflow.
+ bool multi_char_too_long = false;
+ if (isAscii() && isMultiChar()) {
+ LitVal = 0;
+ for (size_t i=0;i<NumCharsSoFar;++i) {
+ // check for enough leading zeros to shift into
+ multi_char_too_long |= (LitVal.countLeadingZeros() < 8);
+ LitVal <<= 8;
+ LitVal = LitVal + (codepoint_buffer[i] & 0xFF);
+ }
+ } else if (NumCharsSoFar > 0) {
+ // otherwise just take the last character
+ LitVal = buffer_begin[-1];
+ }
+
+ if (!HadError && multi_char_too_long) {
+ PP.Diag(Loc,diag::warn_char_constant_too_large);
+ }
+
// Transfer the value from APInt to uint64_t
Value = LitVal.getZExtValue();
Modified: cfe/branches/tooling/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/ModuleMap.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/ModuleMap.cpp (original)
+++ cfe/branches/tooling/lib/Lex/ModuleMap.cpp Fri Jan 20 10:14:22 2012
@@ -69,7 +69,10 @@
return Module::ExportDecl(Context, Unresolved.Wildcard);
}
-ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC) {
+ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
+ const LangOptions &LangOpts)
+ : LangOpts(LangOpts)
+{
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
Diags = llvm::IntrusiveRefCntPtr<DiagnosticsEngine>(
new DiagnosticsEngine(DiagIDs));
@@ -90,8 +93,14 @@
Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
llvm::DenseMap<const FileEntry *, Module *>::iterator Known
= Headers.find(File);
- if (Known != Headers.end())
+ if (Known != Headers.end()) {
+ // If a header corresponds to an unavailable module, don't report
+ // that it maps to anything.
+ if (!Known->second->isAvailable())
+ return 0;
+
return Known->second;
+ }
const DirectoryEntry *Dir = File->getDir();
llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
@@ -110,7 +119,7 @@
Module *UmbrellaModule = Result;
while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
UmbrellaModule = UmbrellaModule->Parent;
-
+
if (UmbrellaModule->InferSubmodules) {
// Infer submodules for each of the directories we found between
// the directory of the umbrella header and the directory where
@@ -149,6 +158,12 @@
}
Headers[File] = Result;
+
+ // If a header corresponds to an unavailable module, don't report
+ // that it maps to anything.
+ if (!Result->isAvailable())
+ return 0;
+
return Result;
}
@@ -166,6 +181,67 @@
return 0;
}
+bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
+ llvm::DenseMap<const FileEntry *, Module *>::iterator Known
+ = Headers.find(Header);
+ if (Known != Headers.end())
+ return !Known->second->isAvailable();
+
+ const DirectoryEntry *Dir = Header->getDir();
+ llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
+ StringRef DirName = Dir->getName();
+
+ // Keep walking up the directory hierarchy, looking for a directory with
+ // an umbrella header.
+ do {
+ llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
+ = UmbrellaDirs.find(Dir);
+ if (KnownDir != UmbrellaDirs.end()) {
+ Module *Found = KnownDir->second;
+ if (!Found->isAvailable())
+ return true;
+
+ // Search up the module stack until we find a module with an umbrella
+ // directory.
+ Module *UmbrellaModule = Found;
+ while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
+ UmbrellaModule = UmbrellaModule->Parent;
+
+ if (UmbrellaModule->InferSubmodules) {
+ for (unsigned I = SkippedDirs.size(); I != 0; --I) {
+ // Find or create the module that corresponds to this directory name.
+ StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+ Found = lookupModuleQualified(Name, Found);
+ if (!Found)
+ return false;
+ if (!Found->isAvailable())
+ return true;
+ }
+
+ // Infer a submodule with the same name as this header file.
+ StringRef Name = llvm::sys::path::stem(Header->getName());
+ Found = lookupModuleQualified(Name, Found);
+ if (!Found)
+ return false;
+ }
+
+ return !Found->isAvailable();
+ }
+
+ SkippedDirs.push_back(Dir);
+
+ // Retrieve our parent path.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ break;
+
+ // Resolve the parent path to a directory entry.
+ Dir = SourceMgr->getFileManager().getDirectory(DirName);
+ } while (Dir);
+
+ return false;
+}
+
Module *ModuleMap::findModule(StringRef Name) {
llvm::StringMap<Module *>::iterator Known = Modules.find(Name);
if (Known != Modules.end())
@@ -187,26 +263,20 @@
if (!Context)
return findModule(Name);
- llvm::StringMap<Module *>::iterator Sub = Context->SubModules.find(Name);
- if (Sub != Context->SubModules.end())
- return Sub->getValue();
-
- return 0;
+ return Context->findSubmodule(Name);
}
std::pair<Module *, bool>
ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
bool IsExplicit) {
// Try to find an existing module with this name.
- if (Module *Found = Parent? Parent->SubModules[Name] : Modules[Name])
- return std::make_pair(Found, false);
+ if (Module *Sub = lookupModuleQualified(Name, Parent))
+ return std::make_pair(Sub, false);
// Create a new module with this name.
Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
IsExplicit);
- if (Parent)
- Parent->SubModules[Name] = Result;
- else
+ if (!Parent)
Modules[Name] = Result;
return std::make_pair(Result, true);
}
@@ -235,12 +305,9 @@
Module *Result = new Module(ModuleName, SourceLocation(), Parent,
/*IsFramework=*/true, /*IsExplicit=*/false);
-
- if (Parent)
- Parent->SubModules[ModuleName] = Result;
- else
+ if (!Parent)
Modules[ModuleName] = Result;
-
+
// umbrella header "umbrella-header-name"
Result->Umbrella = UmbrellaHeader;
Headers[UmbrellaHeader] = Result;
@@ -274,20 +341,7 @@
Result);
}
}
-
- // Look for private headers.
- llvm::SmallString<128> PrivateHeadersDirName(FrameworkDir->getName());
- llvm::sys::path::append(PrivateHeadersDirName, "PrivateHeaders");
- if (const DirectoryEntry *Dir = FileMgr.getDirectory(PrivateHeadersDirName)) {
- Module *Private = findOrCreateModule("Private", Result,
- /*IsFramework=*/false,
- /*IsExplicit=*/true).first;
- setUmbrellaDir(Private, Dir);
- Private->InferSubmodules = true;
- Private->InferExplicitSubmodules = true;
- Private->InferExportWildcard = true;
- }
-
+
return Result;
}
@@ -359,12 +413,23 @@
const SourceManager &SrcMgr = Loc.getManager();
FileID ExpansionFileID = ExpansionLoc.getFileID();
- const FileEntry *ExpansionFile = SrcMgr.getFileEntryForID(ExpansionFileID);
- if (!ExpansionFile)
- return 0;
- // Find the module that owns this header.
- return findModuleForHeader(ExpansionFile);
+ while (const FileEntry *ExpansionFile
+ = SrcMgr.getFileEntryForID(ExpansionFileID)) {
+ // Find the module that owns this header (if any).
+ if (Module *Mod = findModuleForHeader(ExpansionFile))
+ return Mod;
+
+ // No module owns this header, so look up the inclusion chain to see if
+ // any included header has an associated module.
+ SourceLocation IncludeLoc = SrcMgr.getIncludeLoc(ExpansionFileID);
+ if (IncludeLoc.isInvalid())
+ return 0;
+
+ ExpansionFileID = SrcMgr.getFileID(IncludeLoc);
+ }
+
+ return 0;
}
//----------------------------------------------------------------------------//
@@ -375,6 +440,7 @@
/// \brief A token in a module map file.
struct MMToken {
enum TokenKind {
+ Comma,
EndOfFile,
HeaderKeyword,
Identifier,
@@ -384,6 +450,7 @@
ModuleKeyword,
Period,
UmbrellaKeyword,
+ RequiresKeyword,
Star,
StringLiteral,
LBrace,
@@ -449,6 +516,7 @@
ModuleId;
bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
+ void parseRequiresDecl();
void parseHeaderDecl(SourceLocation UmbrellaLoc);
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
@@ -494,10 +562,15 @@
.Case("export", MMToken::ExportKeyword)
.Case("framework", MMToken::FrameworkKeyword)
.Case("module", MMToken::ModuleKeyword)
+ .Case("requires", MMToken::RequiresKeyword)
.Case("umbrella", MMToken::UmbrellaKeyword)
.Default(MMToken::Identifier);
break;
-
+
+ case tok::comma:
+ Tok.Kind = MMToken::Comma;
+ break;
+
case tok::eof:
Tok.Kind = MMToken::EndOfFile;
break;
@@ -614,6 +687,7 @@
/// 'explicit'[opt] 'framework'[opt] 'module' module-id { module-member* }
///
/// module-member:
+/// requires-declaration
/// header-declaration
/// submodule-declaration
/// export-declaration
@@ -713,15 +787,23 @@
SourceLocation LBraceLoc = consumeToken();
// Determine whether this (sub)module has already been defined.
- llvm::StringMap<Module *> &ModuleSpace
- = ActiveModule? ActiveModule->SubModules : Map.Modules;
- llvm::StringMap<Module *>::iterator ExistingModule
- = ModuleSpace.find(ModuleName);
- if (ExistingModule != ModuleSpace.end()) {
+ if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) {
+ if (Existing->DefinitionLoc.isInvalid() && !ActiveModule) {
+ // Skip the module definition.
+ skipUntil(MMToken::RBrace);
+ if (Tok.is(MMToken::RBrace))
+ consumeToken();
+ else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
+ Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
+ HadError = true;
+ }
+ return;
+ }
+
Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)
<< ModuleName;
- Diags.Report(ExistingModule->getValue()->DefinitionLoc,
- diag::note_mmap_prev_definition);
+ Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition);
// Skip the module definition.
skipUntil(MMToken::RBrace);
@@ -733,9 +815,9 @@
}
// Start defining this module.
- ActiveModule = new Module(ModuleName, ModuleNameLoc, ActiveModule, Framework,
- Explicit);
- ModuleSpace[ModuleName] = ActiveModule;
+ ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
+ Explicit).first;
+ ActiveModule->DefinitionLoc = ModuleNameLoc;
bool Done = false;
do {
@@ -755,6 +837,10 @@
parseExportDecl();
break;
+ case MMToken::RequiresKeyword:
+ parseRequiresDecl();
+ break;
+
case MMToken::UmbrellaKeyword: {
SourceLocation UmbrellaLoc = consumeToken();
if (Tok.is(MMToken::HeaderKeyword))
@@ -787,6 +873,43 @@
ActiveModule = PreviousActiveModule;
}
+/// \brief Parse a requires declaration.
+///
+/// requires-declaration:
+/// 'requires' feature-list
+///
+/// feature-list:
+/// identifier ',' feature-list
+/// identifier
+void ModuleMapParser::parseRequiresDecl() {
+ assert(Tok.is(MMToken::RequiresKeyword));
+
+ // Parse 'requires' keyword.
+ consumeToken();
+
+ // Parse the feature-list.
+ do {
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_feature);
+ HadError = true;
+ return;
+ }
+
+ // Consume the feature name.
+ std::string Feature = Tok.getString();
+ consumeToken();
+
+ // Add this feature.
+ ActiveModule->addRequirement(Feature, Map.LangOpts);
+
+ if (!Tok.is(MMToken::Comma))
+ break;
+
+ // Consume the comma.
+ consumeToken();
+ } while (true);
+}
+
/// \brief Append to \p Paths the set of paths needed to get to the
/// subframework in which the given module lives.
void appendSubframeworkPaths(Module *Mod, llvm::SmallVectorImpl<char> &Path) {
@@ -1123,12 +1246,14 @@
parseModuleDecl();
break;
+ case MMToken::Comma:
case MMToken::ExportKeyword:
case MMToken::HeaderKeyword:
case MMToken::Identifier:
case MMToken::LBrace:
case MMToken::Period:
case MMToken::RBrace:
+ case MMToken::RequiresKeyword:
case MMToken::Star:
case MMToken::StringLiteral:
case MMToken::UmbrellaKeyword:
@@ -1138,8 +1263,6 @@
break;
}
} while (true);
-
- return HadError;
}
bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
@@ -1149,8 +1272,8 @@
return true;
// Parse this module map file.
- Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, LangOpts);
- Diags->getClient()->BeginSourceFile(LangOpts);
+ Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
+ Diags->getClient()->BeginSourceFile(MMapLangOpts);
ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir());
bool Result = Parser.parseModuleMapFile();
Diags->getClient()->EndSourceFile();
Modified: cfe/branches/tooling/lib/Lex/PPCaching.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/PPCaching.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/PPCaching.cpp (original)
+++ cfe/branches/tooling/lib/Lex/PPCaching.cpp Fri Jan 20 10:14:22 2012
@@ -42,6 +42,7 @@
&& "EnableBacktrackAtThisPos was not called!");
CachedLexPos = BacktrackPositions.back();
BacktrackPositions.pop_back();
+ recomputeCurLexerKind();
}
void Preprocessor::CachingLex(Token &Result) {
@@ -74,8 +75,7 @@
return;
PushIncludeMacroStack();
- if (CurLexerKind != CLK_LexAfterModuleImport)
- CurLexerKind = CLK_CachingLexer;
+ CurLexerKind = CLK_CachingLexer;
}
Modified: cfe/branches/tooling/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/PPDirectives.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/PPDirectives.cpp (original)
+++ cfe/branches/tooling/lib/Lex/PPDirectives.cpp Fri Jan 20 10:14:22 2012
@@ -682,10 +682,15 @@
//isExtension = true; // FIXME: implement #unassert
break;
- case tok::pp___export_macro__:
- return HandleMacroExportDirective(Result);
- case tok::pp___private_macro__:
- return HandleMacroPrivateDirective(Result);
+ case tok::pp___public_macro:
+ if (getLangOptions().Modules)
+ return HandleMacroPublicDirective(Result);
+ break;
+
+ case tok::pp___private_macro:
+ if (getLangOptions().Modules)
+ return HandleMacroPrivateDirective(Result);
+ break;
}
break;
}
@@ -1038,8 +1043,8 @@
}
}
-/// \brief Handle a #__export_macro__ directive.
-void Preprocessor::HandleMacroExportDirective(Token &Tok) {
+/// \brief Handle a #public directive.
+void Preprocessor::HandleMacroPublicDirective(Token &Tok) {
Token MacroNameTok;
ReadMacroName(MacroNameTok, 2);
@@ -1047,8 +1052,8 @@
if (MacroNameTok.is(tok::eod))
return;
- // Check to see if this is the last token on the #__export_macro__ line.
- CheckEndOfDirective("__export_macro__");
+ // Check to see if this is the last token on the #__public_macro line.
+ CheckEndOfDirective("__public_macro");
// Okay, we finally have a valid identifier to undef.
MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
@@ -1069,7 +1074,7 @@
MI->setChangedAfterLoad();
}
-/// \brief Handle a #__private_macro__ directive.
+/// \brief Handle a #private directive.
void Preprocessor::HandleMacroPrivateDirective(Token &Tok) {
Token MacroNameTok;
ReadMacroName(MacroNameTok, 2);
@@ -1078,8 +1083,8 @@
if (MacroNameTok.is(tok::eod))
return;
- // Check to see if this is the last token on the #__private_macro__ line.
- CheckEndOfDirective("__private_macro__");
+ // Check to see if this is the last token on the #__private_macro line.
+ CheckEndOfDirective("__private_macro");
// Okay, we finally have a valid identifier to undef.
MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
@@ -1294,7 +1299,7 @@
const FileEntry *File = LookupFile(
Filename, isAngled, LookupFrom, CurDir,
Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL,
- AutoModuleImport? &SuggestedModule : 0);
+ getLangOptions().Modules? &SuggestedModule : 0);
if (Callbacks) {
if (!File) {
@@ -1308,7 +1313,7 @@
// Try the lookup again, skipping the cache.
File = LookupFile(Filename, isAngled, LookupFrom, CurDir, 0, 0,
- AutoModuleImport ? &SuggestedModule : 0,
+ getLangOptions().Modules? &SuggestedModule : 0,
/*SkipCache*/true);
}
}
@@ -1365,7 +1370,6 @@
default:
llvm_unreachable("unknown include directive kind");
- break;
}
// Determine whether we are actually building the module that this
@@ -1373,26 +1377,28 @@
bool BuildingImportedModule
= Path[0].first->getName() == getLangOptions().CurrentModule;
- if (!BuildingImportedModule) {
+ if (!BuildingImportedModule && getLangOptions().ObjC2) {
// If we're not building the imported module, warn that we're going
// to automatically turn this inclusion directive into a module import.
+ // We only do this in Objective-C, where we have a module-import syntax.
CharSourceRange ReplaceRange(SourceRange(HashLoc, CharEnd),
/*IsTokenRange=*/false);
Diag(HashLoc, diag::warn_auto_module_import)
<< IncludeKind << PathString
<< FixItHint::CreateReplacement(ReplaceRange,
- "__import_module__ " + PathString.str().str() + ";");
+ "@import " + PathString.str().str() + ";");
}
// Load the module.
// If this was an #__include_macros directive, only make macros visible.
Module::NameVisibilityKind Visibility
= (IncludeKind == 3)? Module::MacrosVisible : Module::AllVisible;
- TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
- /*IsIncludeDirective=*/true);
+ Module *Imported
+ = TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
+ /*IsIncludeDirective=*/true);
// If this header isn't part of the module we're building, we're done.
- if (!BuildingImportedModule)
+ if (!BuildingImportedModule && Imported)
return;
}
Modified: cfe/branches/tooling/lib/Lex/PPExpressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/PPExpressions.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/PPExpressions.cpp (original)
+++ cfe/branches/tooling/lib/Lex/PPExpressions.cpp Fri Jan 20 10:14:22 2012
@@ -703,8 +703,6 @@
LHS.Val = Res;
LHS.setEnd(RHS.getRange().getEnd());
}
-
- return false;
}
/// EvaluateDirectiveExpression - Evaluate an integer constant expression that
Modified: cfe/branches/tooling/lib/Lex/PPLexerChange.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/PPLexerChange.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/PPLexerChange.cpp (original)
+++ cfe/branches/tooling/lib/Lex/PPLexerChange.cpp Fri Jan 20 10:14:22 2012
@@ -18,7 +18,10 @@
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PathV2.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
PPCallbacks::~PPCallbacks() {}
@@ -199,6 +202,31 @@
CurLexerKind = CLK_TokenLexer;
}
+/// \brief Compute the relative path that names the given file relative to
+/// the given directory.
+static void computeRelativePath(FileManager &FM, const DirectoryEntry *Dir,
+ const FileEntry *File,
+ llvm::SmallString<128> &Result) {
+ Result.clear();
+
+ StringRef FilePath = File->getDir()->getName();
+ StringRef Path = FilePath;
+ while (!Path.empty()) {
+ if (const DirectoryEntry *CurDir = FM.getDirectory(Path)) {
+ if (CurDir == Dir) {
+ Result = FilePath.substr(Path.size());
+ llvm::sys::path::append(Result,
+ llvm::sys::path::filename(File->getName()));
+ return;
+ }
+ }
+
+ Path = llvm::sys::path::parent_path(Path);
+ }
+
+ Result = File->getName();
+}
+
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
/// the current file. This either returns the EOF token or pops a level off
/// the include stack and keeps going.
@@ -316,6 +344,48 @@
I=WarnUnusedMacroLocs.begin(), E=WarnUnusedMacroLocs.end(); I!=E; ++I)
Diag(*I, diag::pp_macro_not_used);
+ // If we are building a module that has an umbrella header, make sure that
+ // each of the headers within the directory covered by the umbrella header
+ // was actually included by the umbrella header.
+ if (Module *Mod = getCurrentModule()) {
+ if (Mod->getUmbrellaHeader()) {
+ SourceLocation StartLoc
+ = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+
+ if (getDiagnostics().getDiagnosticLevel(
+ diag::warn_uncovered_module_header,
+ StartLoc) != DiagnosticsEngine::Ignored) {
+ ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
+ typedef llvm::sys::fs::recursive_directory_iterator
+ recursive_directory_iterator;
+ const DirectoryEntry *Dir = Mod->getUmbrellaDir();
+ llvm::error_code EC;
+ for (recursive_directory_iterator Entry(Dir->getName(), EC), End;
+ Entry != End && !EC; Entry.increment(EC)) {
+ using llvm::StringSwitch;
+
+ // Check whether this entry has an extension typically associated with
+ // headers.
+ if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->path()))
+ .Cases(".h", ".H", ".hh", ".hpp", true)
+ .Default(false))
+ continue;
+
+ if (const FileEntry *Header = getFileManager().getFile(Entry->path()))
+ if (!getSourceManager().hasFileInfo(Header)) {
+ if (!ModMap.isHeaderInUnavailableModule(Header)) {
+ // Find the relative path that would access this header.
+ llvm::SmallString<128> RelativePath;
+ computeRelativePath(FileMgr, Dir, Header, RelativePath);
+ Diag(StartLoc, diag::warn_uncovered_module_header)
+ << RelativePath;
+ }
+ }
+ }
+ }
+ }
+ }
+
return true;
}
Modified: cfe/branches/tooling/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/PPMacroExpansion.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/branches/tooling/lib/Lex/PPMacroExpansion.cpp Fri Jan 20 10:14:22 2012
@@ -24,7 +24,7 @@
#include "clang/Lex/LiteralSupport.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstdio>
@@ -305,8 +305,10 @@
// unexpandable.
if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) {
if (MacroInfo *NewMI = getMacroInfo(NewII))
- if (!NewMI->isEnabled() || NewMI == MI)
+ if (!NewMI->isEnabled() || NewMI == MI) {
Identifier.setFlag(Token::DisableExpand);
+ Diag(Identifier, diag::pp_disabled_macro_expansion);
+ }
}
// Since this is not an identifier token, it can't be macro expanded, so
@@ -615,20 +617,23 @@
LangOpts.ObjCRuntimeHasWeak)
.Case("objc_fixed_enum", LangOpts.ObjC2)
.Case("objc_instancetype", LangOpts.ObjC2)
+ .Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
.Case("ownership_holds", true)
.Case("ownership_returns", true)
.Case("ownership_takes", true)
.Case("arc_cf_code_audited", true)
- // C1X features
- .Case("c_alignas", LangOpts.C1X)
- .Case("c_generic_selections", LangOpts.C1X)
- .Case("c_static_assert", LangOpts.C1X)
+ // C11 features
+ .Case("c_alignas", LangOpts.C11)
+ .Case("c_atomic", LangOpts.C11)
+ .Case("c_generic_selections", LangOpts.C11)
+ .Case("c_static_assert", LangOpts.C11)
// C++0x features
.Case("cxx_access_control_sfinae", LangOpts.CPlusPlus0x)
.Case("cxx_alias_templates", LangOpts.CPlusPlus0x)
.Case("cxx_alignas", LangOpts.CPlusPlus0x)
+ .Case("cxx_atomic", LangOpts.CPlusPlus0x)
.Case("cxx_attributes", LangOpts.CPlusPlus0x)
.Case("cxx_auto_type", LangOpts.CPlusPlus0x)
//.Case("cxx_constexpr", false);
@@ -695,6 +700,7 @@
.Case("is_trivial", LangOpts.CPlusPlus)
.Case("is_trivially_copyable", LangOpts.CPlusPlus)
.Case("is_union", LangOpts.CPlusPlus)
+ .Case("modules", LangOpts.Modules)
.Case("tls", PP.getTargetInfo().isTLSSupported())
.Case("underlying_type", LangOpts.CPlusPlus)
.Default(false);
@@ -718,11 +724,13 @@
// Because we inherit the feature list from HasFeature, this string switch
// must be less restrictive than HasFeature's.
return llvm::StringSwitch<bool>(II->getName())
- // C1X features supported by other languages as extensions.
+ // C11 features supported by other languages as extensions.
.Case("c_alignas", true)
+ .Case("c_atomic", true)
.Case("c_generic_selections", true)
.Case("c_static_assert", true)
// C++0x features supported by other languages as extensions.
+ .Case("cxx_atomic", LangOpts.CPlusPlus)
.Case("cxx_deleted_functions", LangOpts.CPlusPlus)
.Case("cxx_explicit_conversions", LangOpts.CPlusPlus)
.Case("cxx_inline_namespaces", LangOpts.CPlusPlus)
Modified: cfe/branches/tooling/lib/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/Pragma.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/Pragma.cpp (original)
+++ cfe/branches/tooling/lib/Lex/Pragma.cpp Fri Jan 20 10:14:22 2012
@@ -714,8 +714,10 @@
// If this is a non-default namespace and it is now empty, remove
// it.
- if (NS != PragmaHandlers && NS->IsEmpty())
+ if (NS != PragmaHandlers && NS->IsEmpty()) {
PragmaHandlers->RemovePragmaHandler(NS);
+ delete NS;
+ }
}
bool Preprocessor::LexOnOffSwitch(tok::OnOffSwitch &Result) {
Modified: cfe/branches/tooling/lib/Lex/PreprocessingRecord.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/PreprocessingRecord.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/PreprocessingRecord.cpp (original)
+++ cfe/branches/tooling/lib/Lex/PreprocessingRecord.cpp Fri Jan 20 10:14:22 2012
@@ -390,7 +390,6 @@
default:
llvm_unreachable("Unknown include directive kind");
- return;
}
clang::InclusionDirective *ID
Modified: cfe/branches/tooling/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/Preprocessor.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/Preprocessor.cpp (original)
+++ cfe/branches/tooling/lib/Lex/Preprocessor.cpp Fri Jan 20 10:14:22 2012
@@ -130,7 +130,6 @@
KeepComments = false;
KeepMacroComments = false;
SuppressIncludeNotFoundError = false;
- AutoModuleImport = false;
// Macro expansion is enabled.
DisableMacroExpansion = false;
@@ -267,6 +266,17 @@
return Macros.end();
}
+void Preprocessor::recomputeCurLexerKind() {
+ if (CurLexer)
+ CurLexerKind = CLK_Lexer;
+ else if (CurPTHLexer)
+ CurLexerKind = CLK_PTHLexer;
+ else if (CurTokenLexer)
+ CurLexerKind = CLK_TokenLexer;
+ else
+ CurLexerKind = CLK_CachingLexer;
+}
+
bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
unsigned CompleteLine,
unsigned CompleteColumn) {
@@ -390,19 +400,23 @@
assert(NumEnteredSourceFiles == 0 && "Cannot reenter the main file!");
FileID MainFileID = SourceMgr.getMainFileID();
- // Enter the main file source buffer.
- EnterSourceFile(MainFileID, 0, SourceLocation());
-
- // If we've been asked to skip bytes in the main file (e.g., as part of a
- // precompiled preamble), do so now.
- if (SkipMainFilePreamble.first > 0)
- CurLexer->SkipBytes(SkipMainFilePreamble.first,
- SkipMainFilePreamble.second);
-
- // Tell the header info that the main file was entered. If the file is later
- // #imported, it won't be re-entered.
- if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))
- HeaderInfo.IncrementIncludeCount(FE);
+ // If MainFileID is loaded it means we loaded an AST file, no need to enter
+ // a main file.
+ if (!SourceMgr.isLoadedFileID(MainFileID)) {
+ // Enter the main file source buffer.
+ EnterSourceFile(MainFileID, 0, SourceLocation());
+
+ // If we've been asked to skip bytes in the main file (e.g., as part of a
+ // precompiled preamble), do so now.
+ if (SkipMainFilePreamble.first > 0)
+ CurLexer->SkipBytes(SkipMainFilePreamble.first,
+ SkipMainFilePreamble.second);
+
+ // Tell the header info that the main file was entered. If the file is later
+ // #imported, it won't be re-entered.
+ if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))
+ HeaderInfo.IncrementIncludeCount(FE);
+ }
// Preprocess Predefines to populate the initial preprocessor state.
llvm::MemoryBuffer *SB =
@@ -509,8 +523,10 @@
// If this is a macro to be expanded, do it.
if (MacroInfo *MI = getMacroInfo(&II)) {
- if (!DisableMacroExpansion && !Identifier.isExpandDisabled()) {
- if (MI->isEnabled()) {
+ if (!DisableMacroExpansion) {
+ if (Identifier.isExpandDisabled()) {
+ Diag(Identifier, diag::pp_disabled_macro_expansion);
+ } else if (MI->isEnabled()) {
if (!HandleMacroExpandedIdentifier(Identifier, MI))
return;
} else {
@@ -518,6 +534,7 @@
// expanded, even if it's in a context where it could be expanded in the
// future.
Identifier.setFlag(Token::DisableExpand);
+ Diag(Identifier, diag::pp_disabled_macro_expansion);
}
}
}
@@ -546,10 +563,14 @@
if (II.isExtensionToken() && !DisableMacroExpansion)
Diag(Identifier, diag::ext_token_used);
- // If this is the '__import_module__' keyword, note that the next token
+ // If this is the 'import' contextual keyword, note that the next token
// indicates a module name.
- if (II.getTokenID() == tok::kw___import_module__ &&
- !InMacroArgs && !DisableMacroExpansion) {
+ //
+ // Note that we do not treat 'import' as a contextual keyword when we're
+ // in a caching lexer, because caching lexers only get used in contexts where
+ // import declarations are disallowed.
+ if (II.isImport() && !InMacroArgs && !DisableMacroExpansion &&
+ getLangOptions().Modules && CurLexerKind != CLK_CachingLexer) {
ModuleImportLoc = Identifier.getLocation();
ModuleImportPath.clear();
ModuleImportExpectsIdentifier = true;
@@ -557,27 +578,21 @@
}
}
-/// \brief Lex a token following the __import_module__ keyword.
+/// \brief Lex a token following the 'import' contextual keyword.
+///
void Preprocessor::LexAfterModuleImport(Token &Result) {
// Figure out what kind of lexer we actually have.
- if (CurLexer)
- CurLexerKind = CLK_Lexer;
- else if (CurPTHLexer)
- CurLexerKind = CLK_PTHLexer;
- else if (CurTokenLexer)
- CurLexerKind = CLK_TokenLexer;
- else
- CurLexerKind = CLK_CachingLexer;
+ recomputeCurLexerKind();
// Lex the next token.
Lex(Result);
// The token sequence
//
- // __import_module__ identifier (. identifier)*
+ // import identifier (. identifier)*
//
- // indicates a module import directive. We already saw the __import_module__
- // keyword, so now we're looking for the identifiers.
+ // indicates a module import directive. We already saw the 'import'
+ // contextual keyword, so now we're looking for the identifiers.
if (ModuleImportExpectsIdentifier && Result.getKind() == tok::identifier) {
// We expected to see an identifier here, and we did; continue handling
// identifiers.
Modified: cfe/branches/tooling/lib/Lex/PreprocessorLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/PreprocessorLexer.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/PreprocessorLexer.cpp (original)
+++ cfe/branches/tooling/lib/Lex/PreprocessorLexer.cpp Fri Jan 20 10:14:22 2012
@@ -17,6 +17,8 @@
#include "clang/Basic/SourceManager.h"
using namespace clang;
+void PreprocessorLexer::anchor() { }
+
PreprocessorLexer::PreprocessorLexer(Preprocessor *pp, FileID fid)
: PP(pp), FID(fid), InitialNumSLocEntries(0),
ParsingPreprocessorDirective(false),
Modified: cfe/branches/tooling/lib/Lex/TokenConcatenation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Lex/TokenConcatenation.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Lex/TokenConcatenation.cpp (original)
+++ cfe/branches/tooling/lib/Lex/TokenConcatenation.cpp Fri Jan 20 10:14:22 2012
@@ -179,11 +179,9 @@
switch (PrevKind) {
default:
llvm_unreachable("InitAvoidConcatTokenInfo built wrong");
- return true;
case tok::raw_identifier:
llvm_unreachable("tok::raw_identifier in non-raw lexing mode!");
- return true;
case tok::identifier: // id+id or id+number or id+L"foo".
// id+'.'... will not append.
Modified: cfe/branches/tooling/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Parse/ParseCXXInlineMethods.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/branches/tooling/lib/Parse/ParseCXXInlineMethods.cpp Fri Jan 20 10:14:22 2012
@@ -76,7 +76,7 @@
if (Tok.is(tok::kw_delete)) {
Diag(Tok, getLang().CPlusPlus0x ?
diag::warn_cxx98_compat_deleted_function :
- diag::warn_deleted_function_accepted_as_extension);
+ diag::ext_deleted_function);
KWLoc = ConsumeToken();
Actions.SetDeclDeleted(FnD, KWLoc);
@@ -84,7 +84,7 @@
} else if (Tok.is(tok::kw_default)) {
Diag(Tok, getLang().CPlusPlus0x ?
diag::warn_cxx98_compat_defaulted_function :
- diag::warn_defaulted_function_accepted_as_extension);
+ diag::ext_defaulted_function);
KWLoc = ConsumeToken();
Actions.SetDeclDefaulted(FnD, KWLoc);
Modified: cfe/branches/tooling/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Parse/ParseDecl.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Parse/ParseDecl.cpp (original)
+++ cfe/branches/tooling/lib/Parse/ParseDecl.cpp Fri Jan 20 10:14:22 2012
@@ -883,7 +883,7 @@
/// [C++] namespace-definition
/// [C++] using-directive
/// [C++] using-declaration
-/// [C++0x/C1X] static_assert-declaration
+/// [C++0x/C11] static_assert-declaration
/// others... [FIXME]
///
Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
@@ -962,10 +962,7 @@
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
getDeclSpecContextFromDeclaratorContext(Context));
- StmtResult R = Actions.ActOnVlaStmt(DS);
- if (R.isUsable())
- Stmts.push_back(R.release());
-
+
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
@@ -997,9 +994,15 @@
case tok::amp:
case tok::ampamp:
- case tok::colon: // Might be a typo for '::'.
return getLang().CPlusPlus;
+ case tok::l_square: // Might be an attribute on an unnamed bit-field.
+ return Context == Declarator::MemberContext && getLang().CPlusPlus0x &&
+ NextToken().is(tok::l_square);
+
+ case tok::colon: // Might be a typo for '::' or an unnamed bit-field.
+ return Context == Declarator::MemberContext || getLang().CPlusPlus;
+
case tok::identifier:
switch (NextToken().getKind()) {
case tok::code_completion:
@@ -1022,8 +1025,13 @@
case tok::colon:
// At namespace scope, 'identifier:' is probably a typo for 'identifier::'
- // and in block scope it's probably a label.
- return getLang().CPlusPlus && Context == Declarator::FileContext;
+ // and in block scope it's probably a label. Inside a class definition,
+ // this is a bit-field.
+ return Context == Declarator::MemberContext ||
+ (getLang().CPlusPlus && Context == Declarator::FileContext);
+
+ case tok::identifier: // Possible virt-specifier.
+ return getLang().CPlusPlus0x && isCXX0XVirtSpecifier(NextToken());
default:
return false;
@@ -1130,6 +1138,7 @@
// Parse the next declarator.
D.clear();
+ D.setCommaLoc(CommaLoc);
// Accept attributes in an init-declarator. In the first declarator in a
// declaration, these would be part of the declspec. In subsequent
@@ -1141,11 +1150,12 @@
MaybeParseGNUAttributes(D);
ParseDeclarator(D);
-
- Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
- D.complete(ThisDecl);
- if (ThisDecl)
- DeclsInGroup.push_back(ThisDecl);
+ if (!D.isInvalidType()) {
+ Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
+ D.complete(ThisDecl);
+ if (ThisDecl)
+ DeclsInGroup.push_back(ThisDecl);
+ }
}
if (DeclEnd)
@@ -1259,8 +1269,8 @@
D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
// Parse declarator '=' initializer.
- if (isTokenEqualOrMistypedEqualEqual(
- diag::err_invalid_equalequal_after_declarator)) {
+ // If a '==' or '+=' is found, suggest a fixit to '='.
+ if (isTokenEqualOrEqualTypo()) {
ConsumeToken();
if (Tok.is(tok::kw_delete)) {
if (D.isFunctionDeclarator())
@@ -1566,8 +1576,8 @@
/// FIXME: Simply returns an alignof() expression if the argument is a
/// type. Ideally, the type should be propagated directly into Sema.
///
-/// [C1X] type-id
-/// [C1X] constant-expression
+/// [C11] type-id
+/// [C11] constant-expression
/// [C++0x] type-id ...[opt]
/// [C++0x] assignment-expression ...[opt]
ExprResult Parser::ParseAlignArgument(SourceLocation Start,
@@ -1592,8 +1602,8 @@
/// attribute to Attrs.
///
/// alignment-specifier:
-/// [C1X] '_Alignas' '(' type-id ')'
-/// [C1X] '_Alignas' '(' constant-expression ')'
+/// [C11] '_Alignas' '(' type-id ')'
+/// [C11] '_Alignas' '(' constant-expression ')'
/// [C++0x] 'alignas' '(' type-id ...[opt] ')'
/// [C++0x] 'alignas' '(' assignment-expression ...[opt] ')'
void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
@@ -1636,7 +1646,7 @@
/// storage-class-specifier declaration-specifiers[opt]
/// type-specifier declaration-specifiers[opt]
/// [C99] function-specifier declaration-specifiers[opt]
-/// [C1X] alignment-specifier declaration-specifiers[opt]
+/// [C11] alignment-specifier declaration-specifiers[opt]
/// [GNU] attributes declaration-specifiers[opt]
/// [Clang] '__module_private__' declaration-specifiers[opt]
///
@@ -2085,8 +2095,8 @@
// alignment-specifier
case tok::kw__Alignas:
- if (!getLang().C1X)
- Diag(Tok, diag::ext_c1x_alignas);
+ if (!getLang().C11)
+ Diag(Tok, diag::ext_c11_alignas);
ParseAlignmentSpecifier(DS.getAttributes());
continue;
@@ -2657,9 +2667,11 @@
// Read struct-declarators until we find the semicolon.
bool FirstDeclarator = true;
+ SourceLocation CommaLoc;
while (1) {
ParsingDeclRAIIObject PD(*this);
FieldDeclarator DeclaratorInfo(DS);
+ DeclaratorInfo.D.setCommaLoc(CommaLoc);
// Attributes are only allowed here on successive declarators.
if (!FirstDeclarator)
@@ -2695,7 +2707,7 @@
return;
// Consume the comma.
- ConsumeToken();
+ CommaLoc = ConsumeToken();
FirstDeclarator = false;
}
@@ -2725,9 +2737,10 @@
// Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
// C++.
- if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
- Diag(Tok, diag::ext_empty_struct_union)
- << (TagType == TST_union);
+ if (Tok.is(tok::r_brace) && !getLang().CPlusPlus) {
+ Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union);
+ Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union);
+ }
SmallVector<Decl *, 32> FieldDecls;
@@ -2856,15 +2869,14 @@
return cutOffParsing();
}
- bool IsScopedEnum = false;
+ SourceLocation ScopedEnumKWLoc;
bool IsScopedUsingClassTag = false;
if (getLang().CPlusPlus0x &&
(Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) {
Diag(Tok, diag::warn_cxx98_compat_scoped_enum);
- IsScopedEnum = true;
IsScopedUsingClassTag = Tok.is(tok::kw_class);
- ConsumeToken();
+ ScopedEnumKWLoc = ConsumeToken();
}
// If attributes exist after tag, parse them.
@@ -2913,11 +2925,11 @@
NameLoc = ConsumeToken();
}
- if (!Name && IsScopedEnum) {
+ if (!Name && ScopedEnumKWLoc.isValid()) {
// C++0x 7.2p2: The optional identifier shall not be omitted in the
// declaration of a scoped enumeration.
Diag(Tok, diag::err_scoped_enum_missing_identifier);
- IsScopedEnum = false;
+ ScopedEnumKWLoc = SourceLocation();
IsScopedUsingClassTag = false;
}
@@ -2984,16 +2996,20 @@
}
}
- // There are three options here. If we have 'enum foo;', then this is a
- // forward declaration. If we have 'enum foo {...' then this is a
- // definition. Otherwise we have something like 'enum foo xyz', a reference.
+ // There are four options here. If we have 'friend enum foo;' then this is a
+ // friend declaration, and cannot have an accompanying definition. If we have
+ // 'enum foo;', then this is a forward declaration. If we have
+ // 'enum foo {...' then this is a definition. Otherwise we have something
+ // like 'enum foo xyz', a reference.
//
// This is needed to handle stuff like this right (C99 6.7.2.3p11):
// enum foo {..}; void bar() { enum foo; } <- new foo in bar.
// enum foo {..}; void bar() { enum foo x; } <- use of old foo.
//
Sema::TagUseKind TUK;
- if (Tok.is(tok::l_brace))
+ if (DS.isFriendSpecified())
+ TUK = Sema::TUK_Friend;
+ else if (Tok.is(tok::l_brace))
TUK = Sema::TUK_Definition;
else if (Tok.is(tok::semi))
TUK = Sema::TUK_Declaration;
@@ -3027,7 +3043,7 @@
StartLoc, SS, Name, NameLoc, attrs.getList(),
AS, DS.getModulePrivateSpecLoc(),
MultiTemplateParamsArg(Actions),
- Owned, IsDependent, IsScopedEnum,
+ Owned, IsDependent, ScopedEnumKWLoc,
IsScopedUsingClassTag, BaseType);
if (IsDependent) {
@@ -3066,9 +3082,13 @@
DS.SetTypeSpecError();
return;
}
-
- if (Tok.is(tok::l_brace))
+
+ if (Tok.is(tok::l_brace)) {
+ if (TUK == Sema::TUK_Friend)
+ Diag(Tok, diag::err_friend_decl_defines_type)
+ << SourceRange(DS.getFriendSpecLoc());
ParseEnumBody(StartLoc, TagDecl);
+ }
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
NameLoc.isValid() ? NameLoc : StartLoc,
@@ -3341,7 +3361,7 @@
case tok::kw_private:
return getLang().OpenCL;
- // C1x _Atomic()
+ // C11 _Atomic()
case tok::kw__Atomic:
return true;
}
@@ -3465,7 +3485,7 @@
case tok::annot_decltype:
return true;
- // C1x _Atomic()
+ // C11 _Atomic()
case tok::kw__Atomic:
return true;
@@ -4670,7 +4690,7 @@
Diag(StartLoc, DiagID) << PrevSpec;
}
-/// [C1X] atomic-specifier:
+/// [C11] atomic-specifier:
/// _Atomic ( type-name )
///
void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
Modified: cfe/branches/tooling/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Parse/ParseDeclCXX.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/branches/tooling/lib/Parse/ParseDeclCXX.cpp Fri Jan 20 10:14:22 2012
@@ -573,20 +573,20 @@
IsTypeName, TypenameLoc);
}
-/// ParseStaticAssertDeclaration - Parse C++0x or C1X static_assert-declaration.
+/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration.
///
/// [C++0x] static_assert-declaration:
/// static_assert ( constant-expression , string-literal ) ;
///
-/// [C1X] static_assert-declaration:
+/// [C11] static_assert-declaration:
/// _Static_assert ( constant-expression , string-literal ) ;
///
Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
assert((Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) &&
"Not a static_assert declaration");
- if (Tok.is(tok::kw__Static_assert) && !getLang().C1X)
- Diag(Tok, diag::ext_c1x_static_assert);
+ if (Tok.is(tok::kw__Static_assert) && !getLang().C11)
+ Diag(Tok, diag::ext_c11_static_assert);
if (Tok.is(tok::kw_static_assert))
Diag(Tok, diag::warn_cxx98_compat_static_assert);
@@ -1115,7 +1115,7 @@
if (DS.isFriendSpecified()) {
// C++ [class.friend]p2:
// A class shall not be defined in a friend declaration.
- Diag(Tok.getLocation(), diag::err_friend_decl_defines_class)
+ Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
<< SourceRange(DS.getFriendSpecLoc());
// Skip everything up to the semicolon, so that this looks like a proper
@@ -1277,8 +1277,9 @@
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
SS, Name, NameLoc, attrs.getList(), AS,
DS.getModulePrivateSpecLoc(),
- TParams, Owned, IsDependent, false,
- false, clang::TypeResult());
+ TParams, Owned, IsDependent,
+ SourceLocation(), false,
+ clang::TypeResult());
// If ActOnTag said the type was dependent, try again with the
// less common call.
@@ -1548,13 +1549,13 @@
}
}
-/// isCXX0XVirtSpecifier - Determine whether the next token is a C++0x
+/// isCXX0XVirtSpecifier - Determine whether the given token is a C++0x
/// virt-specifier.
///
/// virt-specifier:
/// override
/// final
-VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier() const {
+VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const {
if (!getLang().CPlusPlus)
return VirtSpecifiers::VS_None;
@@ -1896,6 +1897,7 @@
SmallVector<Decl *, 8> DeclsInGroup;
ExprResult BitfieldSize;
+ bool ExpectSemi = true;
while (1) {
// member-declarator:
@@ -2023,7 +2025,18 @@
break;
// Consume the comma.
- ConsumeToken();
+ SourceLocation CommaLoc = ConsumeToken();
+
+ if (Tok.isAtStartOfLine() &&
+ !MightBeDeclarator(Declarator::MemberContext)) {
+ // This comma was followed by a line-break and something which can't be
+ // the start of a declarator. The comma was probably a typo for a
+ // semicolon.
+ Diag(CommaLoc, diag::err_expected_semi_declaration)
+ << FixItHint::CreateReplacement(CommaLoc, ";");
+ ExpectSemi = false;
+ break;
+ }
// Parse the next declarator.
DeclaratorInfo.clear();
@@ -2031,6 +2044,7 @@
BitfieldSize = true;
Init = true;
HasInitializer = false;
+ DeclaratorInfo.setCommaLoc(CommaLoc);
// Attributes are only allowed on the second declarator.
MaybeParseGNUAttributes(DeclaratorInfo);
@@ -2039,7 +2053,8 @@
ParseDeclarator(DeclaratorInfo);
}
- if (ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) {
+ if (ExpectSemi &&
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) {
// Skip to end of block or statement.
SkipUntil(tok::r_brace, true, true);
// If we stopped at a ';', eat it.
Modified: cfe/branches/tooling/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Parse/ParseExpr.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Parse/ParseExpr.cpp (original)
+++ cfe/branches/tooling/lib/Parse/ParseExpr.cpp Fri Jan 20 10:14:22 2012
@@ -247,11 +247,12 @@
ExprResult Parser::ParseConstantExpression() {
- // C++ [basic.def.odr]p2:
+ // C++03 [basic.def.odr]p2:
// An expression is potentially evaluated unless it appears where an
// integral constant expression is required (see 5.19) [...].
+ // C++98 and C++11 have no such rule, but this is only a defect in C++98.
EnterExpressionEvaluationContext Unevaluated(Actions,
- Sema::Unevaluated);
+ Sema::ConstantEvaluated);
ExprResult LHS(ParseCastExpression(false));
return ParseRHSOfBinaryExpression(LHS, prec::Conditional);
@@ -311,8 +312,8 @@
SourceLocation FILoc = Tok.getLocation();
const char *FIText = ": ";
const SourceManager &SM = PP.getSourceManager();
- if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc)) {
- FILoc = SM.getExpansionLoc(FILoc);
+ if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc, &FILoc)) {
+ assert(FILoc.isFileID());
bool IsInvalid = false;
const char *SourcePtr =
SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid);
@@ -465,7 +466,7 @@
/// [C++] boolean-literal [C++ 2.13.5]
/// [C++0x] 'nullptr' [C++0x 2.14.7]
/// '(' expression ')'
-/// [C1X] generic-selection
+/// [C11] generic-selection
/// '__func__' [C99 6.4.2.2]
/// [GNU] '__FUNCTION__'
/// [GNU] '__PRETTY_FUNCTION__'
@@ -677,7 +678,8 @@
if (Next.is(tok::coloncolon) ||
(!ColonIsSacred && Next.is(tok::colon)) ||
Next.is(tok::less) ||
- Next.is(tok::l_paren)) {
+ Next.is(tok::l_paren) ||
+ Next.is(tok::l_brace)) {
// If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
if (TryAnnotateTypeOrScopeToken())
return ExprError();
@@ -792,7 +794,7 @@
case tok::utf32_string_literal:
Res = ParseStringLiteralExpression();
break;
- case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1]
+ case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1]
Res = ParseGenericSelectionExpression();
break;
case tok::kw___builtin_va_arg:
@@ -1041,7 +1043,7 @@
if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept"))
return ExprError();
- // C++ [expr.unary.noexcept]p1:
+ // C++11 [expr.unary.noexcept]p1:
// The noexcept operator determines whether the evaluation of its operand,
// which is an unevaluated operand, can throw an exception.
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
@@ -1130,8 +1132,13 @@
case tok::l_square:
if (getLang().CPlusPlus0x) {
if (getLang().ObjC1) {
+ // C++11 lambda expressions and Objective-C message sends both start with a
+ // square bracket. There are three possibilities here:
+ // we have a valid lambda expression, we have an invalid lambda
+ // expression, or we have something that doesn't appear to be a lambda.
+ // If we're in the last case, we fall back to ParseObjCMessageExpression.
Res = TryParseLambdaExpression();
- if (Res.isInvalid())
+ if (!Res.isInvalid() && !Res.get())
Res = ParseObjCMessageExpression();
break;
}
@@ -1439,8 +1446,8 @@
// [...] The operand is either an expression, which is an unevaluated
// operand (Clause 5) [...]
//
- // The GNU typeof and alignof extensions also behave as unevaluated
- // operands.
+ // The GNU typeof and GNU/C++11 alignof extensions also behave as
+ // unevaluated operands.
EnterExpressionEvaluationContext Unevaluated(Actions,
Sema::Unevaluated);
Operand = ParseCastExpression(true/*isUnaryExpression*/);
@@ -1456,8 +1463,8 @@
// [...] The operand is either an expression, which is an unevaluated
// operand (Clause 5) [...]
//
- // The GNU typeof and alignof extensions also behave as unevaluated
- // operands.
+ // The GNU typeof and GNU/C++11 alignof extensions also behave as
+ // unevaluated operands.
EnterExpressionEvaluationContext Unevaluated(Actions,
Sema::Unevaluated);
Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
@@ -1817,9 +1824,24 @@
return ExprError();
}
+ // Diagnose use of bridge casts in non-arc mode.
+ bool BridgeCast = (getLang().ObjC2 &&
+ (Tok.is(tok::kw___bridge) ||
+ Tok.is(tok::kw___bridge_transfer) ||
+ Tok.is(tok::kw___bridge_retained) ||
+ Tok.is(tok::kw___bridge_retain)));
+ if (BridgeCast && !getLang().ObjCAutoRefCount) {
+ StringRef BridgeCastName = Tok.getName();
+ SourceLocation BridgeKeywordLoc = ConsumeToken();
+ if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc))
+ Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_nonarc)
+ << BridgeCastName
+ << FixItHint::CreateReplacement(BridgeKeywordLoc, "");
+ BridgeCast = false;
+ }
+
// None of these cases should fall through with an invalid Result
// unless they've already reported an error.
-
if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
Diag(Tok, diag::ext_gnu_statement_expr);
ParsedAttributes attrs(AttrFactory);
@@ -1829,11 +1851,7 @@
// If the substmt parsed correctly, build the AST node.
if (!Stmt.isInvalid())
Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation());
- } else if (ExprType >= CompoundLiteral &&
- (Tok.is(tok::kw___bridge) ||
- Tok.is(tok::kw___bridge_transfer) ||
- Tok.is(tok::kw___bridge_retained) ||
- Tok.is(tok::kw___bridge_retain))) {
+ } else if (ExprType >= CompoundLiteral && BridgeCast) {
tok::TokenKind tokenKind = Tok.getKind();
SourceLocation BridgeKeywordLoc = ConsumeToken();
@@ -2037,8 +2055,8 @@
return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size());
}
-/// ParseGenericSelectionExpression - Parse a C1X generic-selection
-/// [C1X 6.5.1.1].
+/// ParseGenericSelectionExpression - Parse a C11 generic-selection
+/// [C11 6.5.1.1].
///
/// generic-selection:
/// _Generic ( assignment-expression , generic-assoc-list )
@@ -2052,8 +2070,8 @@
assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected");
SourceLocation KeyLoc = ConsumeToken();
- if (!getLang().C1X)
- Diag(KeyLoc, diag::ext_c1x_generic_selection);
+ if (!getLang().C11)
+ Diag(KeyLoc, diag::ext_c11_generic_selection);
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen))
@@ -2061,7 +2079,7 @@
ExprResult ControllingExpr;
{
- // C1X 6.5.1.1p3 "The controlling expression of a generic selection is
+ // C11 6.5.1.1p3 "The controlling expression of a generic selection is
// not evaluated."
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
ControllingExpr = ParseAssignmentExpression();
@@ -2082,7 +2100,7 @@
while (1) {
ParsedType Ty;
if (Tok.is(tok::kw_default)) {
- // C1X 6.5.1.1p2 "A generic selection shall have no more than one default
+ // C11 6.5.1.1p2 "A generic selection shall have no more than one default
// generic association."
if (!DefaultLoc.isInvalid()) {
Diag(Tok, diag::err_duplicate_default_assoc);
Modified: cfe/branches/tooling/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Parse/ParseExprCXX.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/branches/tooling/lib/Parse/ParseExprCXX.cpp Fri Jan 20 10:14:22 2012
@@ -14,6 +14,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -563,6 +564,9 @@
if (DiagID) {
Diag(Tok, DiagID.getValue());
SkipUntil(tok::r_square);
+ SkipUntil(tok::l_brace);
+ SkipUntil(tok::r_brace);
+ return ExprError();
}
return ParseLambdaExpressionAfterIntroducer(Intro);
@@ -591,14 +595,21 @@
return ParseLambdaExpression();
}
- // If lookahead indicates this is an Objective-C message...
+ // If lookahead indicates an ObjC message send...
+ // [identifier identifier
if (Next.is(tok::identifier) && After.is(tok::identifier)) {
- return ExprError();
+ return ExprEmpty();
}
+ // Here, we're stuck: lambda introducers and Objective-C message sends are
+ // unambiguous, but it requires arbitrary lookhead. [a,b,c,d,e,f,g] is a
+ // lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send. Instead of
+ // writing two routines to parse a lambda introducer, just try to parse
+ // a lambda introducer first, and fall back if that fails.
+ // (TryParseLambdaIntroducer never produces any diagnostic output.)
LambdaIntroducer Intro;
if (TryParseLambdaIntroducer(Intro))
- return ExprError();
+ return ExprEmpty();
return ParseLambdaExpressionAfterIntroducer(Intro);
}
@@ -694,11 +705,15 @@
/// expression.
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
LambdaIntroducer &Intro) {
- Diag(Intro.Range.getBegin(), diag::warn_cxx98_compat_lambda);
+ SourceLocation LambdaBeginLoc = Intro.Range.getBegin();
+ Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda);
+
+ PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
+ "lambda expression parsing");
// Parse lambda-declarator[opt].
DeclSpec DS(AttrFactory);
- Declarator D(DS, Declarator::PrototypeContext);
+ Declarator D(DS, Declarator::LambdaExprContext);
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
@@ -777,22 +792,30 @@
Attr, DeclEndLoc);
}
- // Parse compound-statement.
- if (Tok.is(tok::l_brace)) {
- // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
- // it.
- ParseScope BodyScope(this, Scope::BlockScope | Scope::FnScope |
- Scope::BreakScope | Scope::ContinueScope |
- Scope::DeclScope);
+ // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
+ // it.
+ ParseScope BodyScope(this, Scope::BlockScope | Scope::FnScope |
+ Scope::BreakScope | Scope::ContinueScope |
+ Scope::DeclScope);
- StmtResult Stmt(ParseCompoundStatementBody());
+ Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope());
- BodyScope.Exit();
- } else {
+ // Parse compound-statement.
+ if (!Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_expected_lambda_body);
+ Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
+ return ExprError();
}
- return ExprEmpty();
+ StmtResult Stmt(ParseCompoundStatementBody());
+ BodyScope.Exit();
+
+ if (!Stmt.isInvalid())
+ return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(),
+ getCurScope());
+
+ Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
+ return ExprError();
}
/// ParseCXXCasts - This handles the various ways to cast expressions to another
@@ -901,10 +924,10 @@
// operand (Clause 5).
//
// Note that we can't tell whether the expression is an lvalue of a
- // polymorphic class type until after we've parsed the expression, so
- // we the expression is potentially potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(Actions,
- Sema::PotentiallyPotentiallyEvaluated);
+ // polymorphic class type until after we've parsed the expression; we
+ // speculatively assume the subexpression is unevaluated, and fix it up
+ // later.
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
Result = ParseExpression();
// Match the ')'.
@@ -1022,7 +1045,7 @@
if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid() && SS.isEmpty()) {
DeclSpec DS(AttrFactory);
- SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
+ ParseDecltypeSpecifier(DS);
if (DS.getTypeSpecType() == TST_error)
return ExprError();
return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc,
@@ -1236,8 +1259,8 @@
ExprOut = ExprError();
// '=' assignment-expression
- if (isTokenEqualOrMistypedEqualEqual(
- diag::err_invalid_equalequal_after_declarator)) {
+ // If a '==' or '+=' is found, suggest a fixit to '='.
+ if (isTokenEqualOrEqualTypo()) {
ConsumeToken();
ExprResult AssignExpr(ParseAssignmentExpression());
if (!AssignExpr.isInvalid())
@@ -2440,8 +2463,6 @@
return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(),
T.getCloseLocation());
}
- default:
- break;
}
return ExprError();
}
Modified: cfe/branches/tooling/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Parse/ParseObjc.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Parse/ParseObjc.cpp (original)
+++ cfe/branches/tooling/lib/Parse/ParseObjc.cpp Fri Jan 20 10:14:22 2012
@@ -42,7 +42,6 @@
switch (Tok.getObjCKeywordID()) {
case tok::objc_class:
return ParseObjCAtClassDeclaration(AtLoc);
- break;
case tok::objc_interface: {
ParsedAttributes attrs(AttrFactory);
SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, attrs);
@@ -50,15 +49,13 @@
}
case tok::objc_protocol: {
ParsedAttributes attrs(AttrFactory);
- SingleDecl = ParseObjCAtProtocolDeclaration(AtLoc, attrs);
- break;
+ return ParseObjCAtProtocolDeclaration(AtLoc, attrs);
}
case tok::objc_implementation:
SingleDecl = ParseObjCAtImplementationDeclaration(AtLoc);
break;
case tok::objc_end:
return ParseObjCAtEndDeclaration(AtLoc);
- break;
case tok::objc_compatibility_alias:
SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);
break;
@@ -68,6 +65,12 @@
case tok::objc_dynamic:
SingleDecl = ParseObjCPropertyDynamic(AtLoc);
break;
+ case tok::objc_import:
+ if (getLang().Modules)
+ return ParseModuleImport(AtLoc);
+
+ // Fall through
+
default:
Diag(AtLoc, diag::err_unexpected_at);
SkipUntil(tok::semi);
@@ -284,6 +287,9 @@
/// The Objective-C property callback. This should be defined where
/// it's used, but instead it's been lifted to here to support VS2005.
struct Parser::ObjCPropertyCallback : FieldCallback {
+private:
+ virtual void anchor();
+public:
Parser &P;
SmallVectorImpl<Decl *> &Props;
ObjCDeclSpec &OCDS;
@@ -337,6 +343,9 @@
}
};
+void Parser::ObjCPropertyCallback::anchor() {
+}
+
/// objc-interface-decl-list:
/// empty
/// objc-interface-decl-list objc-property-decl [OBJC2]
@@ -416,7 +425,6 @@
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtDirective(getCurScope());
return cutOffParsing();
- break;
}
tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
@@ -1343,8 +1351,9 @@
/// "@protocol identifier ;" should be resolved as "@protocol
/// identifier-list ;": objc-interface-decl-list may not start with a
/// semicolon in the first alternative if objc-protocol-refs are omitted.
-Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
- ParsedAttributes &attrs) {
+Parser::DeclGroupPtrTy
+Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
+ ParsedAttributes &attrs) {
assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
"ParseObjCAtProtocolDeclaration(): Expected @protocol");
ConsumeToken(); // the "protocol" identifier
@@ -1352,12 +1361,12 @@
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCProtocolDecl(getCurScope());
cutOffParsing();
- return 0;
+ return DeclGroupPtrTy();
}
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing protocol name.
- return 0;
+ return DeclGroupPtrTy();
}
// Save the protocol name, then consume it.
IdentifierInfo *protocolName = Tok.getIdentifierInfo();
@@ -1382,7 +1391,7 @@
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::semi);
- return 0;
+ return DeclGroupPtrTy();
}
ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
Tok.getLocation()));
@@ -1393,7 +1402,7 @@
}
// Consume the ';'.
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
- return 0;
+ return DeclGroupPtrTy();
return Actions.ActOnForwardProtocolDeclaration(AtLoc,
&ProtocolRefs[0],
@@ -1409,7 +1418,7 @@
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false,
LAngleLoc, EndProtoLoc))
- return 0;
+ return DeclGroupPtrTy();
Decl *ProtoType =
Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
@@ -1419,7 +1428,7 @@
EndProtoLoc, attrs.getList());
ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);
- return ProtoType;
+ return Actions.ConvertDeclToDeclGroup(ProtoType);
}
/// objc-implementation:
Modified: cfe/branches/tooling/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Parse/ParseStmt.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Parse/ParseStmt.cpp (original)
+++ cfe/branches/tooling/lib/Parse/ParseStmt.cpp Fri Jan 20 10:14:22 2012
@@ -76,7 +76,8 @@
/// [OBC] '@' 'throw' ';'
///
StmtResult
-Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) {
+Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
+ SourceLocation *TrailingElseLoc) {
const char *SemiError = 0;
StmtResult Res;
@@ -234,18 +235,18 @@
}
case tok::kw_if: // C99 6.8.4.1: if-statement
- return ParseIfStatement(attrs);
+ return ParseIfStatement(attrs, TrailingElseLoc);
case tok::kw_switch: // C99 6.8.4.2: switch-statement
- return ParseSwitchStatement(attrs);
+ return ParseSwitchStatement(attrs, TrailingElseLoc);
case tok::kw_while: // C99 6.8.5.1: while-statement
- return ParseWhileStatement(attrs);
+ return ParseWhileStatement(attrs, TrailingElseLoc);
case tok::kw_do: // C99 6.8.5.2: do-statement
Res = ParseDoStatement(attrs);
SemiError = "do/while";
break;
case tok::kw_for: // C99 6.8.5.3: for-statement
- return ParseForStatement(attrs);
+ return ParseForStatement(attrs, TrailingElseLoc);
case tok::kw_goto: // C99 6.8.6.1: goto-statement
Res = ParseGotoStatement(attrs);
@@ -874,7 +875,8 @@
/// [C++] 'if' '(' condition ')' statement
/// [C++] 'if' '(' condition ')' statement 'else' statement
///
-StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) {
+StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs,
+ SourceLocation *TrailingElseLoc) {
// FIXME: Use attributes?
assert(Tok.is(tok::kw_if) && "Not an if stmt!");
@@ -933,7 +935,9 @@
// Read the 'then' stmt.
SourceLocation ThenStmtLoc = Tok.getLocation();
- StmtResult ThenStmt(ParseStatement());
+
+ SourceLocation InnerStatementTrailingElseLoc;
+ StmtResult ThenStmt(ParseStatement(&InnerStatementTrailingElseLoc));
// Pop the 'if' scope if needed.
InnerScope.Exit();
@@ -944,6 +948,9 @@
StmtResult ElseStmt;
if (Tok.is(tok::kw_else)) {
+ if (TrailingElseLoc)
+ *TrailingElseLoc = Tok.getLocation();
+
ElseLoc = ConsumeToken();
ElseStmtLoc = Tok.getLocation();
@@ -967,6 +974,8 @@
Actions.CodeCompleteAfterIf(getCurScope());
cutOffParsing();
return StmtError();
+ } else if (InnerStatementTrailingElseLoc.isValid()) {
+ Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else);
}
IfScope.Exit();
@@ -1000,7 +1009,8 @@
/// switch-statement:
/// 'switch' '(' expression ')' statement
/// [C++] 'switch' '(' condition ')' statement
-StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) {
+StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs,
+ SourceLocation *TrailingElseLoc) {
// FIXME: Use attributes?
assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
@@ -1068,7 +1078,7 @@
C99orCXX && Tok.isNot(tok::l_brace));
// Read the body statement.
- StmtResult Body(ParseStatement());
+ StmtResult Body(ParseStatement(TrailingElseLoc));
// Pop the scopes.
InnerScope.Exit();
@@ -1085,7 +1095,8 @@
/// while-statement: [C99 6.8.5.1]
/// 'while' '(' expression ')' statement
/// [C++] 'while' '(' condition ')' statement
-StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs) {
+StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs,
+ SourceLocation *TrailingElseLoc) {
// FIXME: Use attributes?
assert(Tok.is(tok::kw_while) && "Not a while stmt!");
@@ -1143,7 +1154,7 @@
C99orCXX && Tok.isNot(tok::l_brace));
// Read the body statement.
- StmtResult Body(ParseStatement());
+ StmtResult Body(ParseStatement(TrailingElseLoc));
// Pop the body scope if needed.
InnerScope.Exit();
@@ -1242,7 +1253,8 @@
/// [C++0x] for-range-initializer:
/// [C++0x] expression
/// [C++0x] braced-init-list [TODO]
-StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
+StmtResult Parser::ParseForStatement(ParsedAttributes &attrs,
+ SourceLocation *TrailingElseLoc) {
// FIXME: Use attributes?
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
@@ -1306,7 +1318,7 @@
if (Tok.is(tok::semi)) { // for (;
// no first part, eat the ';'.
ConsumeToken();
- } else if (isSimpleDeclaration()) { // for (int X = 4;
+ } else if (isForInitDeclaration()) { // for (int X = 4;
// Parse declaration, which eats the ';'.
if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
@@ -1371,6 +1383,14 @@
return StmtError();
}
Collection = ParseExpression();
+ } else if (getLang().CPlusPlus0x && Tok.is(tok::colon) &&
+ !FirstPart.isInvalid()) {
+ // User tried to write the reasonable, but ill-formed, for-range-statement
+ // for (expr : expr) { ... }
+ Diag(Tok, diag::err_for_range_expected_decl)
+ << FirstPart.get()->getSourceRange();
+ SkipUntil(tok::r_paren, false, true);
+ SecondPartIsInvalid = true;
} else {
if (!Value.isInvalid()) {
Diag(Tok, diag::err_expected_semi_for);
@@ -1459,7 +1479,7 @@
C99orCXXorObjC && Tok.isNot(tok::l_brace));
// Read the body statement.
- StmtResult Body(ParseStatement());
+ StmtResult Body(ParseStatement(TrailingElseLoc));
// Pop the body scope if needed.
InnerScope.Exit();
@@ -1914,8 +1934,6 @@
if (Tok.isNot(tok::comma)) return false;
ConsumeToken();
}
-
- return true;
}
Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
@@ -2183,7 +2201,6 @@
case IEB_Dependent:
llvm_unreachable("Dependent case handled above");
- break;
case IEB_Skip:
Braces.skipToEnd();
Modified: cfe/branches/tooling/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Parse/ParseTemplate.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/branches/tooling/lib/Parse/ParseTemplate.cpp Fri Jan 20 10:14:22 2012
@@ -31,8 +31,9 @@
ObjCDeclContextSwitch ObjCDC(*this);
if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
- return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(),
- DeclEnd);
+ return ParseExplicitInstantiation(Context,
+ SourceLocation(), ConsumeToken(),
+ DeclEnd, AS);
}
return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS,
AccessAttrs);
@@ -1107,17 +1108,19 @@
/// 'extern' [opt] 'template' declaration
///
/// Note that the 'extern' is a GNU extension and C++0x feature.
-Decl *Parser::ParseExplicitInstantiation(SourceLocation ExternLoc,
+Decl *Parser::ParseExplicitInstantiation(unsigned Context,
+ SourceLocation ExternLoc,
SourceLocation TemplateLoc,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS) {
// This isn't really required here.
ParsingDeclRAIIObject ParsingTemplateParams(*this);
- return ParseSingleDeclarationAfterTemplate(Declarator::FileContext,
+ return ParseSingleDeclarationAfterTemplate(Context,
ParsedTemplateInfo(ExternLoc,
TemplateLoc),
ParsingTemplateParams,
- DeclEnd, AS_none);
+ DeclEnd, AS);
}
SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {
Modified: cfe/branches/tooling/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Parse/ParseTentative.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Parse/ParseTentative.cpp (original)
+++ cfe/branches/tooling/lib/Parse/ParseTentative.cpp Fri Jan 20 10:14:22 2012
@@ -62,7 +62,7 @@
return true;
// simple-declaration
default:
- return isCXXSimpleDeclaration();
+ return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
}
}
@@ -75,7 +75,11 @@
/// simple-declaration:
/// decl-specifier-seq init-declarator-list[opt] ';'
///
-bool Parser::isCXXSimpleDeclaration() {
+/// (if AllowForRangeDecl specified)
+/// for ( for-range-declaration : for-range-initializer ) statement
+/// for-range-declaration:
+/// attribute-specifier-seqopt type-specifier-seq declarator
+bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
// C++ 6.8p1:
// There is an ambiguity in the grammar involving expression-statements and
// declarations: An expression-statement with a function-style explicit type
@@ -112,7 +116,7 @@
// We need tentative parsing...
TentativeParsingAction PA(*this);
- TPR = TryParseSimpleDeclaration();
+ TPR = TryParseSimpleDeclaration(AllowForRangeDecl);
PA.Revert();
// In case of an error, let the declaration parsing code handle it.
@@ -130,7 +134,12 @@
/// simple-declaration:
/// decl-specifier-seq init-declarator-list[opt] ';'
///
-Parser::TPResult Parser::TryParseSimpleDeclaration() {
+/// (if AllowForRangeDecl specified)
+/// for ( for-range-declaration : for-range-initializer ) statement
+/// for-range-declaration:
+/// attribute-specifier-seqopt type-specifier-seq declarator
+///
+Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
// We know that we have a simple-type-specifier/typename-specifier followed
// by a '('.
assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous());
@@ -150,7 +159,7 @@
if (TPR != TPResult::Ambiguous())
return TPR;
- if (Tok.isNot(tok::semi))
+ if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon)))
return TPResult::False();
return TPResult::Ambiguous();
@@ -1037,7 +1046,7 @@
case tok::kw___underlying_type:
return TPResult::True();
- // C1x _Atomic
+ // C11 _Atomic
case tok::kw__Atomic:
return TPResult::True();
Modified: cfe/branches/tooling/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Parse/Parser.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Parse/Parser.cpp (original)
+++ cfe/branches/tooling/lib/Parse/Parser.cpp Fri Jan 20 10:14:22 2012
@@ -552,7 +552,7 @@
// TODO: Invoke action for top-level semicolon.
return DeclGroupPtrTy();
case tok::r_brace:
- Diag(Tok, diag::err_expected_external_declaration);
+ Diag(Tok, diag::err_extraneous_closing_brace);
ConsumeBrace();
return DeclGroupPtrTy();
case tok::eof:
@@ -581,7 +581,6 @@
}
case tok::at:
return ParseObjCAtDirectives();
- break;
case tok::minus:
case tok::plus:
if (!getLang().ObjC1) {
@@ -656,7 +655,8 @@
diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc);
SourceLocation DeclEnd;
return Actions.ConvertDeclToDeclGroup(
- ParseExplicitInstantiation(ExternLoc, TemplateLoc, DeclEnd));
+ ParseExplicitInstantiation(Declarator::FileContext,
+ ExternLoc, TemplateLoc, DeclEnd));
}
// FIXME: Detect C++ linkage specifications here?
goto dont_know;
@@ -665,9 +665,6 @@
case tok::kw___if_not_exists:
ParseMicrosoftIfExistsExternalDeclaration();
return DeclGroupPtrTy();
-
- case tok::kw___import_module__:
- return ParseModuleImport();
default:
dont_know:
@@ -775,12 +772,11 @@
if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID))
Diag(AtLoc, DiagID) << PrevSpec;
- Decl *TheDecl = 0;
if (Tok.isObjCAtKeyword(tok::objc_protocol))
- TheDecl = ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes());
- else
- TheDecl = ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes());
- return Actions.ConvertDeclToDeclGroup(TheDecl);
+ return ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes());
+
+ return Actions.ConvertDeclToDeclGroup(
+ ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()));
}
// If the declspec consisted only of 'extern' and we have a string
@@ -932,7 +928,7 @@
if (Tok.is(tok::kw_delete)) {
Diag(Tok, getLang().CPlusPlus0x ?
diag::warn_cxx98_compat_deleted_function :
- diag::warn_deleted_function_accepted_as_extension);
+ diag::ext_deleted_function);
KWLoc = ConsumeToken();
Actions.SetDeclDeleted(Res, KWLoc);
@@ -940,7 +936,7 @@
} else if (Tok.is(tok::kw_default)) {
Diag(Tok, getLang().CPlusPlus0x ?
diag::warn_cxx98_compat_defaulted_function :
- diag::warn_defaulted_function_accepted_as_extension);
+ diag::ext_defaulted_function);
KWLoc = ConsumeToken();
Actions.SetDeclDefaulted(Res, KWLoc);
@@ -1070,11 +1066,12 @@
if (Tok.isNot(tok::comma))
break;
+ ParmDeclarator.clear();
+
// Consume the comma.
- ConsumeToken();
+ ParmDeclarator.setCommaLoc(ConsumeToken());
// Parse the next declarator.
- ParmDeclarator.clear();
ParseDeclarator(ParmDeclarator);
}
@@ -1404,18 +1401,31 @@
return false;
}
-bool Parser::isTokenEqualOrMistypedEqualEqual(unsigned DiagID) {
- if (Tok.is(tok::equalequal)) {
- // We have '==' in a context that we would expect a '='.
- // The user probably made a typo, intending to type '='. Emit diagnostic,
- // fixit hint to turn '==' -> '=' and continue as if the user typed '='.
- Diag(Tok, DiagID)
- << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()),
- getTokenSimpleSpelling(tok::equal));
+bool Parser::isTokenEqualOrEqualTypo() {
+ tok::TokenKind Kind = Tok.getKind();
+ switch (Kind) {
+ default:
+ return false;
+ case tok::ampequal: // &=
+ case tok::starequal: // *=
+ case tok::plusequal: // +=
+ case tok::minusequal: // -=
+ case tok::exclaimequal: // !=
+ case tok::slashequal: // /=
+ case tok::percentequal: // %=
+ case tok::lessequal: // <=
+ case tok::lesslessequal: // <<=
+ case tok::greaterequal: // >=
+ case tok::greatergreaterequal: // >>=
+ case tok::caretequal: // ^=
+ case tok::pipeequal: // |=
+ case tok::equalequal: // ==
+ Diag(Tok, diag::err_invalid_token_after_declarator_suggest_equal)
+ << getTokenSimpleSpelling(Kind)
+ << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "=");
+ case tok::equal:
return true;
}
-
- return Tok.is(tok::equal);
}
SourceLocation Parser::handleUnexpectedCodeCompletionToken() {
@@ -1569,8 +1579,8 @@
Braces.consumeClose();
}
-Parser::DeclGroupPtrTy Parser::ParseModuleImport() {
- assert(Tok.is(tok::kw___import_module__) &&
+Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_import) &&
"Improper start to module import");
SourceLocation ImportLoc = ConsumeToken();
@@ -1596,7 +1606,7 @@
break;
} while (true);
- DeclResult Import = Actions.ActOnModuleImport(ImportLoc, Path);
+ DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path);
ExpectAndConsumeSemi(diag::err_module_expected_semi);
if (Import.isInvalid())
return DeclGroupPtrTy();
Modified: cfe/branches/tooling/lib/Rewrite/HTMLRewrite.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Rewrite/HTMLRewrite.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Rewrite/HTMLRewrite.cpp (original)
+++ cfe/branches/tooling/lib/Rewrite/HTMLRewrite.cpp Fri Jan 20 10:14:22 2012
@@ -381,7 +381,6 @@
default: break;
case tok::identifier:
llvm_unreachable("tok::identifier in raw lexing mode!");
- break;
case tok::raw_identifier: {
// Fill in Result.IdentifierInfo and update the token kind,
// looking up the identifier in the identifier table.
Modified: cfe/branches/tooling/lib/Rewrite/RewriteObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Rewrite/RewriteObjC.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Rewrite/RewriteObjC.cpp (original)
+++ cfe/branches/tooling/lib/Rewrite/RewriteObjC.cpp Fri Jan 20 10:14:22 2012
@@ -165,10 +165,20 @@
// Top Level Driver code.
virtual bool HandleTopLevelDecl(DeclGroupRef D) {
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
- if (isa<ObjCClassDecl>((*I))) {
- RewriteForwardClassDecl(D);
- break;
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*I)) {
+ if (!Class->isThisDeclarationADefinition()) {
+ RewriteForwardClassDecl(D);
+ break;
+ }
+ }
+
+ if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*I)) {
+ if (!Proto->isThisDeclarationADefinition()) {
+ RewriteForwardProtocolDecl(D);
+ break;
+ }
}
+
HandleTopLevelSingleDecl(*I);
}
return true;
@@ -256,7 +266,7 @@
void RewriteInclude();
void RewriteForwardClassDecl(DeclGroupRef D);
void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG);
- void RewriteForwardClassEpilogue(ObjCClassDecl *ClassDecl,
+ void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
const std::string &typedefString);
void RewriteImplementations();
void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
@@ -272,7 +282,8 @@
ValueDecl *VD, bool def=false);
void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
- void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl);
+ void RewriteForwardProtocolDecl(DeclGroupRef D);
+ void RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG);
void RewriteMethodDeclaration(ObjCMethodDecl *Method);
void RewriteProperty(ObjCPropertyDecl *prop);
void RewriteFunctionDecl(FunctionDecl *FD);
@@ -659,37 +670,51 @@
} else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
RewriteCategoryDecl(CD);
} else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
- RewriteProtocolDecl(PD);
- } else if (ObjCForwardProtocolDecl *FP =
- dyn_cast<ObjCForwardProtocolDecl>(D)){
- RewriteForwardProtocolDecl(FP);
+ if (PD->isThisDeclarationADefinition())
+ RewriteProtocolDecl(PD);
} else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
// Recurse into linkage specifications
for (DeclContext::decl_iterator DI = LSD->decls_begin(),
DIEnd = LSD->decls_end();
DI != DIEnd; ) {
- if (isa<ObjCClassDecl>((*DI))) {
- SmallVector<Decl *, 8> DG;
- Decl *D = (*DI);
- SourceLocation Loc = D->getLocation();
- while (DI != DIEnd &&
- isa<ObjCClassDecl>(D) && D->getLocation() == Loc) {
- ObjCClassDecl *Class = cast<ObjCClassDecl>(D);
- DG.push_back(D);
- ++DI;
- D = (*DI);
-
- // Following the ObjCClassDecl, we should have the corresponding
- // ObjCInterfaceDecl. Skip over it.
- if (DI != DIEnd && isa<ObjCInterfaceDecl>(D) &&
- Class->getForwardInterfaceDecl() == D) {
+ if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>((*DI))) {
+ if (!IFace->isThisDeclarationADefinition()) {
+ SmallVector<Decl *, 8> DG;
+ SourceLocation StartLoc = IFace->getLocStart();
+ do {
+ if (isa<ObjCInterfaceDecl>(*DI) &&
+ !cast<ObjCInterfaceDecl>(*DI)->isThisDeclarationADefinition() &&
+ StartLoc == (*DI)->getLocStart())
+ DG.push_back(*DI);
+ else
+ break;
+
++DI;
- D = (*DI);
- }
+ } while (DI != DIEnd);
+ RewriteForwardClassDecl(DG);
+ continue;
+ }
+ }
+
+ if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>((*DI))) {
+ if (!Proto->isThisDeclarationADefinition()) {
+ SmallVector<Decl *, 8> DG;
+ SourceLocation StartLoc = Proto->getLocStart();
+ do {
+ if (isa<ObjCProtocolDecl>(*DI) &&
+ !cast<ObjCProtocolDecl>(*DI)->isThisDeclarationADefinition() &&
+ StartLoc == (*DI)->getLocStart())
+ DG.push_back(*DI);
+ else
+ break;
+
+ ++DI;
+ } while (DI != DIEnd);
+ RewriteForwardProtocolDecl(DG);
+ continue;
}
- RewriteForwardClassDecl(DG);
- continue;
}
+
HandleTopLevelSingleDecl(*DI);
++DI;
}
@@ -873,9 +898,9 @@
typedefString += ";\n#endif\n";
}
-void RewriteObjC::RewriteForwardClassEpilogue(ObjCClassDecl *ClassDecl,
+void RewriteObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
const std::string &typedefString) {
- SourceLocation startLoc = ClassDecl->getLocation();
+ SourceLocation startLoc = ClassDecl->getLocStart();
const char *startBuf = SM->getCharacterData(startLoc);
const char *semiPtr = strchr(startBuf, ';');
// Replace the @class with typedefs corresponding to the classes.
@@ -885,8 +910,7 @@
void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) {
std::string typedefString;
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
- ObjCClassDecl *ClassDecl = cast<ObjCClassDecl>(*I);
- ObjCInterfaceDecl *ForwardDecl = ClassDecl->getForwardInterfaceDecl();
+ ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(*I);
if (I == D.begin()) {
// Translate to typedef's that forward reference structs with the same name
// as the class. As a convenience, we include the original declaration
@@ -898,15 +922,14 @@
RewriteOneForwardClassDecl(ForwardDecl, typedefString);
}
DeclGroupRef::iterator I = D.begin();
- RewriteForwardClassEpilogue(cast<ObjCClassDecl>(*I), typedefString);
+ RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(*I), typedefString);
}
void RewriteObjC::RewriteForwardClassDecl(
const llvm::SmallVector<Decl*, 8> &D) {
std::string typedefString;
for (unsigned i = 0; i < D.size(); i++) {
- ObjCClassDecl *ClassDecl = cast<ObjCClassDecl>(D[i]);
- ObjCInterfaceDecl *ForwardDecl = ClassDecl->getForwardInterfaceDecl();
+ ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]);
if (i == 0) {
typedefString += "// @class ";
typedefString += ForwardDecl->getNameAsString();
@@ -914,7 +937,7 @@
}
RewriteOneForwardClassDecl(ForwardDecl, typedefString);
}
- RewriteForwardClassEpilogue(cast<ObjCClassDecl>(D[0]), typedefString);
+ RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(D[0]), typedefString);
}
void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
@@ -967,7 +990,8 @@
void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
SourceLocation LocStart = PDecl->getLocStart();
-
+ assert(PDecl->isThisDeclarationADefinition());
+
// FIXME: handle protocol headers that are declared across multiple lines.
ReplaceText(LocStart, 0, "// ");
@@ -1005,8 +1029,17 @@
}
}
-void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
- SourceLocation LocStart = PDecl->getLocation();
+void RewriteObjC::RewriteForwardProtocolDecl(DeclGroupRef D) {
+ SourceLocation LocStart = (*D.begin())->getLocStart();
+ if (LocStart.isInvalid())
+ llvm_unreachable("Invalid SourceLocation");
+ // FIXME: handle forward protocol that are declared across multiple lines.
+ ReplaceText(LocStart, 0, "// ");
+}
+
+void
+RewriteObjC::RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG) {
+ SourceLocation LocStart = DG[0]->getLocStart();
if (LocStart.isInvalid())
llvm_unreachable("Invalid SourceLocation");
// FIXME: handle forward protocol that are declared across multiple lines.
@@ -1255,7 +1288,7 @@
SmallVector<SourceLocation, 1> SelLocs;
OldMsg->getSelectorLocs(SelLocs);
- ObjCMessageExpr *NewMsg;
+ ObjCMessageExpr *NewMsg = 0;
switch (OldMsg->getReceiverKind()) {
case ObjCMessageExpr::Class:
NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
@@ -1266,7 +1299,8 @@
SelLocs,
OldMsg->getMethodDecl(),
RHS,
- OldMsg->getRightLoc());
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
break;
case ObjCMessageExpr::Instance:
@@ -1278,7 +1312,8 @@
SelLocs,
OldMsg->getMethodDecl(),
RHS,
- OldMsg->getRightLoc());
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
break;
case ObjCMessageExpr::SuperClass:
@@ -1293,7 +1328,8 @@
SelLocs,
OldMsg->getMethodDecl(),
RHS,
- OldMsg->getRightLoc());
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
break;
}
@@ -1328,7 +1364,7 @@
SmallVector<SourceLocation, 1> SelLocs;
SmallVector<Expr*, 1> Args;
- ObjCMessageExpr *NewMsg;
+ ObjCMessageExpr *NewMsg = 0;
switch (OldMsg->getReceiverKind()) {
case ObjCMessageExpr::Class:
NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
@@ -1339,7 +1375,8 @@
SelLocs,
OldMsg->getMethodDecl(),
Args,
- OldMsg->getRightLoc());
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
break;
case ObjCMessageExpr::Instance:
@@ -1351,7 +1388,8 @@
SelLocs,
OldMsg->getMethodDecl(),
Args,
- OldMsg->getRightLoc());
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
break;
case ObjCMessageExpr::SuperClass:
@@ -1366,7 +1404,8 @@
SelLocs,
OldMsg->getMethodDecl(),
Args,
- OldMsg->getRightLoc());
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
break;
}
@@ -2478,7 +2517,7 @@
false);
}
-// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
+// SynthGetMetaClassFunctionDecl - id objc_getMetaClass(const char *name);
void RewriteObjC::SynthGetMetaClassFunctionDecl() {
IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");
SmallVector<QualType, 16> ArgTys;
@@ -2673,7 +2712,7 @@
// (Class)objc_getClass("CurrentClass")
CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
Context->getObjCClassType(),
- CK_CPointerToObjCPointerCast, Cls);
+ CK_BitCast, Cls);
ClsExprs.clear();
ClsExprs.push_back(ArgExpr);
Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
@@ -3088,7 +3127,7 @@
CK_BitCast,
DerefExpr);
ReplaceStmt(Exp, castExpr);
- ProtocolExprDecls.insert(Exp->getProtocol());
+ ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl());
// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
return castExpr;
@@ -4990,10 +5029,6 @@
RewriteRecordBody(RD);
break;
}
- case Decl::ObjCClass: {
- llvm_unreachable("RewriteObjC::HandleDeclInMainFile - ObjCClassDecl");
- break;
- }
default:
break;
}
@@ -5178,7 +5213,7 @@
static bool objc_protocol_methods = false;
// Output struct protocol_methods holder of method selector and type.
- if (!objc_protocol_methods && !PDecl->isForwardDecl()) {
+ if (!objc_protocol_methods && PDecl->hasDefinition()) {
/* struct protocol_methods {
SEL _cmd;
char *method_types;
@@ -5192,9 +5227,12 @@
objc_protocol_methods = true;
}
// Do not synthesize the protocol more than once.
- if (ObjCSynthesizedProtocols.count(PDecl))
+ if (ObjCSynthesizedProtocols.count(PDecl->getCanonicalDecl()))
return;
+ if (ObjCProtocolDecl *Def = PDecl->getDefinition())
+ PDecl = Def;
+
if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
unsigned NumMethods = std::distance(PDecl->instmeth_begin(),
PDecl->instmeth_end());
@@ -5314,7 +5352,7 @@
Result += "};\n";
// Mark this protocol as having been generated.
- if (!ObjCSynthesizedProtocols.insert(PDecl))
+ if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl()))
llvm_unreachable("protocol already synthesized");
}
Modified: cfe/branches/tooling/lib/Sema/AnalysisBasedWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/AnalysisBasedWarnings.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/AnalysisBasedWarnings.cpp (original)
+++ cfe/branches/tooling/lib/Sema/AnalysisBasedWarnings.cpp Fri Jan 20 10:14:22 2012
@@ -415,42 +415,15 @@
return false;
// Suggest possible initialization (if any).
- const char *initialization = 0;
QualType VariableTy = VD->getType().getCanonicalType();
-
- if (VariableTy->isObjCObjectPointerType() ||
- VariableTy->isBlockPointerType()) {
- // Check if 'nil' is defined.
- if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil")))
- initialization = " = nil";
- else
- initialization = " = 0";
- }
- else if (VariableTy->isRealFloatingType())
- initialization = " = 0.0";
- else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus)
- initialization = " = false";
- else if (VariableTy->isEnumeralType())
+ const char *Init = S.getFixItZeroInitializerForType(VariableTy);
+ if (!Init)
return false;
- else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) {
- if (S.Context.getLangOptions().CPlusPlus0x)
- initialization = " = nullptr";
- // Check if 'NULL' is defined.
- else if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL")))
- initialization = " = NULL";
- else
- initialization = " = 0";
- }
- else if (VariableTy->isScalarType())
- initialization = " = 0";
-
- if (initialization) {
- SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
- S.Diag(loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
- << FixItHint::CreateInsertion(loc, initialization);
- return true;
- }
- return false;
+
+ SourceLocation Loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
+ S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
+ << FixItHint::CreateInsertion(Loc, Init);
+ return true;
}
/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
@@ -634,6 +607,7 @@
}
};
+namespace {
class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
Sema &S;
DiagList Warnings;
@@ -744,6 +718,7 @@
};
}
}
+}
//===----------------------------------------------------------------------===//
// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
Modified: cfe/branches/tooling/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/AttributeList.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/AttributeList.cpp (original)
+++ cfe/branches/tooling/lib/Sema/AttributeList.cpp Fri Jan 20 10:14:22 2012
@@ -108,6 +108,7 @@
.Case("weak", AT_weak)
.Case("weakref", AT_weakref)
.Case("objc_arc_weak_reference_unavailable", AT_arc_weakref_unavailable)
+ .Case("objc_requires_property_definitions", AT_objc_requires_property_definitions)
.Case("pure", AT_pure)
.Case("mode", AT_mode)
.Case("used", AT_used)
Modified: cfe/branches/tooling/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/CMakeLists.txt?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/CMakeLists.txt (original)
+++ cfe/branches/tooling/lib/Sema/CMakeLists.txt Fri Jan 20 10:14:22 2012
@@ -17,6 +17,7 @@
SemaCast.cpp
SemaChecking.cpp
SemaCodeComplete.cpp
+ SemaConsumer.cpp
SemaDecl.cpp
SemaDeclAttr.cpp
SemaDeclCXX.cpp
Modified: cfe/branches/tooling/lib/Sema/CodeCompleteConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/CodeCompleteConsumer.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/CodeCompleteConsumer.cpp (original)
+++ cfe/branches/tooling/lib/Sema/CodeCompleteConsumer.cpp Fri Jan 20 10:14:22 2012
@@ -71,8 +71,8 @@
case CCC_ObjCCategoryName:
return false;
}
-
- return false;
+
+ llvm_unreachable("Invalid CodeCompletionContext::Kind!");
}
//===----------------------------------------------------------------------===//
@@ -93,7 +93,6 @@
case CK_Optional:
llvm_unreachable("Optional strings cannot be created from text");
- break;
case CK_LeftParen:
this->Text = "(";
@@ -330,8 +329,8 @@
case CK_FunctionType:
return Type;
}
-
- return 0;
+
+ llvm_unreachable("Invalid CandidateKind!");
}
//===----------------------------------------------------------------------===//
@@ -424,8 +423,17 @@
Availability = CXAvailability_NotAvailable;
CursorKind = getCursorKindForDecl(Declaration);
- if (CursorKind == CXCursor_UnexposedDecl)
- CursorKind = CXCursor_NotImplemented;
+ if (CursorKind == CXCursor_UnexposedDecl) {
+ // FIXME: Forward declarations of Objective-C classes and protocols
+ // are not directly exposed, but we want code completion to treat them
+ // like a definition.
+ if (isa<ObjCInterfaceDecl>(Declaration))
+ CursorKind = CXCursor_ObjCInterfaceDecl;
+ else if (isa<ObjCProtocolDecl>(Declaration))
+ CursorKind = CXCursor_ObjCProtocolDecl;
+ else
+ CursorKind = CXCursor_NotImplemented;
+ }
break;
case RK_Macro:
Modified: cfe/branches/tooling/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/DeclSpec.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/DeclSpec.cpp (original)
+++ cfe/branches/tooling/lib/Sema/DeclSpec.cpp Fri Jan 20 10:14:22 2012
@@ -245,7 +245,6 @@
return false;
}
llvm_unreachable("Invalid type chunk");
- return false;
}
switch (DS.getTypeSpecType()) {
@@ -295,8 +294,8 @@
return QT->isFunctionType();
}
}
-
- return false;
+
+ llvm_unreachable("Invalid TypeSpecType!");
}
/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
@@ -867,7 +866,8 @@
TypeSpecType = TST_double; // _Complex -> _Complex double.
} else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
// Note that this intentionally doesn't include _Complex _Bool.
- Diag(D, TSTLoc, diag::ext_integer_complex);
+ if (!PP.getLangOptions().CPlusPlus)
+ Diag(D, TSTLoc, diag::ext_integer_complex);
} else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
Diag(D, TSCLoc, diag::err_invalid_complex_spec)
<< getSpecifierName((TST)TypeSpecType);
Modified: cfe/branches/tooling/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/Sema.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/Sema.cpp (original)
+++ cfe/branches/tooling/lib/Sema/Sema.cpp Fri Jan 20 10:14:22 2012
@@ -55,10 +55,12 @@
}
BlockScopeInfo::~BlockScopeInfo() { }
+LambdaScopeInfo::~LambdaScopeInfo() { }
-PrintingPolicy Sema::getPrintingPolicy() const {
+PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
+ const Preprocessor &PP) {
PrintingPolicy Policy = Context.getPrintingPolicy();
- Policy.Bool = getLangOptions().Bool;
+ Policy.Bool = Context.getLangOptions().Bool;
if (!Policy.Bool) {
if (MacroInfo *BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) {
Policy.Bool = BoolMacro->isObjectLike() &&
@@ -75,19 +77,6 @@
PushDeclContext(S, Context.getTranslationUnitDecl());
VAListTagName = PP.getIdentifierInfo("__va_list_tag");
-
- if (PP.getLangOptions().ObjC1) {
- // Synthesize "@class Protocol;
- if (Context.getObjCProtoType().isNull()) {
- ObjCInterfaceDecl *ProtocolDecl =
- ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
- &Context.Idents.get("Protocol"),
- /*PrevDecl=*/0,
- SourceLocation(), true);
- Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
- PushOnScopeChains(ProtocolDecl, TUScope, false);
- }
- }
}
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
@@ -100,7 +89,7 @@
CurContext(0), OriginalLexicalContext(0),
PackContext(0), MSStructPragmaOn(false), VisContext(0),
ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
- IdResolver(pp), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
+ IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
GlobalNewDeleteDeclared(false),
ObjCShouldCallSuperDealloc(false),
ObjCShouldCallSuperFinalize(false),
@@ -172,6 +161,11 @@
DeclarationName Class = &Context.Idents.get("Class");
if (IdResolver.begin(Class) == IdResolver.end())
PushOnScopeChains(Context.getObjCClassDecl(), TUScope);
+
+ // Create the built-in forward declaratino for 'Protocol'.
+ DeclarationName Protocol = &Context.Idents.get("Protocol");
+ if (IdResolver.begin(Protocol) == IdResolver.end())
+ PushOnScopeChains(Context.getObjCProtocolDecl(), TUScope);
}
}
@@ -320,7 +314,7 @@
// Later redecls may add new information resulting in not having to warn,
// so check again.
- DeclToCheck = FD->getMostRecentDeclaration();
+ DeclToCheck = FD->getMostRecentDecl();
if (DeclToCheck != FD)
return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck);
}
@@ -334,7 +328,7 @@
// Later redecls may add new information resulting in not having to warn,
// so check again.
- DeclToCheck = VD->getMostRecentDeclaration();
+ DeclToCheck = VD->getMostRecentDecl();
if (DeclToCheck != VD)
return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck);
}
@@ -503,10 +497,10 @@
ModMap.resolveExports(Mod, /*Complain=*/false);
// Queue the submodules, so their exports will also be resolved.
- for (llvm::StringMap<Module *>::iterator Sub = Mod->SubModules.begin(),
- SubEnd = Mod->SubModules.end();
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
Sub != SubEnd; ++Sub) {
- Stack.push_back(Sub->getValue());
+ Stack.push_back(*Sub);
}
}
}
@@ -635,8 +629,15 @@
DeclContext *Sema::getFunctionLevelDeclContext() {
DeclContext *DC = CurContext;
- while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC))
- DC = DC->getParent();
+ while (true) {
+ if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) {
+ DC = DC->getParent();
+ } else if (isa<CXXMethodDecl>(DC) &&
+ cast<CXXRecordDecl>(DC->getParent())->isLambda()) {
+ DC = DC->getParent()->getParent();
+ }
+ else break;
+ }
return DC;
}
@@ -828,8 +829,12 @@
BlockScope, Block));
}
-void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP,
- const Decl *D, const BlockExpr *blkExpr) {
+void Sema::PushLambdaScope(CXXRecordDecl *Lambda) {
+ FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda));
+}
+
+void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
+ const Decl *D, const BlockExpr *blkExpr) {
FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
assert(!FunctionScopes.empty() && "mismatched push/pop!");
@@ -864,6 +869,13 @@
return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
}
+LambdaScopeInfo *Sema::getCurLambda() {
+ if (FunctionScopes.empty())
+ return 0;
+
+ return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
+}
+
// Pin this vtable to this file.
ExternalSemaSource::~ExternalSemaSource() {}
Modified: cfe/branches/tooling/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaAccess.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaAccess.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaAccess.cpp Fri Jan 20 10:14:22 2012
@@ -797,7 +797,6 @@
// Silence bogus warnings
llvm_unreachable("impossible friendship kind");
- return OnFailure;
}
/// Finds the best path from the naming class to the declaring class,
@@ -1020,15 +1019,15 @@
while (D->isOutOfLine()) {
NamedDecl *PrevDecl = 0;
if (VarDecl *VD = dyn_cast<VarDecl>(D))
- PrevDecl = VD->getPreviousDeclaration();
+ PrevDecl = VD->getPreviousDecl();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- PrevDecl = FD->getPreviousDeclaration();
+ PrevDecl = FD->getPreviousDecl();
else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
- PrevDecl = TND->getPreviousDeclaration();
+ PrevDecl = TND->getPreviousDecl();
else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
break;
- PrevDecl = TD->getPreviousDeclaration();
+ PrevDecl = TD->getPreviousDecl();
}
if (!PrevDecl) break;
D = PrevDecl;
@@ -1068,7 +1067,6 @@
case AR_dependent:
llvm_unreachable("can't diagnose dependent access failures");
- return;
}
}
@@ -1166,7 +1164,7 @@
if (Entity.getTargetDecl()->getAccess() == AS_private &&
(OrigDecl->getAccess() == AS_public ||
OrigDecl->getAccess() == AS_protected)) {
- S.Diag(AccessLoc, diag::war_ms_using_declaration_inaccessible)
+ S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible)
<< Shadow->getUsingDecl()->getQualifiedNameAsString()
<< OrigDecl->getQualifiedNameAsString();
return true;
@@ -1298,7 +1296,6 @@
// silence unnecessary warning
llvm_unreachable("invalid access result");
- return AR_accessible;
}
static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
@@ -1333,7 +1330,6 @@
case AR_dependent: return Sema::AR_dependent;
}
llvm_unreachable("falling off end");
- return Sema::AR_accessible;
}
void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *decl) {
Modified: cfe/branches/tooling/lib/Sema/SemaAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaAttr.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaAttr.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaAttr.cpp Fri Jan 20 10:14:22 2012
@@ -263,9 +263,6 @@
Context->setAlignment(AlignmentVal);
}
break;
-
- default:
- llvm_unreachable("Invalid #pragma pack kind.");
}
}
Modified: cfe/branches/tooling/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaCXXScopeSpec.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaCXXScopeSpec.cpp Fri Jan 20 10:14:22 2012
@@ -150,14 +150,13 @@
const TagType *Tag = NNS->getAsType()->getAs<TagType>();
assert(Tag && "Non-tag type in nested-name-specifier");
return Tag->getDecl();
- } break;
+ }
case NestedNameSpecifier::Global:
return Context.getTranslationUnitDecl();
}
- // Required to silence a GCC warning.
- return 0;
+ llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
@@ -363,6 +362,25 @@
return false;
}
+namespace {
+
+// Callback to only accept typo corrections that can be a valid C++ member
+// intializer: either a non-static field member or a base class.
+class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ explicit NestedNameSpecifierValidatorCCC(Sema &SRef)
+ : SRef(SRef) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ return SRef.isAcceptableNestedNameSpecifier(candidate.getCorrectionDecl());
+ }
+
+ private:
+ Sema &SRef;
+};
+
+}
+
/// \brief Build a new nested-name-specifier for "identifier::", as described
/// by ActOnCXXNestedNameSpecifier.
///
@@ -478,12 +496,12 @@
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
+ NestedNameSpecifierValidatorCCC Validator(*this);
TypoCorrection Corrected;
Found.clear();
if ((Corrected = CorrectTypo(Found.getLookupNameInfo(),
- Found.getLookupKind(), S, &SS, LookupCtx,
- EnteringContext, CTC_NoKeywords)) &&
- isAcceptableNestedNameSpecifier(Corrected.getCorrectionDecl())) {
+ Found.getLookupKind(), S, &SS, &Validator,
+ LookupCtx, EnteringContext))) {
std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
if (LookupCtx)
@@ -880,8 +898,7 @@
return true;
}
- // Silence bogus warning.
- return false;
+ llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
Modified: cfe/branches/tooling/lib/Sema/SemaCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaCast.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaCast.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaCast.cpp Fri Jan 20 10:14:22 2012
@@ -295,8 +295,6 @@
OpLoc, Parens.getEnd()));
}
}
-
- return ExprError();
}
/// Try to diagnose a failed overloaded cast. Returns true if
@@ -346,7 +344,6 @@
switch (sequence.getFailedOverloadResult()) {
case OR_Success: llvm_unreachable("successful failed overload");
- return false;
case OR_No_Viable_Function:
if (candidates.empty())
msg = diag::err_ovl_no_conversion_in_cast;
@@ -529,11 +526,12 @@
/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime-
/// checked downcasts in class hierarchies.
void CastOperation::CheckDynamicCast() {
- if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) {
+ if (ValueKind == VK_RValue)
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
- if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
- return;
- }
+ else if (isPlaceholder())
+ SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take());
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
QualType OrigSrcType = SrcExpr.get()->getType();
QualType DestType = Self.Context.getCanonicalType(this->DestType);
@@ -662,11 +660,12 @@
/// const char *str = "literal";
/// legacy_function(const_cast\<char*\>(str));
void CastOperation::CheckConstCast() {
- if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) {
+ if (ValueKind == VK_RValue)
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
- if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
- return;
- }
+ else if (isPlaceholder())
+ SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take());
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryConstCast(Self, SrcExpr.get(), DestType, /*CStyle*/false, msg) != TC_Success
@@ -681,11 +680,12 @@
/// like this:
/// char *bytes = reinterpret_cast\<char*\>(int_ptr);
void CastOperation::CheckReinterpretCast() {
- if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) {
+ if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload))
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
- if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
- return;
- }
+ else
+ checkNonOverloadPlaceholders();
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
unsigned msg = diag::err_bad_cxx_cast_generic;
TryCastResult tcr =
@@ -1894,6 +1894,11 @@
if (SrcExpr.isInvalid())
return;
QualType SrcType = SrcExpr.get()->getType();
+
+ // You can cast an _Atomic(T) to anything you can cast a T to.
+ if (const AtomicType *AtomicSrcType = SrcType->getAs<AtomicType>())
+ SrcType = AtomicSrcType->getValueType();
+
assert(!SrcType->isPlaceholderType());
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
Modified: cfe/branches/tooling/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaChecking.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaChecking.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaChecking.cpp Fri Jan 20 10:14:22 2012
@@ -44,23 +44,24 @@
return SL->getLocationOfByte(ByteNo, PP.getSourceManager(),
PP.getLangOptions(), PP.getTargetInfo());
}
-
-/// CheckablePrintfAttr - does a function call have a "printf" attribute
-/// and arguments that merit checking?
-bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) {
- if (Format->getType() == "printf") return true;
- if (Format->getType() == "printf0") {
+bool Sema::CheckablePrintfAttr(const FormatAttr *Format, Expr **Args,
+ unsigned NumArgs, bool IsCXXMemberCall) {
+ StringRef Type = Format->getType();
+ // FIXME: add support for "CFString" Type. They are not string literal though,
+ // so they need special handling.
+ if (Type == "printf" || Type == "NSString") return true;
+ if (Type == "printf0") {
// printf0 allows null "format" string; if so don't check format/args
unsigned format_idx = Format->getFormatIdx() - 1;
// Does the index refer to the implicit object argument?
- if (isa<CXXMemberCallExpr>(TheCall)) {
+ if (IsCXXMemberCall) {
if (format_idx == 0)
return false;
--format_idx;
}
- if (format_idx < TheCall->getNumArgs()) {
- Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts();
+ if (format_idx < NumArgs) {
+ Expr *Format = Args[format_idx]->IgnoreParenCasts();
if (!Format->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull))
return true;
@@ -277,6 +278,8 @@
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Load);
case Builtin::BI__atomic_store:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Store);
+ case Builtin::BI__atomic_init:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Init);
case Builtin::BI__atomic_exchange:
return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xchg);
case Builtin::BI__atomic_compare_exchange_strong:
@@ -340,7 +343,7 @@
assert(!shift && "cannot shift float types!");
return (2 << IsQuad) - 1;
}
- return 0;
+ llvm_unreachable("Invalid NeonTypeFlag!");
}
/// getNeonEltType - Return the QualType corresponding to the elements of
@@ -365,7 +368,7 @@
case NeonTypeFlags::Float32:
return Context.FloatTy;
}
- return QualType();
+ llvm_unreachable("Invalid NeonTypeFlag!");
}
bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
@@ -461,16 +464,7 @@
for (specific_attr_iterator<FormatAttr>
i = FDecl->specific_attr_begin<FormatAttr>(),
e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
-
- const FormatAttr *Format = *i;
- const bool b = Format->getType() == "scanf";
- if (b || CheckablePrintfAttr(Format, TheCall)) {
- bool HasVAListArg = Format->getFirstArg() == 0;
- CheckPrintfScanfArguments(TheCall, HasVAListArg,
- Format->getFormatIdx() - 1,
- HasVAListArg ? 0 : Format->getFirstArg() - 1,
- !b);
- }
+ CheckFormatArguments(*i, TheCall);
}
for (specific_attr_iterator<NonNullAttr>
@@ -480,88 +474,35 @@
TheCall->getCallee()->getLocStart());
}
- // Builtin handling
- int CMF = -1;
- switch (FDecl->getBuiltinID()) {
- case Builtin::BI__builtin_memset:
- case Builtin::BI__builtin___memset_chk:
- case Builtin::BImemset:
- CMF = CMF_Memset;
- break;
-
- case Builtin::BI__builtin_memcpy:
- case Builtin::BI__builtin___memcpy_chk:
- case Builtin::BImemcpy:
- CMF = CMF_Memcpy;
- break;
-
- case Builtin::BI__builtin_memmove:
- case Builtin::BI__builtin___memmove_chk:
- case Builtin::BImemmove:
- CMF = CMF_Memmove;
- break;
+ unsigned CMId = FDecl->getMemoryFunctionKind();
+ if (CMId == 0)
+ return false;
- case Builtin::BIstrlcpy:
- case Builtin::BIstrlcat:
+ // Handle memory setting and copying functions.
+ if (CMId == Builtin::BIstrlcpy || CMId == Builtin::BIstrlcat)
CheckStrlcpycatArguments(TheCall, FnInfo);
- break;
-
- case Builtin::BI__builtin_memcmp:
- CMF = CMF_Memcmp;
- break;
-
- case Builtin::BI__builtin_strncpy:
- case Builtin::BI__builtin___strncpy_chk:
- case Builtin::BIstrncpy:
- CMF = CMF_Strncpy;
- break;
-
- case Builtin::BI__builtin_strncmp:
- CMF = CMF_Strncmp;
- break;
+ else
+ CheckMemaccessArguments(TheCall, CMId, FnInfo);
- case Builtin::BI__builtin_strncasecmp:
- CMF = CMF_Strncasecmp;
- break;
+ return false;
+}
- case Builtin::BI__builtin_strncat:
- case Builtin::BIstrncat:
- CMF = CMF_Strncat;
- break;
+bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
+ Expr **Args, unsigned NumArgs) {
+ for (specific_attr_iterator<FormatAttr>
+ i = Method->specific_attr_begin<FormatAttr>(),
+ e = Method->specific_attr_end<FormatAttr>(); i != e ; ++i) {
- case Builtin::BI__builtin_strndup:
- case Builtin::BIstrndup:
- CMF = CMF_Strndup;
- break;
+ CheckFormatArguments(*i, Args, NumArgs, false, lbrac,
+ Method->getSourceRange());
+ }
- default:
- if (FDecl->getLinkage() == ExternalLinkage &&
- (!getLangOptions().CPlusPlus || FDecl->isExternC())) {
- if (FnInfo->isStr("memset"))
- CMF = CMF_Memset;
- else if (FnInfo->isStr("memcpy"))
- CMF = CMF_Memcpy;
- else if (FnInfo->isStr("memmove"))
- CMF = CMF_Memmove;
- else if (FnInfo->isStr("memcmp"))
- CMF = CMF_Memcmp;
- else if (FnInfo->isStr("strncpy"))
- CMF = CMF_Strncpy;
- else if (FnInfo->isStr("strncmp"))
- CMF = CMF_Strncmp;
- else if (FnInfo->isStr("strncasecmp"))
- CMF = CMF_Strncasecmp;
- else if (FnInfo->isStr("strncat"))
- CMF = CMF_Strncat;
- else if (FnInfo->isStr("strndup"))
- CMF = CMF_Strndup;
- }
- break;
+ // diagnose nonnull arguments.
+ for (specific_attr_iterator<NonNullAttr>
+ i = Method->specific_attr_begin<NonNullAttr>(),
+ e = Method->specific_attr_end<NonNullAttr>(); i != e; ++i) {
+ CheckNonNullArguments(*i, Args, lbrac);
}
-
- // Memset/memcpy/memmove handling
- if (CMF != -1)
- CheckMemaccessArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo);
return false;
}
@@ -580,13 +521,7 @@
if (!Ty->isBlockPointerType())
return false;
- const bool b = Format->getType() == "scanf";
- if (!b && !CheckablePrintfAttr(Format, TheCall))
- return false;
-
- bool HasVAListArg = Format->getFirstArg() == 0;
- CheckPrintfScanfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
- HasVAListArg ? 0 : Format->getFirstArg() - 1, !b);
+ CheckFormatArguments(Format, TheCall);
return false;
}
@@ -611,6 +546,8 @@
NumVals = 2;
NumOrders = 2;
}
+ if (Op == AtomicExpr::Init)
+ NumOrders = 0;
if (TheCall->getNumArgs() < NumVals+NumOrders+1) {
Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
@@ -673,7 +610,7 @@
}
QualType ResultType = ValType;
- if (Op == AtomicExpr::Store)
+ if (Op == AtomicExpr::Store || Op == AtomicExpr::Init)
ResultType = Context.VoidTy;
else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong)
ResultType = Context.BoolTy;
@@ -714,6 +651,8 @@
SubExprs.push_back(Ptr);
if (Op == AtomicExpr::Load) {
SubExprs.push_back(TheCall->getArg(1)); // Order
+ } else if (Op == AtomicExpr::Init) {
+ SubExprs.push_back(TheCall->getArg(1)); // Val1
} else if (Op != AtomicExpr::CmpXchgWeak && Op != AtomicExpr::CmpXchgStrong) {
SubExprs.push_back(TheCall->getArg(2)); // Order
SubExprs.push_back(TheCall->getArg(1)); // Val1
@@ -1435,8 +1374,8 @@
}
// Handle i > 1 ? "x" : "y", recursively.
-bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
- bool HasVAListArg,
+bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
+ unsigned NumArgs, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg,
bool isPrintf, bool inFunctionCall) {
tryAgain:
@@ -1449,10 +1388,10 @@
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
- return SemaCheckStringLiteral(C->getTrueExpr(), TheCall, HasVAListArg,
+ return SemaCheckStringLiteral(C->getTrueExpr(), Args, NumArgs, HasVAListArg,
format_idx, firstDataArg, isPrintf,
inFunctionCall)
- && SemaCheckStringLiteral(C->getFalseExpr(), TheCall, HasVAListArg,
+ && SemaCheckStringLiteral(C->getFalseExpr(), Args, NumArgs, HasVAListArg,
format_idx, firstDataArg, isPrintf,
inFunctionCall);
}
@@ -1500,7 +1439,7 @@
if (isConstant) {
if (const Expr *Init = VD->getAnyInitializer())
- return SemaCheckStringLiteral(Init, TheCall,
+ return SemaCheckStringLiteral(Init, Args, NumArgs,
HasVAListArg, format_idx, firstDataArg,
isPrintf, /*inFunctionCall*/false);
}
@@ -1541,7 +1480,7 @@
unsigned ArgIndex = FA->getFormatIdx();
const Expr *Arg = CE->getArg(ArgIndex - 1);
- return SemaCheckStringLiteral(Arg, TheCall, HasVAListArg,
+ return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
format_idx, firstDataArg, isPrintf,
inFunctionCall);
}
@@ -1561,7 +1500,7 @@
StrE = cast<StringLiteral>(E);
if (StrE) {
- CheckFormatString(StrE, E, TheCall, HasVAListArg, format_idx,
+ CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
firstDataArg, isPrintf, inFunctionCall);
return true;
}
@@ -1590,37 +1529,52 @@
/// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar
/// functions) for correct use of format strings.
-void
-Sema::CheckPrintfScanfArguments(const CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx, unsigned firstDataArg,
- bool isPrintf) {
-
- const Expr *Fn = TheCall->getCallee();
-
+void Sema::CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall) {
+ bool IsCXXMember = false;
// The way the format attribute works in GCC, the implicit this argument
// of member functions is counted. However, it doesn't appear in our own
// lists, so decrement format_idx in that case.
if (isa<CXXMemberCallExpr>(TheCall)) {
- const CXXMethodDecl *method_decl =
- dyn_cast<CXXMethodDecl>(TheCall->getCalleeDecl());
- if (method_decl && method_decl->isInstance()) {
- // Catch a format attribute mistakenly referring to the object argument.
+ const CXXMethodDecl *method_decl =
+ dyn_cast<CXXMethodDecl>(TheCall->getCalleeDecl());
+ IsCXXMember = method_decl && method_decl->isInstance();
+ }
+ CheckFormatArguments(Format, TheCall->getArgs(), TheCall->getNumArgs(),
+ IsCXXMember, TheCall->getRParenLoc(),
+ TheCall->getCallee()->getSourceRange());
+}
+
+void Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
+ unsigned NumArgs, bool IsCXXMember,
+ SourceLocation Loc, SourceRange Range) {
+ const bool b = Format->getType() == "scanf";
+ if (b || CheckablePrintfAttr(Format, Args, NumArgs, IsCXXMember)) {
+ bool HasVAListArg = Format->getFirstArg() == 0;
+ unsigned format_idx = Format->getFormatIdx() - 1;
+ unsigned firstDataArg = HasVAListArg ? 0 : Format->getFirstArg() - 1;
+ if (IsCXXMember) {
if (format_idx == 0)
return;
--format_idx;
if(firstDataArg != 0)
--firstDataArg;
}
+ CheckPrintfScanfArguments(Args, NumArgs, HasVAListArg, format_idx,
+ firstDataArg, !b, Loc, Range);
}
+}
+void Sema::CheckPrintfScanfArguments(Expr **Args, unsigned NumArgs,
+ bool HasVAListArg, unsigned format_idx,
+ unsigned firstDataArg, bool isPrintf,
+ SourceLocation Loc, SourceRange Range) {
// CHECK: printf/scanf-like function is called with no format string.
- if (format_idx >= TheCall->getNumArgs()) {
- Diag(TheCall->getRParenLoc(), diag::warn_missing_format_string)
- << Fn->getSourceRange();
+ if (format_idx >= NumArgs) {
+ Diag(Loc, diag::warn_missing_format_string) << Range;
return;
}
- const Expr *OrigFormatExpr = TheCall->getArg(format_idx)->IgnoreParenCasts();
+ const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
// CHECK: format string is not a string literal.
//
@@ -1634,18 +1588,18 @@
// C string (e.g. "%d")
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
- if (SemaCheckStringLiteral(OrigFormatExpr, TheCall, HasVAListArg, format_idx,
- firstDataArg, isPrintf))
+ if (SemaCheckStringLiteral(OrigFormatExpr, Args, NumArgs, HasVAListArg,
+ format_idx, firstDataArg, isPrintf))
return; // Literal format string found, check done!
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
- if (TheCall->getNumArgs() == format_idx+1)
- Diag(TheCall->getArg(format_idx)->getLocStart(),
+ if (NumArgs == format_idx+1)
+ Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral_noargs)
<< OrigFormatExpr->getSourceRange();
else
- Diag(TheCall->getArg(format_idx)->getLocStart(),
+ Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral)
<< OrigFormatExpr->getSourceRange();
}
@@ -1661,7 +1615,8 @@
const bool IsObjCLiteral;
const char *Beg; // Start of format string.
const bool HasVAListArg;
- const CallExpr *TheCall;
+ const Expr * const *Args;
+ const unsigned NumArgs;
unsigned FormatIdx;
llvm::BitVector CoveredArgs;
bool usesPositionalArgs;
@@ -1672,14 +1627,14 @@
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
- const CallExpr *theCall, unsigned formatIdx,
- bool inFunctionCall)
+ Expr **args, unsigned numArgs,
+ unsigned formatIdx, bool inFunctionCall)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
FirstDataArg(firstDataArg),
NumDataArgs(numDataArgs),
IsObjCLiteral(isObjCLiteral), Beg(beg),
HasVAListArg(hasVAListArg),
- TheCall(theCall), FormatIdx(formatIdx),
+ Args(args), NumArgs(numArgs), FormatIdx(formatIdx),
usesPositionalArgs(false), atFirstArg(true),
inFunctionCall(inFunctionCall) {
CoveredArgs.resize(numDataArgs);
@@ -1794,7 +1749,7 @@
}
const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
- return TheCall->getArg(FirstDataArg + i);
+ return Args[FirstDataArg + i];
}
void CheckFormatHandler::DoneProcessing() {
@@ -1878,7 +1833,7 @@
bool IsStringLocation,
Range StringRange,
FixItHint FixIt) {
- EmitFormatDiagnostic(S, inFunctionCall, TheCall->getArg(FormatIdx), PDiag,
+ EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag,
Loc, IsStringLocation, StringRange, FixIt);
}
@@ -1937,11 +1892,11 @@
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
- const CallExpr *theCall, unsigned formatIdx,
- bool inFunctionCall)
+ Expr **Args, unsigned NumArgs,
+ unsigned formatIdx, bool inFunctionCall)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, isObjCLiteral, beg, hasVAListArg,
- theCall, formatIdx, inFunctionCall) {}
+ Args, NumArgs, formatIdx, inFunctionCall) {}
bool HandleInvalidPrintfConversionSpecifier(
@@ -2261,11 +2216,11 @@
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
- const CallExpr *theCall, unsigned formatIdx,
- bool inFunctionCall)
+ Expr **Args, unsigned NumArgs,
+ unsigned formatIdx, bool inFunctionCall)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, isObjCLiteral, beg, hasVAListArg,
- theCall, formatIdx, inFunctionCall) {}
+ Args, NumArgs, formatIdx, inFunctionCall) {}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
@@ -2408,14 +2363,15 @@
void Sema::CheckFormatString(const StringLiteral *FExpr,
const Expr *OrigFormatExpr,
- const CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx, unsigned firstDataArg,
- bool isPrintf, bool inFunctionCall) {
+ Expr **Args, unsigned NumArgs,
+ bool HasVAListArg, unsigned format_idx,
+ unsigned firstDataArg, bool isPrintf,
+ bool inFunctionCall) {
// CHECK: is the format string a wide literal?
if (!FExpr->isAscii()) {
CheckFormatHandler::EmitFormatDiagnostic(
- *this, inFunctionCall, TheCall->getArg(format_idx),
+ *this, inFunctionCall, Args[format_idx],
PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(),
/*IsStringLocation*/true, OrigFormatExpr->getSourceRange());
return;
@@ -2425,12 +2381,12 @@
StringRef StrRef = FExpr->getString();
const char *Str = StrRef.data();
unsigned StrLen = StrRef.size();
- const unsigned numDataArgs = TheCall->getNumArgs() - firstDataArg;
+ const unsigned numDataArgs = NumArgs - firstDataArg;
// CHECK: empty format string?
if (StrLen == 0 && numDataArgs > 0) {
CheckFormatHandler::EmitFormatDiagnostic(
- *this, inFunctionCall, TheCall->getArg(format_idx),
+ *this, inFunctionCall, Args[format_idx],
PDiag(diag::warn_empty_format_string), FExpr->getLocStart(),
/*IsStringLocation*/true, OrigFormatExpr->getSourceRange());
return;
@@ -2439,7 +2395,7 @@
if (isPrintf) {
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
- Str, HasVAListArg, TheCall, format_idx,
+ Str, HasVAListArg, Args, NumArgs, format_idx,
inFunctionCall);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
@@ -2449,7 +2405,7 @@
else {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
- Str, HasVAListArg, TheCall, format_idx,
+ Str, HasVAListArg, Args, NumArgs, format_idx,
inFunctionCall);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
@@ -2500,16 +2456,19 @@
///
/// \param Call The call expression to diagnose.
void Sema::CheckMemaccessArguments(const CallExpr *Call,
- CheckedMemoryFunction CMF,
+ unsigned BId,
IdentifierInfo *FnName) {
+ assert(BId != 0);
+
// It is possible to have a non-standard definition of memset. Validate
// we have enough arguments, and if not, abort further checking.
- unsigned ExpectedNumArgs = (CMF == CMF_Strndup ? 2 : 3);
+ unsigned ExpectedNumArgs = (BId == Builtin::BIstrndup ? 2 : 3);
if (Call->getNumArgs() < ExpectedNumArgs)
return;
- unsigned LastArg = (CMF == CMF_Memset || CMF == CMF_Strndup ? 1 : 2);
- unsigned LenArg = (CMF == CMF_Strndup ? 1 : 2);
+ unsigned LastArg = (BId == Builtin::BImemset ||
+ BId == Builtin::BIstrndup ? 1 : 2);
+ unsigned LenArg = (BId == Builtin::BIstrndup ? 1 : 2);
const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts();
// We have special checking when the length is a sizeof expression.
@@ -2553,7 +2512,8 @@
if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
ActionIdx = 2; // If the pointee's size is sizeof(char),
// suggest an explicit length.
- unsigned DestSrcSelect = (CMF == CMF_Strndup ? 1 : ArgIdx);
+ unsigned DestSrcSelect =
+ (BId == Builtin::BIstrndup ? 1 : ArgIdx);
DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest,
PDiag(diag::warn_sizeof_pointer_expr_memaccess)
<< FnName << DestSrcSelect << ActionIdx
@@ -2579,16 +2539,29 @@
}
// Always complain about dynamic classes.
- if (isDynamicClassType(PointeeTy))
+ if (isDynamicClassType(PointeeTy)) {
+
+ unsigned OperationType = 0;
+ // "overwritten" if we're warning about the destination for any call
+ // but memcmp; otherwise a verb appropriate to the call.
+ if (ArgIdx != 0 || BId == Builtin::BImemcmp) {
+ if (BId == Builtin::BImemcpy)
+ OperationType = 1;
+ else if(BId == Builtin::BImemmove)
+ OperationType = 2;
+ else if (BId == Builtin::BImemcmp)
+ OperationType = 3;
+ }
+
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
PDiag(diag::warn_dyn_class_memaccess)
- << (CMF == CMF_Memcmp ? ArgIdx + 2 : ArgIdx) << FnName << PointeeTy
- // "overwritten" if we're warning about the destination for any call
- // but memcmp; otherwise a verb appropriate to the call.
- << (ArgIdx == 0 && CMF != CMF_Memcmp ? 0 : (unsigned)CMF)
+ << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx)
+ << FnName << PointeeTy
+ << OperationType
<< Call->getCallee()->getSourceRange());
- else if (PointeeTy.hasNonTrivialObjCLifetime() && CMF != CMF_Memset)
+ } else if (PointeeTy.hasNonTrivialObjCLifetime() &&
+ BId != Builtin::BImemset)
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
PDiag(diag::warn_arc_object_memaccess)
@@ -3239,7 +3212,7 @@
// FIXME: The only reason we need to pass the type in here is to get
// the sign right on this one case. It would be nice if APValue
// preserved this.
- assert(result.isLValue());
+ assert(result.isLValue() || result.isAddrLabelDiff());
return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType());
}
@@ -3662,12 +3635,10 @@
Expr *OriginalInit = Init->IgnoreParenImpCasts();
- Expr::EvalResult InitValue;
- if (!OriginalInit->EvaluateAsRValue(InitValue, S.Context) ||
- !InitValue.Val.isInt())
+ llvm::APSInt Value;
+ if (!OriginalInit->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects))
return false;
- const llvm::APSInt &Value = InitValue.Val.getInt();
unsigned OriginalWidth = Value.getBitWidth();
unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context);
@@ -3757,11 +3728,6 @@
return ValueInRange.toString(10);
}
-static bool isFromSystemMacro(Sema &S, SourceLocation loc) {
- SourceManager &smgr = S.Context.getSourceManager();
- return loc.isMacroID() && smgr.isInSystemHeader(smgr.getSpellingLoc(loc));
-}
-
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool *ICContext = 0) {
if (E->isTypeDependent() || E->isValueDependent()) return;
@@ -3823,7 +3789,7 @@
// Strip vector types.
if (isa<VectorType>(Source)) {
if (!isa<VectorType>(Target)) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar);
}
@@ -3840,7 +3806,7 @@
// Strip complex types.
if (isa<ComplexType>(Source)) {
if (!isa<ComplexType>(Target)) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar);
@@ -3872,7 +3838,7 @@
return;
}
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision);
@@ -3882,7 +3848,7 @@
// If the target is integral, always warn.
if ((TargetBT && TargetBT->isInteger())) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
Expr *InnerE = E->IgnoreParenImpCasts();
@@ -3919,7 +3885,7 @@
// TODO: this should happen for bitfield stores, too.
llvm::APSInt Value(32);
if (E->isIntegerConstantExpr(Value, S.Context)) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
std::string PrettySourceValue = Value.toString(10);
@@ -3934,7 +3900,7 @@
}
// People want to build with -Wshorten-64-to-32 and not -Wconversion.
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
if (SourceRange.Width == 64 && TargetRange.Width == 32)
@@ -3946,7 +3912,7 @@
(!TargetRange.NonNegative && SourceRange.NonNegative &&
SourceRange.Width == TargetRange.Width)) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
unsigned DiagID = diag::warn_impcast_integer_sign;
@@ -3984,7 +3950,7 @@
(TargetEnum->getDecl()->getIdentifier() ||
TargetEnum->getDecl()->getTypedefNameForAnonDecl()) &&
SourceEnum != TargetEnum) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
return DiagnoseImpCast(S, E, SourceType, T, CC,
@@ -4465,7 +4431,7 @@
return true;
}
-static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
+static bool findRetainCycleOwner(Sema &S, Expr *e, RetainCycleOwner &owner) {
while (true) {
e = e->IgnoreParens();
if (CastExpr *cast = dyn_cast<CastExpr>(e)) {
@@ -4488,7 +4454,7 @@
return false;
// Try to find a retain cycle in the base.
- if (!findRetainCycleOwner(ref->getBase(), owner))
+ if (!findRetainCycleOwner(S, ref->getBase(), owner))
return false;
if (ref->isFreeIvar()) owner.setLocsFrom(ref);
@@ -4531,6 +4497,14 @@
return false;
owner.Indirect = true;
+ if (pre->isSuperReceiver()) {
+ owner.Variable = S.getCurMethodDecl()->getSelfDecl();
+ if (!owner.Variable)
+ return false;
+ owner.Loc = pre->getLocation();
+ owner.Range = pre->getSourceRange();
+ return true;
+ }
e = const_cast<Expr*>(cast<OpaqueValueExpr>(pre->getBase())
->getSourceExpr());
continue;
@@ -4633,7 +4607,7 @@
// Try to find a variable that the receiver is strongly owned by.
RetainCycleOwner owner;
if (msg->getReceiverKind() == ObjCMessageExpr::Instance) {
- if (!findRetainCycleOwner(msg->getInstanceReceiver(), owner))
+ if (!findRetainCycleOwner(*this, msg->getInstanceReceiver(), owner))
return;
} else {
assert(msg->getReceiverKind() == ObjCMessageExpr::SuperInstance);
@@ -4651,7 +4625,7 @@
/// Check a property assign to see if it's likely to cause a retain cycle.
void Sema::checkRetainCycles(Expr *receiver, Expr *argument) {
RetainCycleOwner owner;
- if (!findRetainCycleOwner(receiver, owner))
+ if (!findRetainCycleOwner(*this, receiver, owner))
return;
if (Expr *capturer = findCapturingExpr(*this, argument, owner))
@@ -4678,7 +4652,19 @@
void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
Expr *LHS, Expr *RHS) {
- QualType LHSType = LHS->getType();
+ QualType LHSType;
+ // PropertyRef on LHS type need be directly obtained from
+ // its declaration as it has a PsuedoType.
+ ObjCPropertyRefExpr *PRE
+ = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens());
+ if (PRE && !PRE->isImplicitProperty()) {
+ const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
+ if (PD)
+ LHSType = PD->getType();
+ }
+
+ if (LHSType.isNull())
+ LHSType = LHS->getType();
if (checkUnsafeAssigns(Loc, LHSType, RHS))
return;
Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
@@ -4686,8 +4672,7 @@
if (LT != Qualifiers::OCL_None)
return;
- if (ObjCPropertyRefExpr *PRE
- = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens())) {
+ if (PRE) {
if (PRE->isImplicitProperty())
return;
const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
@@ -4695,7 +4680,15 @@
return;
unsigned Attributes = PD->getPropertyAttributes();
- if (Attributes & ObjCPropertyDecl::OBJC_PR_assign)
+ if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) {
+ // when 'assign' attribute was not explicitly specified
+ // by user, ignore it and rely on property type itself
+ // for lifetime info.
+ unsigned AsWrittenAttr = PD->getPropertyAttributesAsWritten();
+ if (!(AsWrittenAttr & ObjCPropertyDecl::OBJC_PR_assign) &&
+ LHSType->isObjCRetainableType())
+ return;
+
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
if (cast->getCastKind() == CK_ARCConsumeObject) {
Diag(Loc, diag::warn_arc_retained_property_assign)
@@ -4704,5 +4697,6 @@
}
RHS = cast->getSubExpr();
}
+ }
}
}
Modified: cfe/branches/tooling/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaCodeComplete.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaCodeComplete.cpp Fri Jan 20 10:14:22 2012
@@ -596,8 +596,7 @@
default:
return STC_Arithmetic;
}
- return STC_Other;
-
+
case Type::Complex:
return STC_Arithmetic;
@@ -1370,19 +1369,24 @@
case Sema::PCC_ForInit:
return LangOpts.CPlusPlus || LangOpts.ObjC1 || LangOpts.C99;
}
-
- return false;
+
+ llvm_unreachable("Invalid ParserCompletionContext!");
}
-/// \brief Retrieve a printing policy suitable for code completion.
-static PrintingPolicy getCompletionPrintingPolicy(Sema &S) {
- PrintingPolicy Policy = S.getPrintingPolicy();
+static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context,
+ const Preprocessor &PP) {
+ PrintingPolicy Policy = Sema::getPrintingPolicy(Context, PP);
Policy.AnonymousTagLocations = false;
Policy.SuppressStrongLifetime = true;
Policy.SuppressUnwrittenScope = true;
return Policy;
}
+/// \brief Retrieve a printing policy suitable for code completion.
+static PrintingPolicy getCompletionPrintingPolicy(Sema &S) {
+ return getCompletionPrintingPolicy(S.Context, S.PP);
+}
+
/// \brief Retrieve the string representation of the given type as a string
/// that has the appropriate lifetime for code completion.
///
@@ -1751,7 +1755,7 @@
case Sema::PCC_Expression: {
if (SemaRef.getLangOptions().CPlusPlus) {
// 'this', if we're in a non-static member function.
- QualType ThisTy = SemaRef.getCurrentThisType(false);
+ QualType ThisTy = SemaRef.getCurrentThisType();
if (!ThisTy.isNull()) {
Builder.AddResultTypeChunk(GetCompletionTypeString(ThisTy,
SemaRef.Context,
@@ -2409,6 +2413,11 @@
}
}
+CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(Sema &S,
+ CodeCompletionAllocator &Allocator) {
+ return CreateCodeCompletionString(S.Context, S.PP, Allocator);
+}
+
/// \brief If possible, create a new code completion string for the given
/// result.
///
@@ -2416,12 +2425,13 @@
/// how to use this result, or NULL to indicate that the string or name of the
/// result is all that is needed.
CodeCompletionString *
-CodeCompletionResult::CreateCodeCompletionString(Sema &S,
+CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
+ Preprocessor &PP,
CodeCompletionAllocator &Allocator) {
typedef CodeCompletionString::Chunk Chunk;
CodeCompletionBuilder Result(Allocator, Priority, Availability);
- PrintingPolicy Policy = getCompletionPrintingPolicy(S);
+ PrintingPolicy Policy = getCompletionPrintingPolicy(Ctx, PP);
if (Kind == RK_Pattern) {
Pattern->Priority = Priority;
Pattern->Availability = Availability;
@@ -2434,7 +2444,7 @@
}
if (Kind == RK_Macro) {
- MacroInfo *MI = S.PP.getMacroInfo(Macro);
+ MacroInfo *MI = PP.getMacroInfo(Macro);
assert(MI && "Not a macro?");
Result.AddTypedTextChunk(
@@ -2505,14 +2515,14 @@
}
}
- AddResultTypeChunk(S.Context, Policy, ND, Result);
+ AddResultTypeChunk(Ctx, Policy, ND, Result);
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context, Policy);
- AddTypedNameChunk(S.Context, Policy, ND, Result);
+ Ctx, Policy);
+ AddTypedNameChunk(Ctx, Policy, ND, Result);
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
- AddFunctionParameterChunks(S.Context, Policy, Function, Result);
+ AddFunctionParameterChunks(Ctx, Policy, Function, Result);
Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
AddFunctionTypeQualsToCompletionString(Result, Function);
return Result.TakeString();
@@ -2520,14 +2530,14 @@
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context, Policy);
+ Ctx, Policy);
FunctionDecl *Function = FunTmpl->getTemplatedDecl();
- AddTypedNameChunk(S.Context, Policy, Function, Result);
+ AddTypedNameChunk(Ctx, Policy, Function, Result);
// Figure out which template parameters are deduced (or have default
// arguments).
SmallVector<bool, 16> Deduced;
- S.MarkDeducedTemplateParameters(FunTmpl, Deduced);
+ Sema::MarkDeducedTemplateParameters(Ctx, FunTmpl, Deduced);
unsigned LastDeducibleArgument;
for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0;
--LastDeducibleArgument) {
@@ -2559,14 +2569,14 @@
// function call, so we introduce an explicit template argument list
// containing all of the arguments up to the first deducible argument.
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
- AddTemplateParameterChunks(S.Context, Policy, FunTmpl, Result,
+ AddTemplateParameterChunks(Ctx, Policy, FunTmpl, Result,
LastDeducibleArgument);
Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
}
// Add the function parameters
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
- AddFunctionParameterChunks(S.Context, Policy, Function, Result);
+ AddFunctionParameterChunks(Ctx, Policy, Function, Result);
Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
AddFunctionTypeQualsToCompletionString(Result, Function);
return Result.TakeString();
@@ -2574,11 +2584,11 @@
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context, Policy);
+ Ctx, Policy);
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(Template->getNameAsString()));
Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
- AddTemplateParameterChunks(S.Context, Policy, Template, Result);
+ AddTemplateParameterChunks(Ctx, Policy, Template, Result);
Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
return Result.TakeString();
}
@@ -2627,7 +2637,7 @@
std::string Arg;
if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity)
- Arg = FormatFunctionParameter(S.Context, Policy, *P, true);
+ Arg = FormatFunctionParameter(Ctx, Policy, *P, true);
else {
(*P)->getType().getAsStringInternal(Arg, Policy);
Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier())
@@ -2658,7 +2668,7 @@
Result.AddPlaceholderChunk(", ...");
}
- MaybeAddSentinel(S.Context, Method, Result);
+ MaybeAddSentinel(Ctx, Method, Result);
}
return Result.TakeString();
@@ -2666,7 +2676,7 @@
if (Qualifier)
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context, Policy);
+ Ctx, Policy);
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(ND->getNameAsString()));
@@ -2781,14 +2791,15 @@
return CXCursor_FunctionDecl;
case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl;
case Decl::ObjCCategoryImpl: return CXCursor_ObjCCategoryImplDecl;
- case Decl::ObjCClass:
- // FIXME
- return CXCursor_UnexposedDecl;
- case Decl::ObjCForwardProtocol:
- // FIXME
- return CXCursor_UnexposedDecl;
case Decl::ObjCImplementation: return CXCursor_ObjCImplementationDecl;
- case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl;
+
+ case Decl::ObjCInterface:
+ if (cast<ObjCInterfaceDecl>(D)->isThisDeclarationADefinition())
+ return CXCursor_ObjCInterfaceDecl;
+
+ // Forward declarations are not directly exposed.
+ return CXCursor_UnexposedDecl;
+
case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl;
case Decl::ObjCMethod:
return cast<ObjCMethodDecl>(D)->isInstanceMethod()
@@ -2798,7 +2809,12 @@
case Decl::CXXDestructor: return CXCursor_Destructor;
case Decl::CXXConversion: return CXCursor_ConversionFunction;
case Decl::ObjCProperty: return CXCursor_ObjCPropertyDecl;
- case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl;
+ case Decl::ObjCProtocol:
+ if (cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition())
+ return CXCursor_ObjCProtocolDecl;
+
+ return CXCursor_UnexposedDecl;
+
case Decl::ParmVar: return CXCursor_ParmDecl;
case Decl::Typedef: return CXCursor_TypedefDecl;
case Decl::TypeAlias: return CXCursor_TypeAliasDecl;
@@ -2828,7 +2844,6 @@
case ObjCPropertyImplDecl::Synthesize:
return CXCursor_ObjCSynthesizeDecl;
}
- break;
default:
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
@@ -2907,10 +2922,9 @@
case Sema::PCC_MemberTemplate:
if (S.CurContext->isFileContext())
return CodeCompletionContext::CCC_TopLevel;
- else if (S.CurContext->isRecord())
+ if (S.CurContext->isRecord())
return CodeCompletionContext::CCC_ClassStructUnion;
- else
- return CodeCompletionContext::CCC_Other;
+ return CodeCompletionContext::CCC_Other;
case Sema::PCC_RecoveryInFunction:
return CodeCompletionContext::CCC_Recovery;
@@ -2938,8 +2952,8 @@
case Sema::PCC_LocalDeclarationSpecifiers:
return CodeCompletionContext::CCC_Type;
}
-
- return CodeCompletionContext::CCC_Other;
+
+ llvm_unreachable("Invalid ParserCompletionContext!");
}
/// \brief If we're in a C++ virtual member function, add completion results
@@ -4548,13 +4562,16 @@
// Visit the protocols of protocols.
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
- const ObjCList<ObjCProtocolDecl> &Protocols
- = Protocol->getReferencedProtocols();
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
- E = Protocols.end();
- I != E; ++I)
- AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents,
- CurContext, Selectors, AllowSameLength, Results, false);
+ if (Protocol->hasDefinition()) {
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = Protocol->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
+ NumSelIdents, CurContext, Selectors, AllowSameLength,
+ Results, false);
+ }
}
ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
@@ -5411,19 +5428,8 @@
D != DEnd; ++D) {
// Record any protocols we find.
if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*D))
- if (!OnlyForwardDeclarations || Proto->isForwardDecl())
+ if (!OnlyForwardDeclarations || !Proto->hasDefinition())
Results.AddResult(Result(Proto, 0), CurContext, 0, false);
-
- // Record any forward-declared protocols we find.
- if (ObjCForwardProtocolDecl *Forward
- = dyn_cast<ObjCForwardProtocolDecl>(*D)) {
- for (ObjCForwardProtocolDecl::protocol_iterator
- P = Forward->protocol_begin(),
- PEnd = Forward->protocol_end();
- P != PEnd; ++P)
- if (!OnlyForwardDeclarations || (*P)->isForwardDecl())
- Results.AddResult(Result(*P, 0), CurContext, 0, false);
- }
}
}
@@ -5490,15 +5496,6 @@
if ((!OnlyForwardDeclarations || !Class->hasDefinition()) &&
(!OnlyUnimplemented || !Class->getImplementation()))
Results.AddResult(Result(Class, 0), CurContext, 0, false);
-
- // Record any forward-declared interfaces we find.
- if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) {
- ObjCInterfaceDecl *IDecl = Forward->getForwardInterfaceDecl();
- if ((!OnlyForwardDeclarations || !IDecl->hasDefinition()) &&
- (!OnlyUnimplemented || !IDecl->getImplementation()))
- Results.AddResult(Result(IDecl, 0), CurContext,
- 0, false);
- }
}
}
@@ -5826,14 +5823,16 @@
}
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
- // Recurse into protocols.
- const ObjCList<ObjCProtocolDecl> &Protocols
- = Protocol->getReferencedProtocols();
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
- E = Protocols.end();
- I != E; ++I)
- FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
- KnownMethods, false);
+ if (Protocol->hasDefinition()) {
+ // Recurse into protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = Protocol->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
+ KnownMethods, false);
+ }
}
// Add methods in this container. This operation occurs last because
Modified: cfe/branches/tooling/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaDecl.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaDecl.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaDecl.cpp Fri Jan 20 10:14:22 2012
@@ -55,6 +55,30 @@
return DeclGroupPtrTy::make(DeclGroupRef(Ptr));
}
+namespace {
+
+class TypeNameValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ TypeNameValidatorCCC(bool AllowInvalid) : AllowInvalidDecl(AllowInvalid) {
+ WantExpressionKeywords = false;
+ WantCXXNamedCasts = false;
+ WantRemainingKeywords = false;
+ }
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ if (NamedDecl *ND = candidate.getCorrectionDecl())
+ return (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) &&
+ (AllowInvalidDecl || !ND->isInvalidDecl());
+ else
+ return candidate.isKeyword();
+ }
+
+ private:
+ bool AllowInvalidDecl;
+};
+
+}
+
/// \brief If the identifier refers to a type name within this scope,
/// return the declaration of that type.
///
@@ -147,9 +171,9 @@
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (CorrectedII) {
+ TypeNameValidatorCCC Validator(true);
TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(),
- Kind, S, SS, 0, false,
- Sema::CTC_Type);
+ Kind, S, SS, &Validator);
IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
TemplateTy Template;
bool MemberOfUnknownSpecialization;
@@ -291,7 +315,6 @@
if (R.getResultKind() == LookupResult::Found)
if (const TagDecl *TD = R.getAsSingle<TagDecl>()) {
switch (TD->getTagKind()) {
- default: return DeclSpec::TST_unspecified;
case TTK_Struct: return DeclSpec::TST_struct;
case TTK_Union: return DeclSpec::TST_union;
case TTK_Class: return DeclSpec::TST_class;
@@ -340,9 +363,10 @@
// There may have been a typo in the name of the type. Look up typo
// results, in case we have something that we can suggest.
+ TypeNameValidatorCCC Validator(false);
if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(&II, IILoc),
- LookupOrdinaryName, S, SS, NULL,
- false, CTC_Type)) {
+ LookupOrdinaryName, S, SS,
+ &Validator)) {
std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
@@ -351,32 +375,28 @@
// FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
Diag(IILoc, diag::err_unknown_typename_suggest)
<< &II << CorrectedQuotedStr;
- return true;
} else {
NamedDecl *Result = Corrected.getCorrectionDecl();
- if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) &&
- !Result->isInvalidDecl()) {
- // We found a similarly-named type or interface; suggest that.
- if (!SS || !SS->isSet())
- Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << CorrectedQuotedStr
- << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
- else if (DeclContext *DC = computeDeclContext(*SS, false))
- Diag(IILoc, diag::err_unknown_nested_typename_suggest)
- << &II << DC << CorrectedQuotedStr << SS->getRange()
- << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
- else
- llvm_unreachable("could not have corrected a typo here");
+ // We found a similarly-named type or interface; suggest that.
+ if (!SS || !SS->isSet())
+ Diag(IILoc, diag::err_unknown_typename_suggest)
+ << &II << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
+ else if (DeclContext *DC = computeDeclContext(*SS, false))
+ Diag(IILoc, diag::err_unknown_nested_typename_suggest)
+ << &II << DC << CorrectedQuotedStr << SS->getRange()
+ << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
+ else
+ llvm_unreachable("could not have corrected a typo here");
- Diag(Result->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
-
- SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS,
- false, false, ParsedType(),
- /*NonTrivialTypeSourceInfo=*/true);
- return true;
- }
+ Diag(Result->getLocation(), diag::note_previous_decl)
+ << CorrectedQuotedStr;
+
+ SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS,
+ false, false, ParsedType(),
+ /*NonTrivialTypeSourceInfo=*/true);
}
+ return true;
}
if (getLangOptions().CPlusPlus) {
@@ -547,9 +567,10 @@
// close to this name.
if (!SecondTry) {
SecondTry = true;
+ CorrectionCandidateCallback DefaultValidator;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S,
- &SS)) {
+ &SS, &DefaultValidator)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
@@ -1095,7 +1116,7 @@
if (D->isInvalidDecl())
return false;
- if (D->isUsed() || D->hasAttr<UnusedAttr>())
+ if (D->isReferenced() || D->isUsed() || D->hasAttr<UnusedAttr>())
return false;
if (isa<LabelDecl>(D))
@@ -1107,7 +1128,7 @@
return false;
// Types of valid local variables should be complete, so this should succeed.
- if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// White-list anything with an __attribute__((unused)) type.
QualType Ty = VD->getType();
@@ -1129,11 +1150,18 @@
return false;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
- // FIXME: Checking for the presence of a user-declared constructor
- // isn't completely accurate; we'd prefer to check that the initializer
- // has no side effects.
- if (RD->hasUserDeclaredConstructor() || !RD->hasTrivialDestructor())
+ if (!RD->hasTrivialDestructor())
return false;
+
+ if (const Expr *Init = VD->getInit()) {
+ const CXXConstructExpr *Construct =
+ dyn_cast<CXXConstructExpr>(Init);
+ if (Construct && !Construct->isElidable()) {
+ CXXConstructorDecl *CD = Construct->getConstructor();
+ if (!CD->isTrivial())
+ return false;
+ }
+ }
}
}
@@ -1235,10 +1263,11 @@
if (!IDecl && DoTypoCorrection) {
// Perform typo correction at the given location, but only if we
// find an Objective-C class name.
- TypoCorrection C;
- if ((C = CorrectTypo(DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName,
- TUScope, NULL, NULL, false, CTC_NoKeywords)) &&
- (IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
+ DeclFilterCCC<ObjCInterfaceDecl> Validator;
+ if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc),
+ LookupOrdinaryName, TUScope, NULL,
+ &Validator)) {
+ IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>();
Diag(IdLoc, diag::err_undef_interface_suggest)
<< Id << IDecl->getDeclName()
<< FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString());
@@ -1248,8 +1277,11 @@
Id = IDecl->getIdentifier();
}
}
-
- return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
+ ObjCInterfaceDecl *Def = dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
+ // This routine must always return a class definition, if any.
+ if (Def && Def->getDefinition())
+ Def = Def->getDefinition();
+ return Def;
}
/// getNonFieldDeclScope - Retrieves the innermost scope, starting
@@ -1368,6 +1400,40 @@
return New;
}
+bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
+ QualType OldType;
+ if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
+ OldType = OldTypedef->getUnderlyingType();
+ else
+ OldType = Context.getTypeDeclType(Old);
+ QualType NewType = New->getUnderlyingType();
+
+ if (NewType->isVariablyModifiedType()) {
+ // Must not redefine a typedef with a variably-modified type.
+ int Kind = isa<TypeAliasDecl>(Old) ? 1 : 0;
+ Diag(New->getLocation(), diag::err_redefinition_variably_modified_typedef)
+ << Kind << NewType;
+ if (Old->getLocation().isValid())
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ New->setInvalidDecl();
+ return true;
+ }
+
+ if (OldType != NewType &&
+ !OldType->isDependentType() &&
+ !NewType->isDependentType() &&
+ !Context.hasSameType(OldType, NewType)) {
+ int Kind = isa<TypeAliasDecl>(Old) ? 1 : 0;
+ Diag(New->getLocation(), diag::err_redefinition_different_typedef)
+ << Kind << NewType << OldType;
+ if (Old->getLocation().isValid())
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ New->setInvalidDecl();
+ return true;
+ }
+ return false;
+}
+
/// MergeTypedefNameDecl - We just parsed a typedef 'New' which has the
/// same name and scope as a previous declaration 'Old'. Figure out
/// how to resolve this situation, merging decls or emitting
@@ -1426,42 +1492,16 @@
if (Old->isInvalidDecl())
return New->setInvalidDecl();
- // Determine the "old" type we'll use for checking and diagnostics.
- QualType OldType;
- if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
- OldType = OldTypedef->getUnderlyingType();
- else
- OldType = Context.getTypeDeclType(Old);
-
// If the typedef types are not identical, reject them in all languages and
// with any extensions enabled.
-
- if (OldType != New->getUnderlyingType() &&
- Context.getCanonicalType(OldType) !=
- Context.getCanonicalType(New->getUnderlyingType())) {
- int Kind = 0;
- if (isa<TypeAliasDecl>(Old))
- Kind = 1;
- Diag(New->getLocation(), diag::err_redefinition_different_typedef)
- << Kind << New->getUnderlyingType() << OldType;
- if (Old->getLocation().isValid())
- Diag(Old->getLocation(), diag::note_previous_definition);
- return New->setInvalidDecl();
- }
+ if (isIncompatibleTypedef(Old, New))
+ return;
// The types match. Link up the redeclaration chain if the old
// declaration was a typedef.
- // FIXME: this is a potential source of weirdness if the type
- // spellings don't match exactly.
if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old))
New->setPreviousDeclaration(Typedef);
- // __module_private__ is propagated to later declarations.
- if (Old->isModulePrivate())
- New->setModulePrivate();
- else if (New->isModulePrivate())
- diagnoseModulePrivateRedeclaration(New, Old);
-
if (getLangOptions().MicrosoftExt)
return;
@@ -1503,6 +1543,10 @@
return New->setInvalidDecl();
}
+ // Modules always permit redefinition of typedefs, as does C11.
+ if (getLangOptions().Modules || getLangOptions().C11)
+ return;
+
// If we have a redefinition of a typedef in C, emit a warning. This warning
// is normally mapped to an error, but can be controlled with
// -Wtypedef-redefinition. If either the original or the redefinition is
@@ -1541,36 +1585,37 @@
}
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
-static void mergeDeclAttributes(Decl *newDecl, const Decl *oldDecl,
- ASTContext &C, bool mergeDeprecation = true) {
- if (!oldDecl->hasAttrs())
+void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
+ bool MergeDeprecation) {
+ if (!Old->hasAttrs())
return;
- bool foundAny = newDecl->hasAttrs();
+ bool foundAny = New->hasAttrs();
// Ensure that any moving of objects within the allocated map is done before
// we process them.
- if (!foundAny) newDecl->setAttrs(AttrVec());
+ if (!foundAny) New->setAttrs(AttrVec());
for (specific_attr_iterator<InheritableAttr>
- i = oldDecl->specific_attr_begin<InheritableAttr>(),
- e = oldDecl->specific_attr_end<InheritableAttr>(); i != e; ++i) {
+ i = Old->specific_attr_begin<InheritableAttr>(),
+ e = Old->specific_attr_end<InheritableAttr>();
+ i != e; ++i) {
// Ignore deprecated/unavailable/availability attributes if requested.
- if (!mergeDeprecation &&
+ if (!MergeDeprecation &&
(isa<DeprecatedAttr>(*i) ||
isa<UnavailableAttr>(*i) ||
isa<AvailabilityAttr>(*i)))
continue;
- if (!DeclHasAttr(newDecl, *i)) {
- InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(C));
+ if (!DeclHasAttr(New, *i)) {
+ InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(Context));
newAttr->setInherited(true);
- newDecl->addAttr(newAttr);
+ New->addAttr(newAttr);
foundAny = true;
}
}
- if (!foundAny) newDecl->dropAttrs();
+ if (!foundAny) New->dropAttrs();
}
/// mergeParamDeclAttributes - Copy attributes from the old parameter
@@ -2036,7 +2081,7 @@
/// \returns false
bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
// Merge the attributes
- mergeDeclAttributes(New, Old, Context);
+ mergeDeclAttributes(New, Old);
// Merge the storage class.
if (Old->getStorageClass() != SC_Extern &&
@@ -2047,12 +2092,6 @@
if (Old->isPure())
New->setPure();
- // __module_private__ is propagated to later declarations.
- if (Old->isModulePrivate())
- New->setModulePrivate();
- else if (New->isModulePrivate())
- diagnoseModulePrivateRedeclaration(New, Old);
-
// Merge attributes from the parameters. These can mismatch with K&R
// declarations.
if (New->getNumParams() == Old->getNumParams())
@@ -2068,13 +2107,13 @@
void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
- const ObjCMethodDecl *oldMethod) {
+ ObjCMethodDecl *oldMethod) {
// We don't want to merge unavailable and deprecated attributes
// except from interface to implementation.
bool mergeDeprecation = isa<ObjCImplDecl>(newMethod->getDeclContext());
// Merge the attributes.
- mergeDeclAttributes(newMethod, oldMethod, Context, mergeDeprecation);
+ mergeDeclAttributes(newMethod, oldMethod, mergeDeprecation);
// Merge attributes from the parameters.
ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin();
@@ -2181,7 +2220,7 @@
New->setInvalidDecl();
}
- mergeDeclAttributes(New, Old, Context);
+ mergeDeclAttributes(New, Old);
// Warn if an already-declared variable is made a weak_import in a subsequent
// declaration
if (New->getAttr<WeakImportAttr>() &&
@@ -2237,12 +2276,6 @@
return New->setInvalidDecl();
}
- // __module_private__ is propagated to later declarations.
- if (Old->isModulePrivate())
- New->setModulePrivate();
- else if (New->isModulePrivate())
- diagnoseModulePrivateRedeclaration(New, Old);
-
// Variables with external linkage are analyzed in FinalizeDeclaratorGroup.
// FIXME: The test for external storage here seems wrong? We still
@@ -2486,25 +2519,6 @@
return TagD;
}
-/// ActOnVlaStmt - This rouine if finds a vla expression in a decl spec.
-/// builds a statement for it and returns it so it is evaluated.
-StmtResult Sema::ActOnVlaStmt(const DeclSpec &DS) {
- StmtResult R;
- if (DS.getTypeSpecType() == DeclSpec::TST_typeofExpr) {
- Expr *Exp = DS.getRepAsExpr();
- QualType Ty = Exp->getType();
- if (Ty->isPointerType()) {
- do
- Ty = Ty->getAs<PointerType>()->getPointeeType();
- while (Ty->isPointerType());
- }
- if (Ty->isVariableArrayType()) {
- R = ActOnExprStmt(MakeFullExpr(Exp));
- }
- }
- return R;
-}
-
/// We are trying to inject an anonymous member into the given scope;
/// check if there's an existing declaration that can't be overloaded.
///
@@ -3966,38 +3980,8 @@
TemplateParamLists.release());
}
- if (D.getDeclSpec().isConstexprSpecified()) {
- // FIXME: once we know whether there's an initializer, apply this to
- // static data members too.
- if (!NewVD->isStaticDataMember() &&
- !NewVD->isThisDeclarationADefinition()) {
- // 'constexpr' is redundant and ill-formed on a non-defining declaration
- // of a variable. Suggest replacing it with 'const' if appropriate.
- SourceLocation ConstexprLoc = D.getDeclSpec().getConstexprSpecLoc();
- SourceRange ConstexprRange(ConstexprLoc, ConstexprLoc);
- // If the declarator is complex, we need to move the keyword to the
- // innermost chunk as we switch it from 'constexpr' to 'const'.
- int Kind = DeclaratorChunk::Paren;
- for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {
- Kind = D.getTypeObject(I).Kind;
- if (Kind != DeclaratorChunk::Paren)
- break;
- }
- if ((D.getDeclSpec().getTypeQualifiers() & DeclSpec::TQ_const) ||
- Kind == DeclaratorChunk::Reference)
- Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)
- << FixItHint::CreateRemoval(ConstexprRange);
- else if (Kind == DeclaratorChunk::Paren)
- Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)
- << FixItHint::CreateReplacement(ConstexprRange, "const");
- else
- Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)
- << FixItHint::CreateRemoval(ConstexprRange)
- << FixItHint::CreateInsertion(D.getIdentifierLoc(), "const ");
- } else {
- NewVD->setConstexpr(true);
- }
- }
+ if (D.getDeclSpec().isConstexprSpecified())
+ NewVD->setConstexpr(true);
}
// Set the lexical context. If the declarator has a C++ scope specifier, the
@@ -4448,6 +4432,18 @@
};
}
+namespace {
+
+// Callback to only accept typo corrections that have a non-zero edit distance.
+class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ return candidate.getEditDistance() > 0;
+ }
+};
+
+}
+
/// \brief Generate diagnostics for an invalid function redeclaration.
///
/// This routine handles generating the diagnostic messages for an invalid
@@ -4477,6 +4473,7 @@
SemaRef.LookupQualifiedName(Prev, NewDC);
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
+ DifferentNameValidatorCCC Validator;
if (!Prev.empty()) {
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
Func != FuncEnd; ++Func) {
@@ -4492,8 +4489,8 @@
}
// If the qualified name lookup yielded nothing, try typo correction
} else if ((Correction = SemaRef.CorrectTypo(Prev.getLookupNameInfo(),
- Prev.getLookupKind(), 0, 0, NewDC)) &&
- Correction.getCorrection() != Name) {
+ Prev.getLookupKind(), 0, 0,
+ &Validator, NewDC))) {
// Trap errors.
Sema::SFINAETrap Trap(SemaRef);
@@ -4946,6 +4943,56 @@
FunctionTemplate->setInvalidDecl();
}
+ // If we see "T var();" at block scope, where T is a class type, it is
+ // probably an attempt to initialize a variable, not a function declaration.
+ // We don't catch this case earlier, since there is no ambiguity here.
+ if (!FunctionTemplate && D.getFunctionDefinitionKind() == FDK_Declaration &&
+ CurContext->isFunctionOrMethod() &&
+ D.getNumTypeObjects() == 1 && D.isFunctionDeclarator() &&
+ D.getDeclSpec().getStorageClassSpecAsWritten()
+ == DeclSpec::SCS_unspecified) {
+ QualType T = R->getAs<FunctionType>()->getResultType();
+ DeclaratorChunk &C = D.getTypeObject(0);
+ if (!T->isVoidType() && C.Fun.NumArgs == 0 && !C.Fun.isVariadic &&
+ !C.Fun.TrailingReturnType &&
+ C.Fun.getExceptionSpecType() == EST_None) {
+ SourceRange ParenRange(C.Loc, C.EndLoc);
+ Diag(C.Loc, diag::warn_empty_parens_are_function_decl) << ParenRange;
+
+ // If the declaration looks like:
+ // T var1,
+ // f();
+ // and name lookup finds a function named 'f', then the ',' was
+ // probably intended to be a ';'.
+ if (!D.isFirstDeclarator() && D.getIdentifier()) {
+ FullSourceLoc Comma(D.getCommaLoc(), SourceMgr);
+ FullSourceLoc Name(D.getIdentifierLoc(), SourceMgr);
+ if (Comma.getFileID() != Name.getFileID() ||
+ Comma.getSpellingLineNumber() != Name.getSpellingLineNumber()) {
+ LookupResult Result(*this, D.getIdentifier(), SourceLocation(),
+ LookupOrdinaryName);
+ if (LookupName(Result, S))
+ Diag(D.getCommaLoc(), diag::note_empty_parens_function_call)
+ << FixItHint::CreateReplacement(D.getCommaLoc(), ";") << NewFD;
+ }
+ }
+ const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+ // Empty parens mean value-initialization, and no parens mean default
+ // initialization. These are equivalent if the default constructor is
+ // user-provided, or if zero-initialization is a no-op.
+ if (RD && RD->hasDefinition() &&
+ (RD->isEmpty() || RD->hasUserProvidedDefaultConstructor()))
+ Diag(C.Loc, diag::note_empty_parens_default_ctor)
+ << FixItHint::CreateRemoval(ParenRange);
+ else if (const char *Init = getFixItZeroInitializerForType(T))
+ Diag(C.Loc, diag::note_empty_parens_zero_initialize)
+ << FixItHint::CreateReplacement(ParenRange, Init);
+ else if (LangOpts.CPlusPlus0x)
+ Diag(C.Loc, diag::note_empty_parens_zero_initialize)
+ << FixItHint::CreateReplacement(ParenRange, "{}");
+ }
+ }
+
// C++ [dcl.fct.spec]p5:
// The virtual specifier shall only be used in declarations of
// nonstatic class member functions that appear within a
@@ -5318,7 +5365,7 @@
if (isFriend && D.isRedeclaration()) {
AccessSpecifier Access = AS_public;
if (!NewFD->isInvalidDecl())
- Access = NewFD->getPreviousDeclaration()->getAccess();
+ Access = NewFD->getPreviousDecl()->getAccess();
NewFD->setAccess(Access);
if (FunctionTemplate) FunctionTemplate->setAccess(Access);
@@ -5334,7 +5381,7 @@
// list. This will check and merge default template arguments.
if (FunctionTemplate) {
FunctionTemplateDecl *PrevTemplate =
- FunctionTemplate->getPreviousDeclaration();
+ FunctionTemplate->getPreviousDecl();
CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(),
PrevTemplate ? PrevTemplate->getTemplateParameters() : 0,
D.getDeclSpec().isFriendSpecified()
@@ -5627,9 +5674,6 @@
assert(OldTemplateDecl->isMemberSpecialization());
}
- if (OldTemplateDecl->isModulePrivate())
- NewTemplateDecl->setModulePrivate();
-
} else {
if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
NewFD->setAccess(OldDecl->getAccess());
@@ -5968,9 +6012,7 @@
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
TypeSourceInfo *DeducedType = 0;
if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
- Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
- << VDecl->getDeclName() << VDecl->getType() << Init->getType()
- << Init->getSourceRange();
+ DiagnoseAutoDeductionFailure(VDecl, Init);
if (!DeducedType) {
RealDecl->setInvalidDecl();
return;
@@ -5984,7 +6026,7 @@
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
- if (VarDecl *Old = VDecl->getPreviousDeclaration())
+ if (VarDecl *Old = VDecl->getPreviousDecl())
MergeVarDeclTypes(VDecl, Old);
}
@@ -6090,7 +6132,7 @@
// If the type changed, it means we had an incomplete type that was
// completed by the initializer. For example:
// int ary[] = { 1, 3, 5 };
- // "ary" transitions from a VariableArrayType to a ConstantArrayType.
+ // "ary" transitions from an IncompleteArrayType to a ConstantArrayType.
if (!VDecl->isInvalidDecl() && (DclT != SavT)) {
VDecl->setType(DclT);
Init->setType(DclT.getNonReferenceType());
@@ -6265,7 +6307,7 @@
if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
QualType Type = Var->getType();
- // C++0x [dcl.spec.auto]p3
+ // C++11 [dcl.spec.auto]p3
if (TypeMayContainAuto && Type->getContainedAutoType()) {
Diag(Var->getLocation(), diag::err_auto_var_requires_init)
<< Var->getDeclName() << Type;
@@ -6273,13 +6315,19 @@
return;
}
- // C++0x [class.static.data]p3: A static data member can be declared with
+ // C++11 [class.static.data]p3: A static data member can be declared with
// the constexpr specifier; if so, its declaration shall specify
// a brace-or-equal-initializer.
- if (Var->isConstexpr() && Var->isStaticDataMember() &&
- !Var->isThisDeclarationADefinition()) {
- Diag(Var->getLocation(), diag::err_constexpr_static_mem_var_requires_init)
- << Var->getDeclName();
+ // C++11 [dcl.constexpr]p1: The constexpr specifier shall be applied only to
+ // the definition of a variable [...] or the declaration of a static data
+ // member.
+ if (Var->isConstexpr() && !Var->isThisDeclarationADefinition()) {
+ if (Var->isStaticDataMember())
+ Diag(Var->getLocation(),
+ diag::err_constexpr_static_mem_var_requires_init)
+ << Var->getDeclName();
+ else
+ Diag(Var->getLocation(), diag::err_invalid_constexpr_var_decl);
Var->setInvalidDecl();
return;
}
@@ -6338,7 +6386,7 @@
// is accepted by gcc. Hence here we issue a warning instead of
// an error and we do not invalidate the static declaration.
// NOTE: to avoid multiple warnings, only check the first declaration.
- if (Var->getPreviousDeclaration() == 0)
+ if (Var->getPreviousDecl() == 0)
RequireCompleteType(Var->getLocation(), Type,
diag::ext_typecheck_decl_incomplete_type);
}
@@ -6539,17 +6587,37 @@
Expr *Init = var->getInit();
bool IsGlobal = var->hasGlobalStorage() && !var->isStaticLocal();
- if (!var->getDeclContext()->isDependentContext() &&
- (var->isConstexpr() || IsGlobal) && Init &&
- !Init->isConstantInitializer(Context, baseType->isReferenceType())) {
- // FIXME: Improve this diagnostic to explain why the initializer is not
- // a constant expression.
- if (var->isConstexpr())
- Diag(var->getLocation(), diag::err_constexpr_var_requires_const_init)
- << var << Init->getSourceRange();
- if (IsGlobal)
+ if (!var->getDeclContext()->isDependentContext() && Init) {
+ if (IsGlobal && !var->isConstexpr() &&
+ getDiagnostics().getDiagnosticLevel(diag::warn_global_constructor,
+ var->getLocation())
+ != DiagnosticsEngine::Ignored &&
+ !Init->isConstantInitializer(Context, baseType->isReferenceType()))
Diag(var->getLocation(), diag::warn_global_constructor)
<< Init->getSourceRange();
+
+ if (var->isConstexpr()) {
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ if (!var->evaluateValue(Notes) || !var->isInitICE()) {
+ SourceLocation DiagLoc = var->getLocation();
+ // If the note doesn't add any useful information other than a source
+ // location, fold it into the primary diagnostic.
+ if (Notes.size() == 1 && Notes[0].second.getDiagID() ==
+ diag::note_invalid_subexpr_in_const_expr) {
+ DiagLoc = Notes[0].first;
+ Notes.clear();
+ }
+ Diag(DiagLoc, diag::err_constexpr_var_requires_const_init)
+ << var << Init->getSourceRange();
+ for (unsigned I = 0, N = Notes.size(); I != N; ++I)
+ Diag(Notes[I].first, Notes[I].second);
+ }
+ } else if (var->isUsableInConstantExpressions()) {
+ // Check whether the initializer of a const variable of integral or
+ // enumeration type is an ICE now, since we can't tell whether it was
+ // initialized by a constant expression if we check later.
+ var->checkInitIsICE();
+ }
}
// Require the destructor.
@@ -6769,7 +6837,7 @@
return;
for (; Param != ParamEnd; ++Param) {
- if (!(*Param)->isUsed() && (*Param)->getDeclName() &&
+ if (!(*Param)->isReferenced() && (*Param)->getDeclName() &&
!(*Param)->hasAttr<UnusedAttr>()) {
Diag((*Param)->getLocation(), diag::warn_unused_parameter)
<< (*Param)->getDeclName();
@@ -6786,7 +6854,7 @@
// Warn if the return value is pass-by-value and larger than the specified
// threshold.
- if (ReturnTy.isPODType(Context)) {
+ if (!ReturnTy->isDependentType() && ReturnTy.isPODType(Context)) {
unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity();
if (Size > LangOpts.NumLargeByValueCopy)
Diag(D->getLocation(), diag::warn_return_value_size)
@@ -6797,7 +6865,7 @@
// threshold.
for (; Param != ParamEnd; ++Param) {
QualType T = (*Param)->getType();
- if (!T.isPODType(Context))
+ if (T->isDependentType() || !T.isPODType(Context))
continue;
unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
if (Size > LangOpts.NumLargeByValueCopy)
@@ -6946,8 +7014,8 @@
return false;
bool MissingPrototype = true;
- for (const FunctionDecl *Prev = FD->getPreviousDeclaration();
- Prev; Prev = Prev->getPreviousDeclaration()) {
+ for (const FunctionDecl *Prev = FD->getPreviousDecl();
+ Prev; Prev = Prev->getPreviousDecl()) {
// Ignore any declarations that occur in function or method
// scope, because they aren't visible from the header.
if (Prev->getDeclContext()->isFunctionOrMethod())
@@ -7226,7 +7294,7 @@
if (!IsInstantiation)
PopDeclContext();
- PopFunctionOrBlockScope(ActivePolicy, dcl);
+ PopFunctionScopeInfo(ActivePolicy, dcl);
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
@@ -7266,7 +7334,7 @@
// Extension in C99. Legal in C90, but warn about it.
unsigned diag_id;
if (II.getName().startswith("__builtin_"))
- diag_id = diag::err_builtin_unknown;
+ diag_id = diag::warn_builtin_unknown;
else if (getLangOptions().C99)
diag_id = diag::ext_implicit_function_decl;
else
@@ -7277,21 +7345,20 @@
// function declaration is going to be treated as an error.
if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) {
TypoCorrection Corrected;
+ DeclFilterCCC<FunctionDecl> Validator;
if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc),
- LookupOrdinaryName, S, 0))) {
- NamedDecl *Decl = Corrected.getCorrectionDecl();
- if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Decl)) {
- std::string CorrectedStr = Corrected.getAsString(getLangOptions());
- std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOptions());
-
- Diag(Loc, diag::note_function_suggestion) << CorrectedQuotedStr
- << FixItHint::CreateReplacement(Loc, CorrectedStr);
-
- if (Func->getLocation().isValid()
- && !II.getName().startswith("__builtin_"))
- Diag(Func->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
- }
+ LookupOrdinaryName, S, 0, &Validator))) {
+ std::string CorrectedStr = Corrected.getAsString(getLangOptions());
+ std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOptions());
+ FunctionDecl *Func = Corrected.getCorrectionDeclAs<FunctionDecl>();
+
+ Diag(Loc, diag::note_function_suggestion) << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(Loc, CorrectedStr);
+
+ if (Func->getLocation().isValid()
+ && !II.getName().startswith("__builtin_"))
+ Diag(Func->getLocation(), diag::note_previous_decl)
+ << CorrectedQuotedStr;
}
}
@@ -7589,7 +7656,8 @@
SourceLocation ModulePrivateLoc,
MultiTemplateParamsArg TemplateParameterLists,
bool &OwnedDecl, bool &IsDependent,
- bool ScopedEnum, bool ScopedEnumUsesClassTag,
+ SourceLocation ScopedEnumKWLoc,
+ bool ScopedEnumUsesClassTag,
TypeResult UnderlyingType) {
// If this is not a definition, it must have a name.
assert((Name != 0 || TUK == TUK_Definition) &&
@@ -7598,6 +7666,7 @@
OwnedDecl = false;
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+ bool ScopedEnum = ScopedEnumKWLoc.isValid();
// FIXME: Check explicit specializations more carefully.
bool isExplicitSpecialization = false;
@@ -7836,7 +7905,8 @@
// Find the context where we'll be declaring the tag.
// FIXME: We would like to maintain the current DeclContext as the
// lexical context,
- while (SearchDC->isRecord() || SearchDC->isTransparentContext())
+ while (SearchDC->isRecord() || SearchDC->isTransparentContext() ||
+ SearchDC->isObjCContainer())
SearchDC = SearchDC->getParent();
// Find the scope where we'll be declaring the tag.
@@ -7928,6 +7998,16 @@
if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) {
const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl);
+ // If this is an elaborated-type-specifier for a scoped enumeration,
+ // the 'class' keyword is not necessary and not permitted.
+ if (TUK == TUK_Reference || TUK == TUK_Friend) {
+ if (ScopedEnum)
+ Diag(ScopedEnumKWLoc, diag::err_enum_class_reference)
+ << PrevEnum->isScoped()
+ << FixItHint::CreateRemoval(ScopedEnumKWLoc);
+ return PrevTagDecl;
+ }
+
// All conflicts with previous declarations are recovered by
// returning the previous declaration.
if (ScopedEnum != PrevEnum->isScoped()) {
@@ -8029,8 +8109,6 @@
// lookup. This is only actually possible in C++, where a few
// things like templates still live in the tag namespace.
} else {
- assert(getLangOptions().CPlusPlus);
-
// Use a better diagnostic if an elaborated-type-specifier
// found the wrong kind of type on the first
// (non-redeclaration) lookup.
@@ -8190,19 +8268,14 @@
AddMsStructLayoutForRecord(RD);
}
- if (PrevDecl && PrevDecl->isModulePrivate())
- New->setModulePrivate();
- else if (ModulePrivateLoc.isValid()) {
+ if (ModulePrivateLoc.isValid()) {
if (isExplicitSpecialization)
Diag(New->getLocation(), diag::err_module_private_specialization)
<< 2
<< FixItHint::CreateRemoval(ModulePrivateLoc);
- else if (PrevDecl && !PrevDecl->isModulePrivate())
- diagnoseModulePrivateRedeclaration(New, PrevDecl, ModulePrivateLoc);
// __module_private__ does not apply to local classes. However, we only
// diagnose this as an error when the declaration specifiers are
// freestanding. Here, we just ignore the __module_private__.
- // foobar
else if (!SearchDC->isFunctionOrMethod())
New->setModulePrivate();
}
@@ -9482,18 +9555,30 @@
if (Enum->isDependentType() || Val->isTypeDependent())
EltTy = Context.DependentTy;
else {
- // C99 6.7.2.2p2: Make sure we have an integer constant expression.
SourceLocation ExpLoc;
- if (!Val->isValueDependent() &&
- VerifyIntegerConstantExpression(Val, &EnumVal)) {
+ if (getLangOptions().CPlusPlus0x && Enum->isFixed()) {
+ // C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the
+ // constant-expression in the enumerator-definition shall be a converted
+ // constant expression of the underlying type.
+ EltTy = Enum->getIntegerType();
+ ExprResult Converted =
+ CheckConvertedConstantExpression(Val, EltTy, EnumVal,
+ CCEK_Enumerator);
+ if (Converted.isInvalid())
+ Val = 0;
+ else
+ Val = Converted.take();
+ } else if (!Val->isValueDependent() &&
+ VerifyIntegerConstantExpression(Val, &EnumVal)) {
+ // C99 6.7.2.2p2: Make sure we have an integer constant expression.
Val = 0;
- } else {
+ } else {
if (!getLangOptions().CPlusPlus) {
// C99 6.7.2.2p2:
// The expression that defines the value of an enumeration constant
- // shall be an integer constant expression that has a value
+ // shall be an integer constant expression that has a value
// representable as an int.
-
+
// Complain if the value is not representable in an int.
if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy))
Diag(IdLoc, diag::ext_enum_value_not_int)
@@ -9504,25 +9589,24 @@
Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).take();
}
}
-
+
if (Enum->isFixed()) {
EltTy = Enum->getIntegerType();
- // C++0x [dcl.enum]p5:
- // ... if the initializing value of an enumerator cannot be
- // represented by the underlying type, the program is ill-formed.
+ // In Obj-C and Microsoft mode, require the enumeration value to be
+ // representable in the underlying type of the enumeration. In C++11,
+ // we perform a non-narrowing conversion as part of converted constant
+ // expression checking.
if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
if (getLangOptions().MicrosoftExt) {
Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy;
Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
- } else
- Diag(IdLoc, diag::err_enumerator_too_large)
- << EltTy;
+ } else
+ Diag(IdLoc, diag::err_enumerator_too_large) << EltTy;
} else
Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
- }
- else {
- // C++0x [dcl.enum]p5:
+ } else {
+ // C++11 [dcl.enum]p5:
// If the underlying type is not fixed, the type of each enumerator
// is the type of its initializing value:
// - If an initializer is specified for an enumerator, the
@@ -9627,11 +9711,10 @@
Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
SourceLocation IdLoc, IdentifierInfo *Id,
AttributeList *Attr,
- SourceLocation EqualLoc, Expr *val) {
+ SourceLocation EqualLoc, Expr *Val) {
EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl);
EnumConstantDecl *LastEnumConst =
cast_or_null<EnumConstantDecl>(lastEnumConst);
- Expr *Val = static_cast<Expr*>(val);
// The scope passed in may not be a decl scope. Zip up the scope tree until
// we find one that is.
@@ -9920,7 +10003,9 @@
return New;
}
-DeclResult Sema::ActOnModuleImport(SourceLocation ImportLoc, ModuleIdPath Path) {
+DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
+ SourceLocation ImportLoc,
+ ModuleIdPath Path) {
Module *Mod = PP.getModuleLoader().loadModule(ImportLoc, Path,
Module::AllVisible,
/*IsIncludeDirective=*/false);
@@ -9941,26 +10026,12 @@
ImportDecl *Import = ImportDecl::Create(Context,
Context.getTranslationUnitDecl(),
- ImportLoc, Mod,
- IdentifierLocs);
+ AtLoc.isValid()? AtLoc : ImportLoc,
+ Mod, IdentifierLocs);
Context.getTranslationUnitDecl()->addDecl(Import);
return Import;
}
-void
-Sema::diagnoseModulePrivateRedeclaration(NamedDecl *New, NamedDecl *Old,
- SourceLocation ModulePrivateKeyword) {
- assert(!Old->isModulePrivate() && "Old is module-private!");
-
- Diag(New->getLocation(), diag::err_module_private_follows_public)
- << New->getDeclName() << SourceRange(ModulePrivateKeyword);
- Diag(Old->getLocation(), diag::note_previous_declaration)
- << Old->getDeclName();
-
- // Drop the __module_private__ from the new declaration, since it's invalid.
- New->setModulePrivate(false);
-}
-
void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc) {
Modified: cfe/branches/tooling/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaDeclAttr.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaDeclAttr.cpp Fri Jan 20 10:14:22 2012
@@ -1055,8 +1055,6 @@
}
break;
}
- default:
- llvm_unreachable("Unknown ownership attribute");
} // switch
// Check we don't have a conflict with another ownership attribute.
@@ -1107,7 +1105,6 @@
return false;
}
llvm_unreachable("unknown linkage kind!");
- return false;
}
static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1579,6 +1576,23 @@
Attr.getRange(), S.Context));
}
+static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!isa<ObjCInterfaceDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_suppress_autosynthesis);
+ return;
+ }
+
+ unsigned NumArgs = Attr.getNumArgs();
+ if (NumArgs > 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 0;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ObjCRequiresPropertyDefsAttr(
+ Attr.getRange(), S.Context));
+}
+
static void handleAvailabilityAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
IdentifierInfo *Platform = Attr.getParameterName();
@@ -1861,10 +1875,11 @@
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
return;
}
- } else if (isa<BlockDecl>(D)) {
- // Note! BlockDecl is typeless. Variadic diagnostics will be issued by the
- // caller.
- ;
+ } else if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ if (!BD->isVariadic()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1;
+ return;
+ }
} else if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
QualType Ty = V->getType();
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
@@ -2991,7 +3006,6 @@
}
default:
llvm_unreachable("unexpected attribute kind");
- return;
}
}
@@ -3040,7 +3054,7 @@
}
// FALLS THROUGH
}
- default: llvm_unreachable("unexpected attribute kind"); return true;
+ default: llvm_unreachable("unexpected attribute kind");
}
return false;
@@ -3226,7 +3240,7 @@
bool typeOK;
bool cf;
switch (Attr.getKind()) {
- default: llvm_unreachable("invalid ownership attribute"); return;
+ default: llvm_unreachable("invalid ownership attribute");
case AttributeList::AT_ns_returns_autoreleased:
case AttributeList::AT_ns_returns_retained:
case AttributeList::AT_ns_returns_not_retained:
@@ -3603,6 +3617,9 @@
case AttributeList::AT_arc_weakref_unavailable:
handleArcWeakrefUnavailableAttr (S, D, Attr);
break;
+ case AttributeList::AT_objc_requires_property_definitions:
+ handleObjCRequiresPropertyDefsAttr (S, D, Attr);
+ break;
case AttributeList::AT_unused: handleUnusedAttr (S, D, Attr); break;
case AttributeList::AT_returns_twice:
handleReturnsTwiceAttr(S, D, Attr);
Modified: cfe/branches/tooling/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaDeclCXX.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaDeclCXX.cpp Fri Jan 20 10:14:22 2012
@@ -420,8 +420,8 @@
// Look for the function declaration where the default argument was
// actually written, which may be a declaration prior to Old.
- for (FunctionDecl *Older = Old->getPreviousDeclaration();
- Older; Older = Older->getPreviousDeclaration()) {
+ for (FunctionDecl *Older = Old->getPreviousDecl();
+ Older; Older = Older->getPreviousDecl()) {
if (!Older->getParamDecl(p)->hasDefaultArg())
break;
@@ -648,7 +648,7 @@
// the requirements of a constexpr function declaration or a constexpr
// constructor declaration. Return true if it does, false if not.
//
-// This implements C++0x [dcl.constexpr]p3,4, as amended by N3308.
+// This implements C++11 [dcl.constexpr]p3,4, as amended by N3308.
//
// \param CCK Specifies whether to produce diagnostics if the function does not
// satisfy the requirements.
@@ -659,17 +659,16 @@
NewFD->getTemplateInstantiationPattern()->isConstexpr())) &&
"only constexpr templates can be instantiated non-constexpr");
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(NewFD)) {
- // C++0x [dcl.constexpr]p4:
- // In the definition of a constexpr constructor, each of the parameter
- // types shall be a literal type.
- if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
- return false;
-
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
+ if (MD && MD->isInstance()) {
+ // C++11 [dcl.constexpr]p4: In the definition of a constexpr constructor...
// In addition, either its function-body shall be = delete or = default or
// it shall satisfy the following constraints:
// - the class shall not have any virtual base classes;
- const CXXRecordDecl *RD = CD->getParent();
+ //
+ // We apply this to constexpr member functions too: the class cannot be a
+ // literal type, so the members are not permitted to be constexpr.
+ const CXXRecordDecl *RD = MD->getParent();
if (RD->getNumVBases()) {
// Note, this is still illegal if the body is = default, since the
// implicit body does not satisfy the requirements of a constexpr
@@ -679,7 +678,8 @@
Diag(NewFD->getLocation(),
CCK == CCK_Declaration ? diag::err_constexpr_virtual_base
: diag::note_constexpr_tmpl_virtual_base)
- << RD->isStruct() << RD->getNumVBases();
+ << isa<CXXConstructorDecl>(NewFD) << RD->isStruct()
+ << RD->getNumVBases();
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I)
Diag(I->getSourceRange().getBegin(),
@@ -687,8 +687,10 @@
}
return false;
}
- } else {
- // C++0x [dcl.constexpr]p3:
+ }
+
+ if (!isa<CXXConstructorDecl>(NewFD)) {
+ // C++11 [dcl.constexpr]p3:
// The definition of a constexpr function shall satisfy the following
// constraints:
// - it shall not be virtual;
@@ -705,7 +707,7 @@
while (!WrittenVirtual->isVirtualAsWritten())
WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
if (WrittenVirtual != Method)
- Diag(WrittenVirtual->getLocation(),
+ Diag(WrittenVirtual->getLocation(),
diag::note_overridden_virtual_function);
}
return false;
@@ -723,12 +725,12 @@
diag::note_constexpr_tmpl_non_literal_return) << RT;
return false;
}
-
- // - each of its parameter types shall be a literal type;
- if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
- return false;
}
+ // - each of its parameter types shall be a literal type;
+ if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
+ return false;
+
return true;
}
@@ -1745,6 +1747,31 @@
EllipsisLoc);
}
+namespace {
+
+// Callback to only accept typo corrections that can be a valid C++ member
+// intializer: either a non-static field member or a base class.
+class MemInitializerValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ explicit MemInitializerValidatorCCC(CXXRecordDecl *ClassDecl)
+ : ClassDecl(ClassDecl) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ if (NamedDecl *ND = candidate.getCorrectionDecl()) {
+ if (FieldDecl *Member = dyn_cast<FieldDecl>(ND))
+ return Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl);
+ else
+ return isa<TypeDecl>(ND);
+ }
+ return false;
+ }
+
+ private:
+ CXXRecordDecl *ClassDecl;
+};
+
+}
+
/// \brief Handle a C++ member initializer.
MemInitResult
Sema::BuildMemInitializer(Decl *ConstructorD,
@@ -1837,24 +1864,23 @@
// If no results were found, try to correct typos.
TypoCorrection Corr;
+ MemInitializerValidatorCCC Validator(ClassDecl);
if (R.empty() && BaseType.isNull() &&
(Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
- ClassDecl, false, CTC_NoKeywords))) {
+ &Validator, ClassDecl))) {
std::string CorrectedStr(Corr.getAsString(getLangOptions()));
std::string CorrectedQuotedStr(Corr.getQuoted(getLangOptions()));
if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
- if (Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl)) {
- // We have found a non-static data member with a similar
- // name to what was typed; complain and initialize that
- // member.
- Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
- << MemberOrBase << true << CorrectedQuotedStr
- << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
- Diag(Member->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
+ // We have found a non-static data member with a similar
+ // name to what was typed; complain and initialize that
+ // member.
+ Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
+ << MemberOrBase << true << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ Diag(Member->getLocation(), diag::note_previous_decl)
+ << CorrectedQuotedStr;
- return BuildMemberInitializer(Member, Args, IdLoc);
- }
+ return BuildMemberInitializer(Member, Args, IdLoc);
} else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) {
const CXXBaseSpecifier *DirectBaseSpec;
const CXXBaseSpecifier *VirtualBaseSpec;
@@ -2340,7 +2366,9 @@
bool Moving = ImplicitInitKind == IIK_Move;
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
-
+
+ SemaRef.MarkDeclarationReferenced(Constructor->getLocation(), Param);
+
Expr *CopyCtorArg =
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
Constructor->getLocation(), ParamType,
@@ -2410,6 +2438,8 @@
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
+ SemaRef.MarkDeclarationReferenced(Constructor->getLocation(), Param);
+
// Suppress copying zero-width bitfields.
if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0)
return false;
@@ -3651,7 +3681,7 @@
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
MEnd = Record->method_end();
M != MEnd; ++M) {
- if ((*M)->isConstexpr()) {
+ if (M->isConstexpr() && M->isInstance()) {
switch (Record->getTemplateSpecializationKind()) {
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDeclaration:
@@ -3756,6 +3786,18 @@
*ExceptionType = Context.getFunctionType(
Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+ // C++11 [dcl.fct.def.default]p2:
+ // An explicitly-defaulted function may be declared constexpr only if it
+ // would have been implicitly declared as constexpr,
+ if (CD->isConstexpr()) {
+ if (!CD->getParent()->defaultedDefaultConstructorIsConstexpr()) {
+ Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+ << CXXDefaultConstructor;
+ HadError = true;
+ }
+ }
+ // and may have an explicit exception-specification only if it is compatible
+ // with the exception-specification on the implicit declaration.
if (CtorType->hasExceptionSpec()) {
if (CheckEquivalentExceptionSpec(
PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3765,11 +3807,20 @@
CtorType, CD->getLocation())) {
HadError = true;
}
- } else if (First) {
- // We set the declaration to have the computed exception spec here.
- // We know there are no parameters.
+ }
+
+ // If a function is explicitly defaulted on its first declaration,
+ if (First) {
+ // -- it is implicitly considered to be constexpr if the implicit
+ // definition would be,
+ CD->setConstexpr(CD->getParent()->defaultedDefaultConstructorIsConstexpr());
+
+ // -- it is implicitly considered to have the same
+ // exception-specification as if it had been implicitly declared
+ //
+ // FIXME: a compatible, but different, explicit exception specification
+ // will be silently overridden. We should issue a warning if this happens.
EPI.ExtInfo = CtorType->getExtInfo();
- CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
}
if (HadError) {
@@ -3823,6 +3874,18 @@
HadError = true;
}
+ // C++11 [dcl.fct.def.default]p2:
+ // An explicitly-defaulted function may be declared constexpr only if it
+ // would have been implicitly declared as constexpr,
+ if (CD->isConstexpr()) {
+ if (!CD->getParent()->defaultedCopyConstructorIsConstexpr()) {
+ Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+ << CXXCopyConstructor;
+ HadError = true;
+ }
+ }
+ // and may have an explicit exception-specification only if it is compatible
+ // with the exception-specification on the implicit declaration.
if (CtorType->hasExceptionSpec()) {
if (CheckEquivalentExceptionSpec(
PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3832,10 +3895,23 @@
CtorType, CD->getLocation())) {
HadError = true;
}
- } else if (First) {
- // We set the declaration to have the computed exception spec here.
- // We duplicate the one parameter type.
+ }
+
+ // If a function is explicitly defaulted on its first declaration,
+ if (First) {
+ // -- it is implicitly considered to be constexpr if the implicit
+ // definition would be,
+ CD->setConstexpr(CD->getParent()->defaultedCopyConstructorIsConstexpr());
+
+ // -- it is implicitly considered to have the same
+ // exception-specification as if it had been implicitly declared, and
+ //
+ // FIXME: a compatible, but different, explicit exception specification
+ // will be silently overridden. We should issue a warning if this happens.
EPI.ExtInfo = CtorType->getExtInfo();
+
+ // -- [...] it shall have the same parameter type as if it had been
+ // implicitly declared.
CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
}
@@ -3917,7 +3993,8 @@
OperType, MD->getLocation())) {
HadError = true;
}
- } else if (First) {
+ }
+ if (First) {
// We set the declaration to have the computed exception spec here.
// We duplicate the one parameter type.
EPI.RefQualifier = OperType->getRefQualifier();
@@ -3974,6 +4051,18 @@
HadError = true;
}
+ // C++11 [dcl.fct.def.default]p2:
+ // An explicitly-defaulted function may be declared constexpr only if it
+ // would have been implicitly declared as constexpr,
+ if (CD->isConstexpr()) {
+ if (!CD->getParent()->defaultedMoveConstructorIsConstexpr()) {
+ Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+ << CXXMoveConstructor;
+ HadError = true;
+ }
+ }
+ // and may have an explicit exception-specification only if it is compatible
+ // with the exception-specification on the implicit declaration.
if (CtorType->hasExceptionSpec()) {
if (CheckEquivalentExceptionSpec(
PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3983,10 +4072,23 @@
CtorType, CD->getLocation())) {
HadError = true;
}
- } else if (First) {
- // We set the declaration to have the computed exception spec here.
- // We duplicate the one parameter type.
+ }
+
+ // If a function is explicitly defaulted on its first declaration,
+ if (First) {
+ // -- it is implicitly considered to be constexpr if the implicit
+ // definition would be,
+ CD->setConstexpr(CD->getParent()->defaultedMoveConstructorIsConstexpr());
+
+ // -- it is implicitly considered to have the same
+ // exception-specification as if it had been implicitly declared, and
+ //
+ // FIXME: a compatible, but different, explicit exception specification
+ // will be silently overridden. We should issue a warning if this happens.
EPI.ExtInfo = CtorType->getExtInfo();
+
+ // -- [...] it shall have the same parameter type as if it had been
+ // implicitly declared.
CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
}
@@ -4066,7 +4168,8 @@
OperType, MD->getLocation())) {
HadError = true;
}
- } else if (First) {
+ }
+ if (First) {
// We set the declaration to have the computed exception spec here.
// We duplicate the one parameter type.
EPI.RefQualifier = OperType->getRefQualifier();
@@ -4113,7 +4216,8 @@
DD->setInvalidDecl();
return;
}
- } else if (First) {
+ }
+ if (First) {
// We set the declaration to have the computed exception spec here.
// There are no parameters.
EPI.ExtInfo = DtorType->getExtInfo();
@@ -4907,6 +5011,9 @@
if (!ClassDecl->hasUserDeclaredCopyConstructor())
++ASTContext::NumImplicitCopyConstructors;
+ if (getLangOptions().CPlusPlus0x && ClassDecl->needsImplicitMoveConstructor())
+ ++ASTContext::NumImplicitMoveConstructors;
+
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
++ASTContext::NumImplicitCopyAssignmentOperators;
@@ -4918,6 +5025,14 @@
DeclareImplicitCopyAssignment(ClassDecl);
}
+ if (getLangOptions().CPlusPlus0x && ClassDecl->needsImplicitMoveAssignment()){
+ ++ASTContext::NumImplicitMoveAssignmentOperators;
+
+ // Likewise for the move assignment operator.
+ if (ClassDecl->isDynamicClass())
+ DeclareImplicitMoveAssignment(ClassDecl);
+ }
+
if (!ClassDecl->hasUserDeclaredDestructor()) {
++ASTContext::NumImplicitDestructors;
@@ -5446,17 +5561,13 @@
SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc;
// For anonymous namespace, take the location of the left brace.
SourceLocation Loc = II ? IdentLoc : LBrace;
- NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext,
- StartLoc, Loc, II);
- Namespc->setInline(InlineLoc.isValid());
-
+ bool IsInline = InlineLoc.isValid();
+ bool IsInvalid = false;
+ bool IsStd = false;
+ bool AddToKnown = false;
Scope *DeclRegionScope = NamespcScope->getParent();
- ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
-
- if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
- PushNamespaceVisibilityAttr(Attr);
-
+ NamespaceDecl *PrevNS = 0;
if (II) {
// C++ [namespace.def]p2:
// The identifier in an original-namespace-definition shall not
@@ -5470,11 +5581,11 @@
// look through using directives, just look for any ordinary names.
const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member |
- Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
- Decl::IDNS_Namespace;
+ Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
+ Decl::IDNS_Namespace;
NamedDecl *PrevDecl = 0;
for (DeclContext::lookup_result R
- = CurContext->getRedeclContext()->lookup(II);
+ = CurContext->getRedeclContext()->lookup(II);
R.first != R.second; ++R.first) {
if ((*R.first)->getIdentifierNamespace() & IDNS) {
PrevDecl = *R.first;
@@ -5482,100 +5593,91 @@
}
}
- if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
+ PrevNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl);
+
+ if (PrevNS) {
// This is an extended namespace definition.
- if (Namespc->isInline() != OrigNS->isInline()) {
+ if (IsInline != PrevNS->isInline()) {
// inline-ness must match
- if (OrigNS->isInline()) {
+ if (PrevNS->isInline()) {
// The user probably just forgot the 'inline', so suggest that it
// be added back.
- Diag(Namespc->getLocation(),
- diag::warn_inline_namespace_reopened_noninline)
+ Diag(Loc, diag::warn_inline_namespace_reopened_noninline)
<< FixItHint::CreateInsertion(NamespaceLoc, "inline ");
} else {
- Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
- << Namespc->isInline();
+ Diag(Loc, diag::err_inline_namespace_mismatch)
+ << IsInline;
}
- Diag(OrigNS->getLocation(), diag::note_previous_definition);
-
- // Recover by ignoring the new namespace's inline status.
- Namespc->setInline(OrigNS->isInline());
- }
-
- // Attach this namespace decl to the chain of extended namespace
- // definitions.
- OrigNS->setNextNamespace(Namespc);
- Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace());
-
- // Remove the previous declaration from the scope.
- if (DeclRegionScope->isDeclScope(OrigNS)) {
- IdResolver.RemoveDecl(OrigNS);
- DeclRegionScope->RemoveDecl(OrigNS);
- }
+ Diag(PrevNS->getLocation(), diag::note_previous_definition);
+
+ IsInline = PrevNS->isInline();
+ }
} else if (PrevDecl) {
// This is an invalid name redefinition.
- Diag(Namespc->getLocation(), diag::err_redefinition_different_kind)
- << Namespc->getDeclName();
+ Diag(Loc, diag::err_redefinition_different_kind)
+ << II;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- Namespc->setInvalidDecl();
+ IsInvalid = true;
// Continue on to push Namespc as current DeclContext and return it.
- } else if (II->isStr("std") &&
+ } else if (II->isStr("std") &&
CurContext->getRedeclContext()->isTranslationUnit()) {
// This is the first "real" definition of the namespace "std", so update
// our cache of the "std" namespace to point at this definition.
- if (NamespaceDecl *StdNS = getStdNamespace()) {
- // We had already defined a dummy namespace "std". Link this new
- // namespace definition to the dummy namespace "std".
- StdNS->setNextNamespace(Namespc);
- StdNS->setLocation(IdentLoc);
- Namespc->setOriginalNamespace(StdNS->getOriginalNamespace());
- }
-
- // Make our StdNamespace cache point at the first real definition of the
- // "std" namespace.
- StdNamespace = Namespc;
-
- // Add this instance of "std" to the set of known namespaces
- KnownNamespaces[Namespc] = false;
- } else if (!Namespc->isInline()) {
- // Since this is an "original" namespace, add it to the known set of
- // namespaces if it is not an inline namespace.
- KnownNamespaces[Namespc] = false;
+ PrevNS = getStdNamespace();
+ IsStd = true;
+ AddToKnown = !IsInline;
+ } else {
+ // We've seen this namespace for the first time.
+ AddToKnown = !IsInline;
}
-
- PushOnScopeChains(Namespc, DeclRegionScope);
} else {
// Anonymous namespaces.
- assert(Namespc->isAnonymousNamespace());
-
- // Link the anonymous namespace into its parent.
- NamespaceDecl *PrevDecl;
+
+ // Determine whether the parent already has an anonymous namespace.
DeclContext *Parent = CurContext->getRedeclContext();
if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
- PrevDecl = TU->getAnonymousNamespace();
- TU->setAnonymousNamespace(Namespc);
+ PrevNS = TU->getAnonymousNamespace();
} else {
NamespaceDecl *ND = cast<NamespaceDecl>(Parent);
- PrevDecl = ND->getAnonymousNamespace();
- ND->setAnonymousNamespace(Namespc);
+ PrevNS = ND->getAnonymousNamespace();
+ }
+
+ if (PrevNS && IsInline != PrevNS->isInline()) {
+ // inline-ness must match
+ Diag(Loc, diag::err_inline_namespace_mismatch)
+ << IsInline;
+ Diag(PrevNS->getLocation(), diag::note_previous_definition);
+
+ // Recover by ignoring the new namespace's inline status.
+ IsInline = PrevNS->isInline();
}
+ }
+
+ NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,
+ StartLoc, Loc, II, PrevNS);
+ if (IsInvalid)
+ Namespc->setInvalidDecl();
+
+ ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
- // Link the anonymous namespace with its previous declaration.
- if (PrevDecl) {
- assert(PrevDecl->isAnonymousNamespace());
- assert(!PrevDecl->getNextNamespace());
- Namespc->setOriginalNamespace(PrevDecl->getOriginalNamespace());
- PrevDecl->setNextNamespace(Namespc);
+ // FIXME: Should we be merging attributes?
+ if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
+ PushNamespaceVisibilityAttr(Attr);
- if (Namespc->isInline() != PrevDecl->isInline()) {
- // inline-ness must match
- Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
- << Namespc->isInline();
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- Namespc->setInvalidDecl();
- // Recover by ignoring the new namespace's inline status.
- Namespc->setInline(PrevDecl->isInline());
- }
+ if (IsStd)
+ StdNamespace = Namespc;
+ if (AddToKnown)
+ KnownNamespaces[Namespc] = false;
+
+ if (II) {
+ PushOnScopeChains(Namespc, DeclRegionScope);
+ } else {
+ // Link the anonymous namespace into its parent.
+ DeclContext *Parent = CurContext->getRedeclContext();
+ if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
+ TU->setAnonymousNamespace(Namespc);
+ } else {
+ cast<NamespaceDecl>(Parent)->setAnonymousNamespace(Namespc);
}
CurContext->addDecl(Namespc);
@@ -5596,7 +5698,7 @@
// declarations semantically contained within an anonymous
// namespace internal linkage.
- if (!PrevDecl) {
+ if (!PrevNS) {
UsingDirectiveDecl* UD
= UsingDirectiveDecl::Create(Context, CurContext,
/* 'using' */ LBrace,
@@ -5655,14 +5757,143 @@
// The "std" namespace has not yet been defined, so build one implicitly.
StdNamespace = NamespaceDecl::Create(Context,
Context.getTranslationUnitDecl(),
+ /*Inline=*/false,
SourceLocation(), SourceLocation(),
- &PP.getIdentifierTable().get("std"));
+ &PP.getIdentifierTable().get("std"),
+ /*PrevDecl=*/0);
getStdNamespace()->setImplicit(true);
}
return getStdNamespace();
}
+bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
+ assert(getLangOptions().CPlusPlus &&
+ "Looking for std::initializer_list outside of C++.");
+
+ // We're looking for implicit instantiations of
+ // template <typename E> class std::initializer_list.
+
+ if (!StdNamespace) // If we haven't seen namespace std yet, this can't be it.
+ return false;
+
+ ClassTemplateDecl *Template = 0;
+ const TemplateArgument *Arguments = 0;
+
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+
+ ClassTemplateSpecializationDecl *Specialization =
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
+ if (!Specialization)
+ return false;
+
+ if (Specialization->getSpecializationKind() != TSK_ImplicitInstantiation)
+ return false;
+
+ Template = Specialization->getSpecializedTemplate();
+ Arguments = Specialization->getTemplateArgs().data();
+ } else if (const TemplateSpecializationType *TST =
+ Ty->getAs<TemplateSpecializationType>()) {
+ Template = dyn_cast_or_null<ClassTemplateDecl>(
+ TST->getTemplateName().getAsTemplateDecl());
+ Arguments = TST->getArgs();
+ }
+ if (!Template)
+ return false;
+
+ if (!StdInitializerList) {
+ // Haven't recognized std::initializer_list yet, maybe this is it.
+ CXXRecordDecl *TemplateClass = Template->getTemplatedDecl();
+ if (TemplateClass->getIdentifier() !=
+ &PP.getIdentifierTable().get("initializer_list") ||
+ !TemplateClass->getDeclContext()->Equals(getStdNamespace()))
+ return false;
+ // This is a template called std::initializer_list, but is it the right
+ // template?
+ TemplateParameterList *Params = Template->getTemplateParameters();
+ if (Params->size() != 1)
+ return false;
+ if (!isa<TemplateTypeParmDecl>(Params->getParam(0)))
+ return false;
+
+ // It's the right template.
+ StdInitializerList = Template;
+ }
+
+ if (Template != StdInitializerList)
+ return false;
+
+ // This is an instance of std::initializer_list. Find the argument type.
+ if (Element)
+ *Element = Arguments[0].getAsType();
+ return true;
+}
+
+static ClassTemplateDecl *LookupStdInitializerList(Sema &S, SourceLocation Loc){
+ NamespaceDecl *Std = S.getStdNamespace();
+ if (!Std) {
+ S.Diag(Loc, diag::err_implied_std_initializer_list_not_found);
+ return 0;
+ }
+
+ LookupResult Result(S, &S.PP.getIdentifierTable().get("initializer_list"),
+ Loc, Sema::LookupOrdinaryName);
+ if (!S.LookupQualifiedName(Result, Std)) {
+ S.Diag(Loc, diag::err_implied_std_initializer_list_not_found);
+ return 0;
+ }
+ ClassTemplateDecl *Template = Result.getAsSingle<ClassTemplateDecl>();
+ if (!Template) {
+ Result.suppressDiagnostics();
+ // We found something weird. Complain about the first thing we found.
+ NamedDecl *Found = *Result.begin();
+ S.Diag(Found->getLocation(), diag::err_malformed_std_initializer_list);
+ return 0;
+ }
+
+ // We found some template called std::initializer_list. Now verify that it's
+ // correct.
+ TemplateParameterList *Params = Template->getTemplateParameters();
+ if (Params->size() != 1 || !isa<TemplateTypeParmDecl>(Params->getParam(0))) {
+ S.Diag(Template->getLocation(), diag::err_malformed_std_initializer_list);
+ return 0;
+ }
+
+ return Template;
+}
+
+QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
+ if (!StdInitializerList) {
+ StdInitializerList = LookupStdInitializerList(*this, Loc);
+ if (!StdInitializerList)
+ return QualType();
+ }
+
+ TemplateArgumentListInfo Args(Loc, Loc);
+ Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element),
+ Context.getTrivialTypeSourceInfo(Element,
+ Loc)));
+ return Context.getCanonicalType(
+ CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
+}
+
+bool Sema::isInitListConstructor(const CXXConstructorDecl* Ctor) {
+ // C++ [dcl.init.list]p2:
+ // A constructor is an initializer-list constructor if its first parameter
+ // is of type std::initializer_list<E> or reference to possibly cv-qualified
+ // std::initializer_list<E> for some type E, and either there are no other
+ // parameters or else all other parameters have default arguments.
+ if (Ctor->getNumParams() < 1 ||
+ (Ctor->getNumParams() > 1 && !Ctor->getParamDecl(1)->hasDefaultArg()))
+ return false;
+
+ QualType ArgType = Ctor->getParamDecl(0)->getType();
+ if (const ReferenceType *RT = ArgType->getAs<ReferenceType>())
+ ArgType = RT->getPointeeType().getUnqualifiedType();
+
+ return isStdInitializerList(ArgType, 0);
+}
+
/// \brief Determine whether a using statement is in a context where it will be
/// apply in all contexts.
static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) {
@@ -5676,35 +5907,47 @@
}
}
+namespace {
+
+// Callback to only accept typo corrections that are namespaces.
+class NamespaceValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ if (NamedDecl *ND = candidate.getCorrectionDecl()) {
+ return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
+ }
+ return false;
+ }
+};
+
+}
+
static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident) {
+ NamespaceValidatorCCC Validator;
R.clear();
if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), Sc, &SS, NULL,
- false, S.CTC_NoKeywords, NULL)) {
- if (Corrected.getCorrectionDeclAs<NamespaceDecl>() ||
- Corrected.getCorrectionDeclAs<NamespaceAliasDecl>()) {
- std::string CorrectedStr(Corrected.getAsString(S.getLangOptions()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOptions()));
- if (DeclContext *DC = S.computeDeclContext(SS, false))
- S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
- << Ident << DC << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
- else
- S.Diag(IdentLoc, diag::err_using_directive_suggest)
- << Ident << CorrectedQuotedStr
- << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+ R.getLookupKind(), Sc, &SS,
+ &Validator)) {
+ std::string CorrectedStr(Corrected.getAsString(S.getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOptions()));
+ if (DeclContext *DC = S.computeDeclContext(SS, false))
+ S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
+ << Ident << DC << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+ else
+ S.Diag(IdentLoc, diag::err_using_directive_suggest)
+ << Ident << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
- S.Diag(Corrected.getCorrectionDecl()->getLocation(),
- diag::note_namespace_defined_here) << CorrectedQuotedStr;
+ S.Diag(Corrected.getCorrectionDecl()->getLocation(),
+ diag::note_namespace_defined_here) << CorrectedQuotedStr;
- Ident = Corrected.getCorrectionAsIdentifierInfo();
- R.addDecl(Corrected.getCorrectionDecl());
- return true;
- }
- R.setLookupName(Ident);
+ Ident = Corrected.getCorrectionAsIdentifierInfo();
+ R.addDecl(Corrected.getCorrectionDecl());
+ return true;
}
return false;
}
@@ -6699,7 +6942,7 @@
~ImplicitlyDefinedFunctionScope() {
S.PopExpressionEvaluationContext();
- S.PopFunctionOrBlockScope();
+ S.PopFunctionScopeInfo();
}
};
}
@@ -6792,16 +7035,12 @@
DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(ClassType);
DeclarationNameInfo NameInfo(Name, ClassLoc);
- CXXConstructorDecl *DefaultCon
- = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(Context.VoidTy,
- 0, 0, EPI),
- /*TInfo=*/0,
- /*isExplicit=*/false,
- /*isInline=*/true,
- /*isImplicitlyDeclared=*/true,
- // FIXME: apply the rules for definitions here
- /*isConstexpr=*/false);
+ CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
+ Context, ClassDecl, ClassLoc, NameInfo,
+ Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0,
+ /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+ /*isConstexpr=*/ClassDecl->defaultedDefaultConstructorIsConstexpr() &&
+ getLangOptions().CPlusPlus0x);
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
DefaultCon->setImplicit();
@@ -8476,21 +8715,17 @@
DeclarationNameInfo NameInfo(Name, ClassLoc);
// An implicitly-declared copy constructor is an inline public
- // member of its class.
- CXXConstructorDecl *CopyConstructor
- = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(Context.VoidTy,
- &ArgType, 1, EPI),
- /*TInfo=*/0,
- /*isExplicit=*/false,
- /*isInline=*/true,
- /*isImplicitlyDeclared=*/true,
- // FIXME: apply the rules for definitions here
- /*isConstexpr=*/false);
+ // member of its class.
+ CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
+ Context, ClassDecl, ClassLoc, NameInfo,
+ Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
+ /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+ /*isConstexpr=*/ClassDecl->defaultedCopyConstructorIsConstexpr() &&
+ getLangOptions().CPlusPlus0x);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
-
+
// Note that we have declared this constructor.
++ASTContext::NumImplicitCopyConstructorsDeclared;
@@ -8631,21 +8866,17 @@
// C++0x [class.copy]p11:
// An implicitly-declared copy/move constructor is an inline public
- // member of its class.
- CXXConstructorDecl *MoveConstructor
- = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(Context.VoidTy,
- &ArgType, 1, EPI),
- /*TInfo=*/0,
- /*isExplicit=*/false,
- /*isInline=*/true,
- /*isImplicitlyDeclared=*/true,
- // FIXME: apply the rules for definitions here
- /*isConstexpr=*/false);
+ // member of its class.
+ CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
+ Context, ClassDecl, ClassLoc, NameInfo,
+ Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
+ /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+ /*isConstexpr=*/ClassDecl->defaultedMoveConstructorIsConstexpr() &&
+ getLangOptions().CPlusPlus0x);
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();
MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());
-
+
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
ClassLoc, ClassLoc,
@@ -8825,8 +9056,6 @@
MultiExprArg Exprs,
SourceLocation RParenLoc,
bool TypeMayContainAuto) {
- assert(Exprs.size() != 0 && Exprs.get() && "missing expressions");
-
// If there is no declaration, there was an error parsing it. Just ignore
// the initializer.
if (RealDecl == 0)
@@ -8839,9 +9068,18 @@
return;
}
- // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
+ // C++0x [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
- // FIXME: n3225 doesn't actually seem to indicate this is ill-formed
+ if (Exprs.size() == 0) {
+ // It isn't possible to write this directly, but it is possible to
+ // end up in this situation with "auto x(some_pack...);"
+ Diag(LParenLoc, diag::err_auto_var_init_no_expression)
+ << VDecl->getDeclName() << VDecl->getType()
+ << VDecl->getSourceRange();
+ RealDecl->setInvalidDecl();
+ return;
+ }
+
if (Exprs.size() > 1) {
Diag(Exprs.get()[1]->getSourceRange().getBegin(),
diag::err_auto_var_init_multiple_expressions)
@@ -8854,9 +9092,7 @@
Expr *Init = Exprs.get()[0];
TypeSourceInfo *DeducedType = 0;
if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
- Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
- << VDecl->getDeclName() << VDecl->getType() << Init->getType()
- << Init->getSourceRange();
+ DiagnoseAutoDeductionFailure(VDecl, Init);
if (!DeducedType) {
RealDecl->setInvalidDecl();
return;
@@ -8870,7 +9106,7 @@
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
- if (VarDecl *Old = VDecl->getPreviousDeclaration())
+ if (VarDecl *Old = VDecl->getPreviousDecl())
MergeVarDeclTypes(VDecl, Old);
}
@@ -9783,7 +10019,7 @@
Attr, AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(), Owned, IsDependent,
- /*ScopedEnum=*/false,
+ /*ScopedEnumKWLoc=*/SourceLocation(),
/*ScopedEnumUsesClassTag=*/false,
/*UnderlyingType=*/TypeResult());
}
@@ -10203,7 +10439,7 @@
Diag(DelLoc, diag::err_deleted_non_function);
return;
}
- if (const FunctionDecl *Prev = Fn->getPreviousDeclaration()) {
+ if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
Diag(DelLoc, diag::err_deleted_decl_not_first);
Diag(Prev->getLocation(), diag::note_previous_declaration);
// If the declaration wasn't the first, we delete the function anyway for
@@ -10515,7 +10751,8 @@
// not have a vtable.
if (!Class->isDynamicClass() || Class->isDependentContext() ||
CurContext->isDependentContext() ||
- ExprEvalContexts.back().Context == Unevaluated)
+ ExprEvalContexts.back().Context == Unevaluated ||
+ ExprEvalContexts.back().Context == ConstantEvaluated)
return;
// Try to insert this class into the map.
Modified: cfe/branches/tooling/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaDeclObjC.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaDeclObjC.cpp Fri Jan 20 10:14:22 2012
@@ -347,6 +347,28 @@
}
}
+namespace {
+
+// Callback to only accept typo corrections that are Objective-C classes.
+// If an ObjCInterfaceDecl* is given to the constructor, then the validation
+// function will reject corrections to that class.
+class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ ObjCInterfaceValidatorCCC() : CurrentIDecl(0) {}
+ explicit ObjCInterfaceValidatorCCC(ObjCInterfaceDecl *IDecl)
+ : CurrentIDecl(IDecl) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ ObjCInterfaceDecl *ID = candidate.getCorrectionDeclAs<ObjCInterfaceDecl>();
+ return ID && !declaresSameEntity(ID, CurrentIDecl);
+ }
+
+ private:
+ ObjCInterfaceDecl *CurrentIDecl;
+};
+
+}
+
Decl *Sema::
ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
@@ -396,20 +418,17 @@
LookupOrdinaryName);
if (!PrevDecl) {
- // Try to correct for a typo in the superclass name.
- TypoCorrection Corrected = CorrectTypo(
+ // Try to correct for a typo in the superclass name without correcting
+ // to the class we're defining.
+ ObjCInterfaceValidatorCCC Validator(IDecl);
+ if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
- NULL, NULL, false, CTC_NoKeywords);
- if ((PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
- if (declaresSameEntity(PrevDecl, IDecl)) {
- // Don't correct to the class we're defining.
- PrevDecl = 0;
- } else {
- Diag(SuperLoc, diag::err_undef_superclass_suggest)
- << SuperName << ClassName << PrevDecl->getDeclName();
- Diag(PrevDecl->getLocation(), diag::note_previous_decl)
- << PrevDecl->getDeclName();
- }
+ NULL, &Validator)) {
+ PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
+ Diag(SuperLoc, diag::err_undef_superclass_suggest)
+ << SuperName << ClassName << PrevDecl->getDeclName();
+ Diag(PrevDecl->getLocation(), diag::note_previous_decl)
+ << PrevDecl->getDeclName();
}
}
@@ -545,6 +564,10 @@
Diag(PrevLoc, diag::note_previous_definition);
res = true;
}
+
+ if (!PDecl->hasDefinition())
+ continue;
+
if (CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
PDecl->getLocation(), PDecl->getReferencedProtocols()))
res = true;
@@ -565,49 +588,52 @@
bool err = false;
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
- ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc);
- if (PDecl) {
- // Protocol already seen. Better be a forward protocol declaration
- if (!PDecl->isForwardDecl()) {
- Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName;
- Diag(PDecl->getLocation(), diag::note_previous_definition);
-
- // Create a new one; the other may be in a different DeclContex, (e.g.
- // this one may be in a LinkageSpecDecl while the other is not) which
- // will break invariants.
- // We will not add it to scope chains to ignore it as the warning says.
- PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName,
- ProtocolLoc, AtProtoInterfaceLoc,
- /*isForwardDecl=*/false);
-
- } else {
+ ObjCProtocolDecl *PrevDecl = LookupProtocol(ProtocolName, ProtocolLoc,
+ ForRedeclaration);
+ ObjCProtocolDecl *PDecl = 0;
+ if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : 0) {
+ // If we already have a definition, complain.
+ Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+
+ // Create a new protocol that is completely distinct from previous
+ // declarations, and do not make this protocol available for name lookup.
+ // That way, we'll end up completely ignoring the duplicate.
+ // FIXME: Can we turn this into an error?
+ PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName,
+ ProtocolLoc, AtProtoInterfaceLoc,
+ /*PrevDecl=*/0);
+ PDecl->startDefinition();
+ } else {
+ if (PrevDecl) {
+ // Check for circular dependencies among protocol declarations. This can
+ // only happen if this protocol was forward-declared.
ObjCList<ObjCProtocolDecl> PList;
PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
err = CheckForwardProtocolDeclarationForCircularDependency(
- ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
-
- // Make sure the cached decl gets a valid start location.
- PDecl->setAtStartLoc(AtProtoInterfaceLoc);
- PDecl->setLocation(ProtocolLoc);
- // Since this ObjCProtocolDecl was created by a forward declaration,
- // we now add it to the DeclContext since it wasn't added before
- PDecl->setLexicalDeclContext(CurContext);
- CurContext->addDecl(PDecl);
- PDecl->completedForwardDecl();
+ ProtocolName, ProtocolLoc, PrevDecl->getLocation(), PList);
}
- } else {
+
+ // Create the new declaration.
PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName,
ProtocolLoc, AtProtoInterfaceLoc,
- /*isForwardDecl=*/false);
+ /*PrevDecl=*/PrevDecl);
+
PushOnScopeChains(PDecl, TUScope);
+ PDecl->startDefinition();
}
+
if (AttrList)
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
+
+ // Merge attributes from previous declarations.
+ if (PrevDecl)
+ mergeDeclAttributes(PDecl, PrevDecl);
+
if (!err && NumProtoRefs ) {
/// Check then save referenced protocols.
PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
- PDecl->setLocEnd(EndProtoLoc);
}
CheckObjCDeclScope(PDecl);
@@ -626,9 +652,10 @@
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
ProtocolId[i].second);
if (!PDecl) {
+ DeclFilterCCC<ObjCProtocolDecl> Validator;
TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
- LookupObjCProtocolName, TUScope, NULL, NULL, false, CTC_NoKeywords);
+ LookupObjCProtocolName, TUScope, NULL, &Validator);
if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) {
Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
<< ProtocolId[i].first << Corrected.getCorrection();
@@ -647,7 +674,7 @@
// If this is a forward declaration and we are supposed to warn in this
// case, do it.
- if (WarnOnDeclarations && PDecl->isForwardDecl())
+ if (WarnOnDeclarations && !PDecl->hasDefinition())
Diag(ProtocolId[i].second, diag::warn_undef_protocolref)
<< ProtocolId[i].first;
Protocols.push_back(PDecl);
@@ -684,43 +711,34 @@
}
/// ActOnForwardProtocolDeclaration - Handle @protocol foo;
-Decl *
+Sema::DeclGroupPtrTy
Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
const IdentifierLocPair *IdentList,
unsigned NumElts,
AttributeList *attrList) {
- SmallVector<ObjCProtocolDecl*, 32> Protocols;
- SmallVector<SourceLocation, 8> ProtoLocs;
-
+ SmallVector<Decl *, 8> DeclsInGroup;
for (unsigned i = 0; i != NumElts; ++i) {
IdentifierInfo *Ident = IdentList[i].first;
- ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second);
- bool isNew = false;
- if (PDecl == 0) { // Not already seen?
- PDecl = ObjCProtocolDecl::Create(Context, CurContext, Ident,
- IdentList[i].second, AtProtocolLoc,
- /*isForwardDecl=*/true);
- PushOnScopeChains(PDecl, TUScope, false);
- isNew = true;
- }
- if (attrList) {
+ ObjCProtocolDecl *PrevDecl = LookupProtocol(Ident, IdentList[i].second,
+ ForRedeclaration);
+ ObjCProtocolDecl *PDecl
+ = ObjCProtocolDecl::Create(Context, CurContext, Ident,
+ IdentList[i].second, AtProtocolLoc,
+ PrevDecl);
+
+ PushOnScopeChains(PDecl, TUScope);
+ CheckObjCDeclScope(PDecl);
+
+ if (attrList)
ProcessDeclAttributeList(TUScope, PDecl, attrList);
- if (!isNew) {
- if (ASTMutationListener *L = Context.getASTMutationListener())
- L->UpdatedAttributeList(PDecl);
- }
- }
- Protocols.push_back(PDecl);
- ProtoLocs.push_back(IdentList[i].second);
+
+ if (PrevDecl)
+ mergeDeclAttributes(PDecl, PrevDecl);
+
+ DeclsInGroup.push_back(PDecl);
}
- ObjCForwardProtocolDecl *PDecl =
- ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc,
- Protocols.data(), Protocols.size(),
- ProtoLocs.data());
- CurContext->addDecl(PDecl);
- CheckObjCDeclScope(PDecl);
- return PDecl;
+ return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false);
}
Decl *Sema::
@@ -872,15 +890,16 @@
} else {
// We did not find anything with the name ClassName; try to correct for
// typos in the class name.
- TypoCorrection Corrected = CorrectTypo(
+ ObjCInterfaceValidatorCCC Validator;
+ if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope,
- NULL, NULL, false, CTC_NoKeywords);
- if ((IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
+ NULL, &Validator)) {
// Suggest the (potentially) correct interface name. However, put the
// fix-it hint itself in a separate note, since changing the name in
// the warning would make the fix-it change semantics.However, don't
// provide a code-modification hint or use the typo name for recovery,
// because this is just a warning. The program may actually be correct.
+ IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
DeclarationName CorrectedName = Corrected.getCorrection();
Diag(ClassLoc, diag::warn_undef_interface_suggest)
<< ClassName << CorrectedName;
@@ -1667,9 +1686,10 @@
// Check and see if properties declared in the interface have either 1)
// an implementation or 2) there is a @synthesize/@dynamic implementation
// of the property in the @implementation.
- if (isa<ObjCInterfaceDecl>(CDecl) &&
- !(LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2))
- DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
+ if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))
+ if (!(LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2) ||
+ IDecl->isObjCRequiresPropertyDefs())
+ DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
llvm::DenseSet<Selector> ClsMap;
for (ObjCImplementationDecl::classmeth_iterator
@@ -1775,21 +1795,12 @@
= dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
ObjCInterfaceDecl *IDecl
= ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
- IdentList[i], PrevIDecl, IdentLocs[i], true);
+ IdentList[i], PrevIDecl, IdentLocs[i]);
IDecl->setAtEndRange(IdentLocs[i]);
- // Create the forward declaration. Note that we intentionally do this
- // before we add the ObjCInterfaceDecl we just created, so that the
- // rewriter sees the ObjCClassDecl first.
- // FIXME: ObjCClassDecl should probably just go away.
- ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc,
- IDecl, IdentLocs[i]);
- CurContext->addDecl(CDecl);
-
PushOnScopeChains(IDecl, TUScope);
-
- CheckObjCDeclScope(CDecl);
- DeclsInGroup.push_back(CDecl);
+ CheckObjCDeclScope(IDecl);
+ DeclsInGroup.push_back(IDecl);
}
return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false);
@@ -2506,6 +2517,9 @@
}
void searchFrom(ObjCProtocolDecl *protocol) {
+ if (!protocol->hasDefinition())
+ return;
+
// A method in a protocol declaration overrides declarations from
// referenced ("parent") protocols.
search(protocol->getReferencedProtocols());
@@ -2688,6 +2702,10 @@
// Apply the attributes to the parameter.
ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
+ if (Param->hasAttr<BlocksAttr>()) {
+ Diag(Param->getLocation(), diag::err_block_on_nonlocal);
+ Param->setInvalidDecl();
+ }
S->AddDecl(Param);
IdResolver.AddDecl(Param);
@@ -2737,8 +2755,11 @@
ObjCMethod->isInstanceMethod());
if (ObjCMethod->hasAttrs() &&
containsInvalidMethodImplAttribute(IMD, ObjCMethod->getAttrs())) {
- Diag(EndLoc, diag::warn_attribute_method_def);
- Diag(IMD->getLocation(), diag::note_method_declared_at);
+ SourceLocation MethodLoc = IMD->getLocation();
+ if (!getSourceManager().isInSystemHeader(MethodLoc)) {
+ Diag(EndLoc, diag::warn_attribute_method_def);
+ Diag(MethodLoc, diag::note_method_declared_at);
+ }
}
} else {
cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);
Modified: cfe/branches/tooling/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaExceptionSpec.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaExceptionSpec.cpp Fri Jan 20 10:14:22 2012
@@ -611,10 +611,8 @@
case AR_inaccessible: continue;
case AR_dependent:
llvm_unreachable("access check dependent for unprivileged context");
- break;
case AR_delayed:
llvm_unreachable("access check delayed in non-declaration");
- break;
}
Contained = true;
Modified: cfe/branches/tooling/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaExpr.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaExpr.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaExpr.cpp Fri Jan 20 10:14:22 2012
@@ -12,8 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/AnalysisBasedWarnings.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -38,6 +40,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/Template.h"
+#include "TreeTransform.h"
using namespace clang;
using namespace sema;
@@ -1015,7 +1018,7 @@
if (Types[i]->getType()->isDependentType()) {
IsResultDependent = true;
} else {
- // C1X 6.5.1.1p2 "The type name in a generic association shall specify a
+ // C11 6.5.1.1p2 "The type name in a generic association shall specify a
// complete object type other than a variably modified type."
unsigned D = 0;
if (Types[i]->getType()->isIncompleteType())
@@ -1032,7 +1035,7 @@
TypeErrorFound = true;
}
- // C1X 6.5.1.1p2 "No two generic associations in the same generic
+ // C11 6.5.1.1p2 "No two generic associations in the same generic
// selection shall specify compatible types."
for (unsigned j = i+1; j < NumAssocs; ++j)
if (Types[j] && !Types[j]->getType()->isDependentType() &&
@@ -1073,7 +1076,7 @@
CompatIndices.push_back(i);
}
- // C1X 6.5.1.1p2 "The controlling expression of a generic selection shall have
+ // C11 6.5.1.1p2 "The controlling expression of a generic selection shall have
// type compatible with at most one of the types named in its generic
// association list."
if (CompatIndices.size() > 1) {
@@ -1093,7 +1096,7 @@
return ExprError();
}
- // C1X 6.5.1.1p2 "If a generic selection has no default generic association,
+ // C11 6.5.1.1p2 "If a generic selection has no default generic association,
// its controlling expression shall have type compatible with exactly one of
// the types named in its generic association list."
if (DefaultIndex == -1U && CompatIndices.size() == 0) {
@@ -1105,7 +1108,7 @@
return ExprError();
}
- // C1X 6.5.1.1p3 "If a generic selection has a generic association with a
+ // C11 6.5.1.1p3 "If a generic selection has a generic association with a
// type name that is compatible with the type of the controlling expression,
// then the result expression of the generic selection is the expression
// in that generic association. Otherwise, the result expression of the
@@ -1199,16 +1202,13 @@
VarDecl *var, DeclContext *DC) {
switch (S.ExprEvalContexts.back().Context) {
case Sema::Unevaluated:
- // The argument will never be evaluated, so don't complain.
+ case Sema::ConstantEvaluated:
+ // The argument will never be evaluated at runtime, so don't complain.
return CR_NoCapture;
case Sema::PotentiallyEvaluated:
case Sema::PotentiallyEvaluatedIfUsed:
break;
-
- case Sema::PotentiallyPotentiallyEvaluated:
- // FIXME: delay these!
- break;
}
// Don't diagnose about capture if we're not actually in code right
@@ -1247,20 +1247,16 @@
/// There is a well-formed capture at a particular scope level;
/// propagate it through all the nested blocks.
static CaptureResult propagateCapture(Sema &S, unsigned ValidScopeIndex,
- const BlockDecl::Capture &Capture) {
- VarDecl *var = Capture.getVariable();
-
+ const CapturingScopeInfo::Capture &Cap) {
// Update all the inner blocks with the capture information.
for (unsigned i = ValidScopeIndex + 1, e = S.FunctionScopes.size();
i != e; ++i) {
BlockScopeInfo *innerBlock = cast<BlockScopeInfo>(S.FunctionScopes[i]);
- innerBlock->Captures.push_back(
- BlockDecl::Capture(Capture.getVariable(), Capture.isByRef(),
- /*nested*/ true, Capture.getCopyExpr()));
- innerBlock->CaptureMap[var] = innerBlock->Captures.size(); // +1
+ innerBlock->AddCapture(Cap.getVariable(), Cap.isReferenceCapture(),
+ /*nested*/ true, Cap.getCopyExpr());
}
- return Capture.isByRef() ? CR_CaptureByRef : CR_Capture;
+ return Cap.isReferenceCapture() ? CR_CaptureByRef : CR_Capture;
}
/// shouldCaptureValueReference - Determine if a reference to the
@@ -1371,9 +1367,7 @@
cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
// Build a valid capture in this scope.
- blockScope->Captures.push_back(
- BlockDecl::Capture(var, byRef, /*nested*/ false, copyExpr));
- blockScope->CaptureMap[var] = blockScope->Captures.size(); // +1
+ blockScope->AddCapture(var, byRef, /*nested*/ false, copyExpr);
// Propagate that to inner captures if necessary.
return propagateCapture(S, functionScopesIndex,
@@ -1490,7 +1484,7 @@
///
/// \return false if new lookup candidates were found
bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- CorrectTypoContext CTC,
+ CorrectionCandidateCallback &CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs) {
DeclarationName Name = R.getLookupName();
@@ -1543,6 +1537,7 @@
Diag(R.getNameLoc(), diagnostic) << Name
<< FixItHint::CreateInsertion(R.getNameLoc(), "this->");
QualType DepThisType = DepMethod->getThisType(Context);
+ CheckCXXThisCapture(R.getNameLoc());
CXXThisExpr *DepThis = new (Context) CXXThisExpr(
R.getNameLoc(), DepThisType, false);
TemplateArgumentListInfo TList;
@@ -1604,7 +1599,7 @@
// We didn't find anything, so try to correct for a typo.
TypoCorrection Corrected;
if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
- S, &SS, NULL, false, CTC))) {
+ S, &SS, &CCC))) {
std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
R.setLookupName(Corrected.getCorrection());
@@ -1819,7 +1814,8 @@
return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand,
TemplateArgs);
- if (DiagnoseEmptyLookup(S, SS, R, CTC_Unknown))
+ CorrectionCandidateCallback DefaultValidator;
+ if (DiagnoseEmptyLookup(S, SS, R, DefaultValidator))
return ExprError();
assert(!R.empty() &&
@@ -2009,6 +2005,12 @@
Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName();
}
}
+ } else if (Lookup.isSingleResult() &&
+ Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) {
+ // If accessing a stand-alone ivar in a class method, this is an error.
+ if (const ObjCIvarDecl *IV = dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl()))
+ return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method)
+ << IV->getDeclName());
}
if (Lookup.empty() && II && AllowBuiltinCreation) {
@@ -2390,13 +2392,11 @@
case Decl::type:
#include "clang/AST/DeclNodes.inc"
llvm_unreachable("invalid value decl kind");
- return ExprError();
// These shouldn't make it here.
case Decl::ObjCAtDefsField:
case Decl::ObjCIvar:
llvm_unreachable("forming non-member reference to ivar?");
- return ExprError();
// Enum constants are always r-values and never references.
// Unresolved using declarations are dependent.
@@ -2517,7 +2517,6 @@
}
llvm_unreachable("unknown capture result");
- return ExprError();
}
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
@@ -2567,16 +2566,14 @@
return ExprError();
QualType Ty;
- if (!getLangOptions().CPlusPlus)
- Ty = Context.IntTy; // 'x' and L'x' -> int in C.
- else if (Literal.isWide())
- Ty = Context.WCharTy; // L'x' -> wchar_t in C++.
+ if (Literal.isWide())
+ Ty = Context.WCharTy; // L'x' -> wchar_t in C and C++.
else if (Literal.isUTF16())
- Ty = Context.Char16Ty; // u'x' -> char16_t in C++0x.
+ Ty = Context.Char16Ty; // u'x' -> char16_t in C11 and C++11.
else if (Literal.isUTF32())
- Ty = Context.Char32Ty; // U'x' -> char32_t in C++0x.
- else if (Literal.isMultiChar())
- Ty = Context.IntTy; // 'wxyz' -> int in C++.
+ Ty = Context.Char32Ty; // U'x' -> char32_t in C11 and C++11.
+ else if (!getLangOptions().CPlusPlus || Literal.isMultiChar())
+ Ty = Context.IntTy; // 'x' -> int in C, 'wxyz' -> int in C++.
else
Ty = Context.CharTy; // 'x' -> char in C++
@@ -4064,6 +4061,11 @@
// pointers. Everything else should be possible.
QualType SrcTy = Src.get()->getType();
+ if (const AtomicType *SrcAtomicTy = SrcTy->getAs<AtomicType>())
+ SrcTy = SrcAtomicTy->getValueType();
+ if (const AtomicType *DestAtomicTy = DestTy->getAs<AtomicType>())
+ DestTy = DestAtomicTy->getValueType();
+
if (Context.hasSameUnqualifiedType(SrcTy, DestTy))
return CK_NoOp;
@@ -4083,12 +4085,10 @@
case Type::STK_ObjCObjectPointer:
if (SrcKind == Type::STK_ObjCObjectPointer)
return CK_BitCast;
- else if (SrcKind == Type::STK_CPointer)
+ if (SrcKind == Type::STK_CPointer)
return CK_CPointerToObjCPointerCast;
- else {
- maybeExtendBlockObject(*this, Src);
- return CK_BlockPointerToObjCPointerCast;
- }
+ maybeExtendBlockObject(*this, Src);
+ return CK_BlockPointerToObjCPointerCast;
case Type::STK_Bool:
return CK_PointerToBoolean;
case Type::STK_Integral:
@@ -4099,7 +4099,7 @@
case Type::STK_MemberPointer:
llvm_unreachable("illegal cast from pointer");
}
- break;
+ llvm_unreachable("Should have returned before this");
case Type::STK_Bool: // casting from bool is like casting from an integer
case Type::STK_Integral:
@@ -4130,7 +4130,7 @@
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
}
- break;
+ llvm_unreachable("Should have returned before this");
case Type::STK_Floating:
switch (DestTy->getScalarTypeKind()) {
@@ -4157,7 +4157,7 @@
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
}
- break;
+ llvm_unreachable("Should have returned before this");
case Type::STK_FloatingComplex:
switch (DestTy->getScalarTypeKind()) {
@@ -4186,7 +4186,7 @@
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
}
- break;
+ llvm_unreachable("Should have returned before this");
case Type::STK_IntegralComplex:
switch (DestTy->getScalarTypeKind()) {
@@ -4215,7 +4215,7 @@
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
}
- break;
+ llvm_unreachable("Should have returned before this");
}
llvm_unreachable("Unhandled scalar cast");
@@ -5302,7 +5302,9 @@
QualType lhptee = LHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
QualType rhptee = RHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
- if (!lhptee.isAtLeastAsQualifiedAs(rhptee))
+ if (!lhptee.isAtLeastAsQualifiedAs(rhptee) &&
+ // make an exception for id<P>
+ !LHSType->isObjCQualifiedIdType())
return Sema::CompatiblePointerDiscardsQualifiers;
if (S.Context.typesAreCompatible(LHSType, RHSType))
@@ -5354,9 +5356,6 @@
LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType();
RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType();
- // We can't do assignment from/to atomics yet.
- if (LHSType->isAtomicType())
- return Incompatible;
// Common case: no conversion required.
if (LHSType == RHSType) {
@@ -5364,6 +5363,21 @@
return Compatible;
}
+ if (const AtomicType *AtomicTy = dyn_cast<AtomicType>(LHSType)) {
+ if (AtomicTy->getValueType() == RHSType) {
+ Kind = CK_NonAtomicToAtomic;
+ return Compatible;
+ }
+ }
+
+ if (const AtomicType *AtomicTy = dyn_cast<AtomicType>(RHSType)) {
+ if (AtomicTy->getValueType() == LHSType) {
+ Kind = CK_AtomicToNonAtomic;
+ return Compatible;
+ }
+ }
+
+
// If the left-hand side is a reference type, then we are in a
// (rare!) case where we've allowed the use of references in C,
// e.g., as a parameter type in a built-in function. In this case,
@@ -5902,9 +5916,15 @@
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
+
if (!LHS.get()->getType()->isArithmeticType() ||
- !RHS.get()->getType()->isArithmeticType())
+ !RHS.get()->getType()->isArithmeticType()) {
+ if (IsCompAssign &&
+ LHS.get()->getType()->isAtomicType() &&
+ RHS.get()->getType()->isArithmeticType())
+ return compType;
return InvalidOperands(Loc, LHS, RHS);
+ }
// Check for division by zero.
if (IsDiv &&
@@ -6130,6 +6150,12 @@
return compType;
}
+ if (LHS.get()->getType()->isAtomicType() &&
+ RHS.get()->getType()->isArithmeticType()) {
+ *CompLHSTy = LHS.get()->getType();
+ return compType;
+ }
+
// Put any potential pointer into PExp
Expr* PExp = LHS.get(), *IExp = RHS.get();
if (IExp->getType()->isAnyPointerType())
@@ -6190,6 +6216,12 @@
return compType;
}
+ if (LHS.get()->getType()->isAtomicType() &&
+ RHS.get()->getType()->isArithmeticType()) {
+ *CompLHSTy = LHS.get()->getType();
+ return compType;
+ }
+
// Either ptr - int or ptr - ptr.
if (LHS.get()->getType()->isAnyPointerType()) {
QualType lpointee = LHS.get()->getType()->getPointeeType();
@@ -6843,6 +6875,26 @@
return InvalidOperands(Loc, LHS, RHS);
}
+
+// Return a signed type that is of identical size and number of elements.
+// For floating point vectors, return an integer type of identical size
+// and number of elements.
+QualType Sema::GetSignedVectorType(QualType V) {
+ const VectorType *VTy = V->getAs<VectorType>();
+ unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
+ if (TypeSize == Context.getTypeSize(Context.CharTy))
+ return Context.getExtVectorType(Context.CharTy, VTy->getNumElements());
+ else if (TypeSize == Context.getTypeSize(Context.ShortTy))
+ return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements());
+ else if (TypeSize == Context.getTypeSize(Context.IntTy))
+ return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
+ else if (TypeSize == Context.getTypeSize(Context.LongTy))
+ return Context.getExtVectorType(Context.LongTy, VTy->getNumElements());
+ assert(TypeSize == Context.getTypeSize(Context.LongLongTy) &&
+ "Unhandled vector element size in vector compare");
+ return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
+}
+
/// CheckVectorCompareOperands - vector comparisons are a clang extension that
/// operates on extended vector types. Instead of producing an IntTy result,
/// like a scalar comparison, a vector comparison produces a vector of integer
@@ -6857,7 +6909,6 @@
return vType;
QualType LHSType = LHS.get()->getType();
- QualType RHSType = RHS.get()->getType();
// If AltiVec, the comparison results in a numeric type, i.e.
// bool for C++, int for C
@@ -6882,26 +6933,23 @@
// Check for comparisons of floating point operands using != and ==.
if (!IsRelational && LHSType->hasFloatingRepresentation()) {
- assert (RHSType->hasFloatingRepresentation());
+ assert (RHS.get()->getType()->hasFloatingRepresentation());
CheckFloatComparison(Loc, LHS.get(), RHS.get());
}
+
+ // Return a signed type for the vector.
+ return GetSignedVectorType(LHSType);
+}
- // Return a signed type that is of identical size and number of elements.
- // For floating point vectors, return an integer type of identical size
- // and number of elements.
- const VectorType *VTy = LHSType->getAs<VectorType>();
- unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
- if (TypeSize == Context.getTypeSize(Context.CharTy))
- return Context.getExtVectorType(Context.CharTy, VTy->getNumElements());
- else if (TypeSize == Context.getTypeSize(Context.ShortTy))
- return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements());
- else if (TypeSize == Context.getTypeSize(Context.IntTy))
- return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
- else if (TypeSize == Context.getTypeSize(Context.LongTy))
- return Context.getExtVectorType(Context.LongTy, VTy->getNumElements());
- assert(TypeSize == Context.getTypeSize(Context.LongLongTy) &&
- "Unhandled vector element size in vector compare");
- return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
+QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc) {
+ // Ensure that either both operands are of the same vector type, or
+ // one operand is of a vector type and the other is of its element type.
+ QualType vType = CheckVectorOperands(LHS, RHS, Loc, false);
+ if (vType.isNull() || vType->isFloatingType())
+ return InvalidOperands(Loc, LHS, RHS);
+
+ return GetSignedVectorType(LHS.get()->getType());
}
inline QualType Sema::CheckBitwiseOperands(
@@ -6934,6 +6982,10 @@
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc) {
+ // Check vector operands differently.
+ if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType())
+ return CheckVectorLogicalOperands(LHS, RHS, Loc);
+
// Diagnose cases where the user write a logical and/or but probably meant a
// bitwise one. We do this when the LHS is a non-bool integer and the RHS
// is a constant.
@@ -7141,7 +7193,6 @@
case Expr::MLV_ReadonlyProperty:
case Expr::MLV_NoSetterProperty:
llvm_unreachable("readonly properties should be processed differently");
- break;
case Expr::MLV_InvalidMessageExpression:
Diag = diag::error_readonly_message_assignment;
break;
@@ -7287,6 +7338,12 @@
return S.Context.DependentTy;
QualType ResType = Op->getType();
+ // Atomic types can be used for increment / decrement where the non-atomic
+ // versions can, so ignore the _Atomic() specifier for the purpose of
+ // checking.
+ if (const AtomicType *ResAtomicType = ResType->getAs<AtomicType>())
+ ResType = ResAtomicType->getValueType();
+
assert(!ResType.isNull() && "no type for increment/decrement expression");
if (S.getLangOptions().CPlusPlus && ResType->isBooleanType()) {
@@ -8099,6 +8156,9 @@
if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())
return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
+ if (LHSExpr->getType()->isOverloadableType())
+ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
+
return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
}
@@ -8217,6 +8277,10 @@
Input = ImpCastExprToType(Input.take(), Context.BoolTy,
ScalarTypeToBooleanCastKind(resultType));
}
+ } else if (resultType->isExtVectorType()) {
+ // Vector logical not returns the signed variant of the operand type.
+ resultType = GetSignedVectorType(resultType);
+ break;
} else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -8799,12 +8863,6 @@
// Finally we can process decl attributes.
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
- if (!isVariadic && CurBlock->TheDecl->getAttr<SentinelAttr>()) {
- Diag(ParamInfo.getAttributes()->getLoc(),
- diag::warn_attribute_sentinel_not_variadic) << 1;
- // FIXME: remove the attribute.
- }
-
// Put the parameter variables in scope. We can bail out immediately
// if we don't have any.
if (Params.empty())
@@ -8832,7 +8890,7 @@
// Pop off CurBlock, handle nested blocks.
PopDeclContext();
- PopFunctionOrBlockScope();
+ PopFunctionScopeInfo();
}
/// ActOnBlockStmtExpr - This is called when the body of a block statement
@@ -8859,8 +8917,18 @@
QualType BlockTy;
// Set the captured variables on the block.
- BSI->TheDecl->setCaptures(Context, BSI->Captures.begin(), BSI->Captures.end(),
- BSI->CapturesCXXThis);
+ // FIXME: Share capture structure between BlockDecl and CapturingScopeInfo!
+ SmallVector<BlockDecl::Capture, 4> Captures;
+ for (unsigned i = 0, e = BSI->Captures.size(); i != e; i++) {
+ CapturingScopeInfo::Capture &Cap = BSI->Captures[i];
+ if (Cap.isThisCapture())
+ continue;
+ BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isReferenceCapture(),
+ Cap.isNested(), Cap.getCopyExpr());
+ Captures.push_back(NewCap);
+ }
+ BSI->TheDecl->setCaptures(Context, Captures.begin(), Captures.end(),
+ BSI->CXXThisCaptureIndex != 0);
// If the user wrote a function type in some form, try to use that.
if (!BSI->FunctionType.isNull()) {
@@ -8924,7 +8992,7 @@
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
- PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result);
+ PopFunctionScopeInfo(&WP, Result->getBlockDecl(), Result);
// If the block isn't obviously global, i.e. it captures anything at
// all, mark this full-expression as needing a cleanup.
@@ -9087,7 +9155,6 @@
bool MayHaveFunctionDiff = false;
switch (ConvTy) {
- default: llvm_unreachable("Unknown conversion type");
case Compatible: return false;
case PointerToInt:
DiagKind = diag::ext_typecheck_convert_pointer_int;
@@ -9204,9 +9271,8 @@
// If we can fix the conversion, suggest the FixIts.
assert(ConvHints.isNull() || Hint.isNull());
if (!ConvHints.isNull()) {
- for (llvm::SmallVector<FixItHint, 1>::iterator
- HI = ConvHints.Hints.begin(), HE = ConvHints.Hints.end();
- HI != HE; ++HI)
+ for (std::vector<FixItHint>::iterator HI = ConvHints.Hints.begin(),
+ HE = ConvHints.Hints.end(); HI != HE; ++HI)
FDiag << *HI;
} else {
FDiag << Hint;
@@ -9261,8 +9327,11 @@
}
if (!Folded || !AllowFold) {
- Diag(E->getSourceRange().getBegin(),
- DiagID ? DiagID : diag::err_expr_not_ice) << E->getSourceRange();
+ if (DiagID)
+ Diag(E->getSourceRange().getBegin(), DiagID) << E->getSourceRange();
+ else
+ Diag(E->getSourceRange().getBegin(), diag::err_expr_not_ice)
+ << E->getSourceRange() << LangOpts.CPlusPlus;
// We only show the notes if they're not the usual "invalid subexpression"
// or if they are actually in a subexpression.
@@ -9277,18 +9346,63 @@
}
Diag(E->getSourceRange().getBegin(), diag::ext_expr_not_ice)
- << E->getSourceRange();
-
- if (Diags.getDiagnosticLevel(diag::ext_expr_not_ice, E->getExprLoc())
- != DiagnosticsEngine::Ignored)
- for (unsigned I = 0, N = Notes.size(); I != N; ++I)
- Diag(Notes[I].first, Notes[I].second);
+ << E->getSourceRange() << LangOpts.CPlusPlus;
+ for (unsigned I = 0, N = Notes.size(); I != N; ++I)
+ Diag(Notes[I].first, Notes[I].second);
if (Result)
*Result = EvalResult.Val.getInt();
return false;
}
+namespace {
+ // Handle the case where we conclude a expression which we speculatively
+ // considered to be unevaluated is actually evaluated.
+ class TransformToPE : public TreeTransform<TransformToPE> {
+ typedef TreeTransform<TransformToPE> BaseTransform;
+
+ public:
+ TransformToPE(Sema &SemaRef) : BaseTransform(SemaRef) { }
+
+ // Make sure we redo semantic analysis
+ bool AlwaysRebuild() { return true; }
+
+ // We need to special-case DeclRefExprs referring to FieldDecls which
+ // are not part of a member pointer formation; normal TreeTransforming
+ // doesn't catch this case because of the way we represent them in the AST.
+ // FIXME: This is a bit ugly; is it really the best way to handle this
+ // case?
+ //
+ // Error on DeclRefExprs referring to FieldDecls.
+ ExprResult TransformDeclRefExpr(DeclRefExpr *E) {
+ if (isa<FieldDecl>(E->getDecl()) &&
+ SemaRef.ExprEvalContexts.back().Context != Sema::Unevaluated)
+ return SemaRef.Diag(E->getLocation(),
+ diag::err_invalid_non_static_member_use)
+ << E->getDecl() << E->getSourceRange();
+
+ return BaseTransform::TransformDeclRefExpr(E);
+ }
+
+ // Exception: filter out member pointer formation
+ ExprResult TransformUnaryOperator(UnaryOperator *E) {
+ if (E->getOpcode() == UO_AddrOf && E->getType()->isMemberPointerType())
+ return E;
+
+ return BaseTransform::TransformUnaryOperator(E);
+ }
+
+ };
+}
+
+ExprResult Sema::TranformToPotentiallyEvaluated(Expr *E) {
+ ExprEvalContexts.back().Context =
+ ExprEvalContexts[ExprEvalContexts.size()-2].Context;
+ if (ExprEvalContexts.back().Context == Unevaluated)
+ return E;
+ return TransformToPE(*this).TransformExpr(E);
+}
+
void
Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
ExprEvalContexts.push_back(
@@ -9303,33 +9417,11 @@
ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back();
ExprEvalContexts.pop_back();
- if (Rec.Context == PotentiallyPotentiallyEvaluated) {
- if (Rec.PotentiallyReferenced) {
- // Mark any remaining declarations in the current position of the stack
- // as "referenced". If they were not meant to be referenced, semantic
- // analysis would have eliminated them (e.g., in ActOnCXXTypeId).
- for (PotentiallyReferencedDecls::iterator
- I = Rec.PotentiallyReferenced->begin(),
- IEnd = Rec.PotentiallyReferenced->end();
- I != IEnd; ++I)
- MarkDeclarationReferenced(I->first, I->second);
- }
-
- if (Rec.PotentiallyDiagnosed) {
- // Emit any pending diagnostics.
- for (PotentiallyEmittedDiagnostics::iterator
- I = Rec.PotentiallyDiagnosed->begin(),
- IEnd = Rec.PotentiallyDiagnosed->end();
- I != IEnd; ++I)
- Diag(I->first, I->second);
- }
- }
-
// When are coming out of an unevaluated context, clear out any
// temporaries that we may have created as part of the evaluation of
// the expression in that context: they aren't relevant because they
// will never be constructed.
- if (Rec.Context == Unevaluated) {
+ if (Rec.Context == Unevaluated || Rec.Context == ConstantEvaluated) {
ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects,
ExprCleanupObjects.end());
ExprNeedsCleanups = Rec.ParentNeedsCleanups;
@@ -9338,9 +9430,6 @@
} else {
ExprNeedsCleanups |= Rec.ParentNeedsCleanups;
}
-
- // Destroy the popped expression evaluation record.
- Rec.Destroy();
}
void Sema::DiscardCleanupsInEvaluationContext() {
@@ -9368,16 +9457,6 @@
if (D->isUsed(false))
return;
- // Mark a parameter or variable declaration "used", regardless of whether
- // we're in a template or not. The reason for this is that unevaluated
- // expressions (e.g. (void)sizeof()) constitute a use for warning purposes
- // (-Wunused-variables and -Wunused-parameters)
- if (isa<ParmVarDecl>(D) ||
- (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) {
- D->setUsed();
- return;
- }
-
if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D))
return;
@@ -9391,18 +9470,21 @@
// We are in an expression that is not potentially evaluated; do nothing.
return;
+ case ConstantEvaluated:
+ // We are in an expression that will be evaluated during translation; in
+ // C++11, we need to define any functions which are used in case they're
+ // constexpr, whereas in C++98, we only need to define static data members
+ // of class templates.
+ if (!getLangOptions().CPlusPlus ||
+ (!getLangOptions().CPlusPlus0x && !isa<VarDecl>(D)))
+ return;
+ break;
+
case PotentiallyEvaluated:
// We are in a potentially-evaluated expression, so this declaration is
// "used"; handle this below.
break;
- case PotentiallyPotentiallyEvaluated:
- // We are in an expression that may be potentially evaluated; queue this
- // declaration reference until we know whether the expression is
- // potentially evaluated.
- ExprEvalContexts.back().addReferencedDecl(Loc, D);
- return;
-
case PotentiallyEvaluatedIfUsed:
// Referenced declarations will only be used if the construct in the
// containing expression is used.
@@ -9473,6 +9555,11 @@
cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass())
PendingLocalImplicitInstantiations.push_back(std::make_pair(Function,
Loc));
+ else if (Function->getTemplateInstantiationPattern()->isConstexpr())
+ // Do not defer instantiations of constexpr functions, to avoid the
+ // expression evaluator needing to call back into Sema if it sees a
+ // call to such a function.
+ InstantiateFunctionDefinition(Loc, Function);
else
PendingInstantiations.push_back(std::make_pair(Function, Loc));
}
@@ -9508,7 +9595,12 @@
// This is a modification of an existing AST node. Notify listeners.
if (ASTMutationListener *L = getASTMutationListener())
L->StaticDataMemberInstantiated(Var);
- PendingInstantiations.push_back(std::make_pair(Var, Loc));
+ if (Var->isUsableInConstantExpressions())
+ // Do not defer instantiations of variables which could be used in a
+ // constant expression.
+ InstantiateStaticDataMemberDefinition(Loc, Var);
+ else
+ PendingInstantiations.push_back(std::make_pair(Var, Loc));
}
}
@@ -9662,6 +9754,10 @@
// The argument will never be evaluated, so don't complain.
break;
+ case ConstantEvaluated:
+ // Relevant diagnostics should be produced by constant evaluation.
+ break;
+
case PotentiallyEvaluated:
case PotentiallyEvaluatedIfUsed:
if (Statement && getCurFunctionOrMethodDecl()) {
@@ -9672,10 +9768,6 @@
Diag(Loc, PD);
return true;
-
- case PotentiallyPotentiallyEvaluated:
- ExprEvalContexts.back().addDiagnostic(Loc, PD);
- break;
}
return false;
@@ -9836,7 +9928,6 @@
ExprResult VisitStmt(Stmt *S) {
llvm_unreachable("unexpected statement!");
- return ExprError();
}
ExprResult VisitExpr(Expr *E) {
@@ -9929,7 +10020,6 @@
ExprResult VisitStmt(Stmt *S) {
llvm_unreachable("unexpected statement!");
- return ExprError();
}
ExprResult VisitExpr(Expr *E) {
Modified: cfe/branches/tooling/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaExprCXX.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaExprCXX.cpp Fri Jan 20 10:14:22 2012
@@ -310,7 +310,6 @@
SourceLocation TypeidLoc,
Expr *E,
SourceLocation RParenLoc) {
- bool isUnevaluatedOperand = true;
if (E && !E->isTypeDependent()) {
if (E->getType()->isPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
@@ -332,7 +331,11 @@
// polymorphic class type [...] [the] expression is an unevaluated
// operand. [...]
if (RecordD->isPolymorphic() && E->Classify(Context).isGLValue()) {
- isUnevaluatedOperand = false;
+ // The subexpression is potentially evaluated; switch the context
+ // and recheck the subexpression.
+ ExprResult Result = TranformToPotentiallyEvaluated(E);
+ if (Result.isInvalid()) return ExprError();
+ E = Result.take();
// We require a vtable to query the type at run time.
MarkVTableUsed(TypeidLoc, RecordD);
@@ -352,12 +355,6 @@
}
}
- // If this is an unevaluated operand, clear out the set of
- // declaration references we have been computing and eliminate any
- // temporaries introduced in its computation.
- if (isUnevaluatedOperand)
- ExprEvalContexts.back().Context = Unevaluated;
-
return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(),
E,
SourceRange(TypeidLoc, RParenLoc)));
@@ -653,22 +650,8 @@
return Owned(E);
}
-QualType Sema::getCurrentThisType(bool Capture) {
- // Ignore block scopes: we can capture through them.
- // Ignore nested enum scopes: we'll diagnose non-constant expressions
- // where they're invalid, and other uses are legitimate.
- // Don't ignore nested class scopes: you can't use 'this' in a local class.
- DeclContext *DC = CurContext;
- unsigned NumBlocks = 0;
- while (true) {
- if (isa<BlockDecl>(DC)) {
- DC = cast<BlockDecl>(DC)->getDeclContext();
- ++NumBlocks;
- } else if (isa<EnumDecl>(DC))
- DC = cast<EnumDecl>(DC)->getDeclContext();
- else break;
- }
-
+QualType Sema::getCurrentThisType() {
+ DeclContext *DC = getFunctionLevelDeclContext();
QualType ThisTy;
if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) {
if (method && method->isInstance())
@@ -683,17 +666,49 @@
ThisTy = Context.getPointerType(Context.getRecordType(RD));
}
- if (!Capture || ThisTy.isNull())
- return ThisTy;
-
- // Mark that we're closing on 'this' in all the block scopes we ignored.
- for (unsigned idx = FunctionScopes.size() - 1;
- NumBlocks; --idx, --NumBlocks)
- cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
-
return ThisTy;
}
+void Sema::CheckCXXThisCapture(SourceLocation Loc) {
+ // We don't need to capture this in an unevaluated context.
+ if (ExprEvalContexts.back().Context == Unevaluated)
+ return;
+
+ // Otherwise, check that we can capture 'this'.
+ unsigned NumClosures = 0;
+ for (unsigned idx = FunctionScopes.size() - 1; idx != 0; idx--) {
+ if (CapturingScopeInfo *CSI =
+ dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) {
+ if (CSI->CXXThisCaptureIndex != 0) {
+ // 'this' is already being captured; there isn't anything more to do.
+ break;
+ }
+ if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
+ CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block) {
+ // This closure can implicitly capture 'this'; continue looking upwards.
+ // FIXME: Is this check correct? The rules in the standard are a bit
+ // unclear.
+ NumClosures++;
+ continue;
+ }
+ // This context can't implicitly capture 'this'; fail out.
+ Diag(Loc, diag::err_implicit_this_capture);
+ return;
+ }
+ break;
+ }
+
+ // Mark that we're implicitly capturing 'this' in all the scopes we skipped.
+ // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated
+ // contexts.
+ for (unsigned idx = FunctionScopes.size() - 1;
+ NumClosures; --idx, --NumClosures) {
+ CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);
+ bool isNested = NumClosures > 1;
+ CSI->AddThisCapture(isNested);
+ }
+}
+
ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
/// is a non-lvalue expression whose value is the address of the object for
@@ -702,6 +717,7 @@
QualType ThisTy = getCurrentThisType();
if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use);
+ CheckCXXThisCapture(Loc);
return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false));
}
@@ -977,10 +993,13 @@
// C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
// or enumeration type with a non-negative value."
if (ArraySize && !ArraySize->isTypeDependent()) {
+ // Eliminate placeholders.
+ ExprResult ConvertedSize = CheckPlaceholderExpr(ArraySize);
+ if (ConvertedSize.isInvalid())
+ return ExprError();
+ ArraySize = ConvertedSize.take();
- QualType SizeType = ArraySize->getType();
-
- ExprResult ConvertedSize = ConvertToIntegralOrEnumerationType(
+ ConvertedSize = ConvertToIntegralOrEnumerationType(
StartLoc, ArraySize,
PDiag(diag::err_array_size_not_integral),
PDiag(diag::err_array_size_incomplete_type)
@@ -996,7 +1015,7 @@
return ExprError();
ArraySize = ConvertedSize.take();
- SizeType = ArraySize->getType();
+ QualType SizeType = ArraySize->getType();
if (!SizeType->isIntegralOrUnscopedEnumerationType())
return ExprError();
@@ -2014,6 +2033,9 @@
ConditionVar->getLocation(),
ConditionVar->getType().getNonReferenceType(),
VK_LValue));
+
+ MarkDeclarationReferenced(ConditionVar->getLocation(), ConditionVar);
+
if (ConvertToBoolean) {
Condition = CheckBooleanCondition(Condition.take(), StmtLoc);
if (Condition.isInvalid())
@@ -4265,21 +4287,26 @@
}
}
- if (BaseType->isPointerType())
+ if (BaseType->isPointerType() || BaseType->isObjCObjectPointerType())
BaseType = BaseType->getPointeeType();
}
- // We could end up with various non-record types here, such as extended
- // vector types or Objective-C interfaces. Just return early and let
- // ActOnMemberReferenceExpr do the work.
- if (!BaseType->isRecordType()) {
- // C++ [basic.lookup.classref]p2:
- // [...] If the type of the object expression is of pointer to scalar
- // type, the unqualified-id is looked up in the context of the complete
- // postfix-expression.
- //
- // This also indicates that we should be parsing a
- // pseudo-destructor-name.
+ // Objective-C properties allow "." access on Objective-C pointer types,
+ // so adjust the base type to the object type itself.
+ if (BaseType->isObjCObjectPointerType())
+ BaseType = BaseType->getPointeeType();
+
+ // C++ [basic.lookup.classref]p2:
+ // [...] If the type of the object expression is of pointer to scalar
+ // type, the unqualified-id is looked up in the context of the complete
+ // postfix-expression.
+ //
+ // This also indicates that we could be parsing a pseudo-destructor-name.
+ // Note that Objective-C class and object types can be pseudo-destructor
+ // expressions or normal member (ivar or property) access expressions.
+ if (BaseType->isObjCObjectOrInterfaceType()) {
+ MayBePseudoDestructor = true;
+ } else if (!BaseType->isRecordType()) {
ObjectType = ParsedType();
MayBePseudoDestructor = true;
return Owned(Base);
@@ -4749,8 +4776,8 @@
case LookupResult::NotFoundInCurrentInstantiation:
return IER_Dependent;
}
-
- return IER_DoesNotExist;
+
+ llvm_unreachable("Invalid LookupResult Kind!");
}
Sema::IfExistsResult
@@ -4774,3 +4801,217 @@
return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);
}
+//===----------------------------------------------------------------------===//
+// Lambdas.
+//===----------------------------------------------------------------------===//
+
+void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
+ Declarator &ParamInfo,
+ Scope *CurScope) {
+ DeclContext *DC = CurContext;
+ while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
+ DC = DC->getParent();
+
+ // Start constructing the lambda class.
+ CXXRecordDecl *Class = CXXRecordDecl::Create(Context, TTK_Class, DC,
+ Intro.Range.getBegin(),
+ /*IdLoc=*/SourceLocation(),
+ /*Id=*/0);
+ Class->startDefinition();
+ Class->setLambda(true);
+ CurContext->addDecl(Class);
+
+ QualType ThisCaptureType;
+ llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
+ unsigned CXXThisCaptureIndex = 0;
+ llvm::SmallVector<LambdaScopeInfo::Capture, 4> Captures;
+ for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
+ C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; ++C) {
+ if (C->Kind == LCK_This) {
+ if (!ThisCaptureType.isNull()) {
+ Diag(C->Loc, diag::err_capture_more_than_once) << "'this'";
+ continue;
+ }
+
+ if (Intro.Default == LCD_ByCopy) {
+ Diag(C->Loc, diag::err_this_capture_with_copy_default);
+ continue;
+ }
+
+ ThisCaptureType = getCurrentThisType();
+ if (ThisCaptureType.isNull()) {
+ Diag(C->Loc, diag::err_invalid_this_use);
+ continue;
+ }
+ CheckCXXThisCapture(C->Loc);
+
+ // FIXME: Need getCurCapture().
+ bool isNested = getCurBlock() || getCurLambda();
+ CapturingScopeInfo::Capture Cap(CapturingScopeInfo::Capture::ThisCapture,
+ isNested);
+ Captures.push_back(Cap);
+ CXXThisCaptureIndex = Captures.size();
+ continue;
+ }
+
+ assert(C->Id && "missing identifier for capture");
+
+ if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
+ Diag(C->Loc, diag::err_reference_capture_with_reference_default);
+ continue;
+ } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
+ Diag(C->Loc, diag::err_copy_capture_with_copy_default);
+ continue;
+ }
+
+ DeclarationNameInfo Name(C->Id, C->Loc);
+ LookupResult R(*this, Name, LookupOrdinaryName);
+ CXXScopeSpec ScopeSpec;
+ LookupParsedName(R, CurScope, &ScopeSpec);
+ if (R.isAmbiguous())
+ continue;
+ if (R.empty()) {
+ DeclFilterCCC<VarDecl> Validator;
+ if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator))
+ continue;
+ }
+
+ VarDecl *Var = R.getAsSingle<VarDecl>();
+ if (!Var) {
+ Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
+ continue;
+ }
+
+ if (CaptureMap.count(Var)) {
+ Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
+ continue;
+ }
+
+ if (!Var->hasLocalStorage()) {
+ Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
+ continue;
+ }
+
+ // FIXME: This is completely wrong for nested captures and variables
+ // with a non-trivial constructor.
+ // FIXME: We should refuse to capture __block variables.
+ Captures.push_back(LambdaScopeInfo::Capture(Var, C->Kind == LCK_ByRef,
+ /*isNested*/false, 0));
+ CaptureMap[Var] = Captures.size();
+ }
+
+ // Build the call operator; we don't really have all the relevant information
+ // at this point, but we need something to attach child declarations to.
+ QualType MethodTy;
+ TypeSourceInfo *MethodTyInfo;
+ if (ParamInfo.getNumTypeObjects() == 0) {
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.TypeQuals |= DeclSpec::TQ_const;
+ MethodTy = Context.getFunctionType(Context.DependentTy,
+ /*Args=*/0, /*NumArgs=*/0, EPI);
+ MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
+ } else {
+ assert(ParamInfo.isFunctionDeclarator() &&
+ "lambda-declarator is a function");
+ DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
+ if (!FTI.hasMutableQualifier())
+ FTI.TypeQuals |= DeclSpec::TQ_const;
+ MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
+ // FIXME: Can these asserts actually fail?
+ assert(MethodTyInfo && "no type from lambda-declarator");
+ MethodTy = MethodTyInfo->getType();
+ assert(!MethodTy.isNull() && "no type from lambda declarator");
+ }
+
+ DeclarationName MethodName
+ = Context.DeclarationNames.getCXXOperatorName(OO_Call);
+ CXXMethodDecl *Method
+ = CXXMethodDecl::Create(Context,
+ Class,
+ ParamInfo.getSourceRange().getEnd(),
+ DeclarationNameInfo(MethodName,
+ /*NameLoc=*/SourceLocation()),
+ MethodTy,
+ MethodTyInfo,
+ /*isStatic=*/false,
+ SC_None,
+ /*isInline=*/true,
+ /*isConstExpr=*/false,
+ ParamInfo.getSourceRange().getEnd());
+ Method->setAccess(AS_public);
+ Class->addDecl(Method);
+ Method->setLexicalDeclContext(DC); // FIXME: Is this really correct?
+
+ ProcessDeclAttributes(CurScope, Method, ParamInfo);
+
+ // Enter a new evaluation context to insulate the block from any
+ // cleanups from the enclosing full-expression.
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
+
+ PushDeclContext(CurScope, Method);
+
+ // Set the parameters on the decl, if specified.
+ if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
+ FunctionProtoTypeLoc Proto =
+ cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc());
+ Method->setParams(Proto.getParams());
+ CheckParmsForFunctionDef(Method->param_begin(),
+ Method->param_end(),
+ /*CheckParameterNames=*/false);
+
+ // Introduce our parameters into the function scope
+ for (unsigned p = 0, NumParams = Method->getNumParams(); p < NumParams; ++p) {
+ ParmVarDecl *Param = Method->getParamDecl(p);
+ Param->setOwningFunction(Method);
+
+ // If this has an identifier, add it to the scope stack.
+ if (Param->getIdentifier()) {
+ CheckShadow(CurScope, Param);
+
+ PushOnScopeChains(Param, CurScope);
+ }
+ }
+ }
+
+ // Introduce the lambda scope.
+ PushLambdaScope(Class);
+
+ LambdaScopeInfo *LSI = getCurLambda();
+ LSI->CXXThisCaptureIndex = CXXThisCaptureIndex;
+ std::swap(LSI->CaptureMap, CaptureMap);
+ std::swap(LSI->Captures, Captures);
+ LSI->NumExplicitCaptures = Captures.size();
+ if (Intro.Default == LCD_ByCopy)
+ LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
+ else if (Intro.Default == LCD_ByRef)
+ LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
+
+ const FunctionType *Fn = MethodTy->getAs<FunctionType>();
+ QualType RetTy = Fn->getResultType();
+ if (RetTy != Context.DependentTy) {
+ LSI->ReturnType = RetTy;
+ } else {
+ LSI->HasImplicitReturnType = true;
+ }
+
+ // FIXME: Check return type is complete, !isObjCObjectType
+
+}
+
+void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) {
+ // Leave the expression-evaluation context.
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
+
+ // Leave the context of the lambda.
+ PopDeclContext();
+ PopFunctionScopeInfo();
+}
+
+ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
+ Stmt *Body, Scope *CurScope) {
+ // FIXME: Implement
+ Diag(StartLoc, diag::err_lambda_unsupported);
+ ActOnLambdaError(StartLoc, CurScope);
+ return ExprError();
+}
Modified: cfe/branches/tooling/lib/Sema/SemaExprMember.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaExprMember.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaExprMember.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaExprMember.cpp Fri Jan 20 10:14:22 2012
@@ -56,7 +56,7 @@
/// The reference may be an implicit instance member access.
IMA_Mixed,
- /// The reference may be to an instance member, but it is invalid if
+ /// The reference may be to an instance member, but it might be invalid if
/// so, because the context is not an instance method.
IMA_Mixed_StaticContext,
@@ -74,6 +74,11 @@
/// context is not an instance method.
IMA_Unresolved_StaticContext,
+ // The reference refers to a field which is not a member of the containing
+ // class, which is allowed because we're in C++11 mode and the context is
+ // unevaluated.
+ IMA_Field_Uneval_Context,
+
/// All possible referrents are instance members and the current
/// context is not an instance method.
IMA_Error_StaticContext,
@@ -86,7 +91,7 @@
/// The given lookup names class member(s) and is not being used for
/// an address-of-member expression. Classify the type of access
/// according to whether it's possible that this reference names an
-/// instance member. This is best-effort; it is okay to
+/// instance member. This is best-effort in dependent contexts; it is okay to
/// conservatively answer "yes", in which case some errors will simply
/// not be caught until template-instantiation.
static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
@@ -112,14 +117,14 @@
// Collect all the declaring classes of instance members we find.
bool hasNonInstance = false;
- bool hasField = false;
+ bool isField = false;
llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
NamedDecl *D = *I;
if (D->isCXXInstanceMember()) {
if (dyn_cast<FieldDecl>(D))
- hasField = true;
+ isField = true;
CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
Classes.insert(R->getCanonicalDecl());
@@ -139,8 +144,8 @@
if (hasNonInstance)
return IMA_Mixed_StaticContext;
- if (SemaRef.getLangOptions().CPlusPlus0x && hasField) {
- // C++0x [expr.prim.general]p10:
+ if (SemaRef.getLangOptions().CPlusPlus0x && isField) {
+ // C++11 [expr.prim.general]p12:
// An id-expression that denotes a non-static data member or non-static
// member function of a class can only be used:
// (...)
@@ -148,9 +153,8 @@
// appears in an unevaluated operand.
const Sema::ExpressionEvaluationContextRecord& record
= SemaRef.ExprEvalContexts.back();
- bool isUnevaluatedExpression = (record.Context == Sema::Unevaluated);
- if (isUnevaluatedExpression)
- return IMA_Mixed_StaticContext;
+ if (record.Context == Sema::Unevaluated)
+ return IMA_Field_Uneval_Context;
}
return IMA_Error_StaticContext;
@@ -196,16 +200,16 @@
if (MD->isStatic()) {
// "invalid use of member 'x' in static member function"
SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
- << Range << nameInfo.getName();
+ << Range << nameInfo.getName();
return;
}
}
-
+
SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
- << nameInfo.getName() << Range;
+ << nameInfo.getName() << Range;
return;
}
-
+
SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
}
@@ -226,6 +230,7 @@
case IMA_Static:
case IMA_Mixed_StaticContext:
case IMA_Unresolved_StaticContext:
+ case IMA_Field_Uneval_Context:
if (TemplateArgs)
return BuildTemplateIdExpr(SS, R, false, *TemplateArgs);
return BuildDeclarationNameExpr(SS, R, false);
@@ -238,7 +243,6 @@
}
llvm_unreachable("unexpected instance member access kind");
- return ExprError();
}
/// Check an ext-vector component access expression.
@@ -509,6 +513,20 @@
return true;
}
+namespace {
+
+// Callback to only accept typo corrections that are either a ValueDecl or a
+// FunctionTemplateDecl.
+class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ NamedDecl *ND = candidate.getCorrectionDecl();
+ return ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND));
+ }
+};
+
+}
+
static bool
LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
SourceRange BaseRange, const RecordType *RTy,
@@ -559,13 +577,12 @@
// We didn't find anything with the given name, so try to correct
// for typos.
DeclarationName Name = R.getLookupName();
+ RecordMemberExprValidatorCCC Validator;
TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), NULL,
- &SS, DC, false,
- Sema::CTC_MemberLookup);
- NamedDecl *ND = Corrected.getCorrectionDecl();
+ &SS, &Validator, DC);
R.clear();
- if (ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND))) {
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
std::string CorrectedStr(
Corrected.getAsString(SemaRef.getLangOptions()));
std::string CorrectedQuotedStr(
@@ -705,6 +722,7 @@
}
// Our base object expression is "this".
+ CheckCXXThisCapture(loc);
baseObjectExpr
= new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
baseObjectIsPointer = true;
@@ -854,6 +872,7 @@
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
+ CheckCXXThisCapture(Loc);
BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
}
@@ -974,12 +993,10 @@
/// Perform conversions on the LHS of a member access expression.
ExprResult
Sema::PerformMemberExprBaseConversion(Expr *Base, bool IsArrow) {
- ExprResult BaseResult = DefaultFunctionArrayConversion(Base);
+ if (IsArrow && !Base->getType()->isFunctionType())
+ return DefaultFunctionArrayLvalueConversion(Base);
- if (!BaseResult.isInvalid() && IsArrow)
- BaseResult = DefaultLvalueConversion(BaseResult.take());
-
- return BaseResult;
+ return CheckPlaceholderExpr(Base);
}
/// Look up the given member of the given non-type-dependent
@@ -1031,7 +1048,7 @@
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
<< FixItHint::CreateReplacement(OpLoc, ".");
IsArrow = false;
- } else if (BaseType == Context.BoundMemberTy) {
+ } else if (BaseType->isFunctionType()) {
goto fail;
} else {
Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
@@ -1073,10 +1090,12 @@
goto fail;
// There's an implicit 'isa' ivar on all objects.
// But we only actually find it this way on objects of type 'id',
- // apparently.
- if (OTy->isObjCId() && Member->isStr("isa"))
+ // apparently.ghjg
+ if (OTy->isObjCId() && Member->isStr("isa")) {
+ Diag(MemberLoc, diag::warn_objc_isa_use);
return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
Context.getObjCClassType()));
+ }
if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
@@ -1084,17 +1103,22 @@
goto fail;
}
+ if (RequireCompleteType(OpLoc, BaseType,
+ PDiag(diag::err_typecheck_incomplete_tag)
+ << BaseExpr.get()->getSourceRange()))
+ return ExprError();
+
ObjCInterfaceDecl *ClassDeclared;
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
if (!IV) {
// Attempt to correct for typos in ivar names.
- LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
- LookupMemberName);
- TypoCorrection Corrected = CorrectTypo(
- R.getLookupNameInfo(), LookupMemberName, NULL, NULL, IDecl, false,
- IsArrow ? CTC_ObjCIvarLookup : CTC_ObjCPropertyLookup);
- if ((IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>())) {
+ DeclFilterCCC<ObjCIvarDecl> Validator;
+ Validator.IsObjCIvarLookup = IsArrow;
+ if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
+ LookupMemberName, NULL, NULL,
+ &Validator, IDecl)) {
+ IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
Diag(R.getNameLoc(),
diag::err_typecheck_member_reference_ivar_suggest)
<< IDecl->getDeclName() << MemberName << IV->getDeclName()
@@ -1110,8 +1134,6 @@
<< FixItHint::CreateReplacement(OpLoc, ".");
return ExprError();
}
- Res.clear();
- Res.setLookupName(Member);
Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
<< IDecl->getDeclName() << MemberName
@@ -1358,7 +1380,7 @@
if (tryToRecoverWithCall(BaseExpr,
PDiag(diag::err_member_reference_needs_call),
/*complain*/ false,
- IsArrow ? &isRecordType : &isPointerToRecordType)) {
+ IsArrow ? &isPointerToRecordType : &isRecordType)) {
if (BaseExpr.isInvalid())
return ExprError();
BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
@@ -1551,6 +1573,7 @@
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
+ CheckCXXThisCapture(Loc);
baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
}
Modified: cfe/branches/tooling/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaExprObjC.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaExprObjC.cpp Fri Jan 20 10:14:22 2012
@@ -265,8 +265,7 @@
if (captureIndex) break;
bool nested = isa<BlockScopeInfo>(FunctionScopes[idx-1]);
- blockScope->Captures.push_back(
- BlockDecl::Capture(self, /*byref*/ false, nested, /*copy*/ 0));
+ blockScope->AddCapture(self, /*byref*/ false, nested, /*copy*/ 0);
captureIndex = blockScope->Captures.size(); // +1
}
@@ -454,14 +453,12 @@
Args[NumArgs-1]->getLocEnd());
}
}
- // diagnose nonnull arguments.
- for (specific_attr_iterator<NonNullAttr>
- i = Method->specific_attr_begin<NonNullAttr>(),
- e = Method->specific_attr_end<NonNullAttr>(); i != e; ++i) {
- CheckNonNullArguments(*i, Args, lbrac);
- }
DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs);
+
+ // Do additional checkings on method.
+ IsError |= CheckObjCMethodCall(Method, lbrac, Args, NumArgs);
+
return IsError;
}
@@ -704,11 +701,12 @@
}
// Attempt to correct for typos in property names.
- TypoCorrection Corrected = CorrectTypo(
+ DeclFilterCCC<ObjCPropertyDecl> Validator;
+ if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
- NULL, IFace, false, CTC_NoKeywords, OPT);
- if (ObjCPropertyDecl *Property =
- Corrected.getCorrectionDeclAs<ObjCPropertyDecl>()) {
+ NULL, &Validator, IFace, false, OPT)) {
+ ObjCPropertyDecl *Property =
+ Corrected.getCorrectionDeclAs<ObjCPropertyDecl>();
DeclarationName TypoResult = Corrected.getCorrection();
Diag(MemberLoc, diag::err_property_not_found_suggest)
<< MemberName << QualType(OPT, 0) << TypoResult
@@ -848,6 +846,24 @@
<< &propertyName << Context.getObjCInterfaceType(IFace));
}
+namespace {
+
+class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback {
+ public:
+ ObjCInterfaceOrSuperCCC(ObjCMethodDecl *Method) {
+ // Determine whether "super" is acceptable in the current context.
+ if (Method && Method->getClassInterface())
+ WantObjCSuper = Method->getClassInterface()->getSuperClass();
+ }
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ return candidate.getCorrectionDeclAs<ObjCInterfaceDecl>() ||
+ candidate.isKeyword("super");
+ }
+};
+
+}
+
Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
IdentifierInfo *Name,
SourceLocation NameLoc,
@@ -917,39 +933,32 @@
}
}
- // Determine our typo-correction context.
- CorrectTypoContext CTC = CTC_Expression;
- if (ObjCMethodDecl *Method = getCurMethodDecl())
- if (Method->getClassInterface() &&
- Method->getClassInterface()->getSuperClass())
- CTC = CTC_ObjCMessageReceiver;
-
+ ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl());
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S, NULL,
- NULL, false, CTC)) {
- if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
- // If we found a declaration, correct when it refers to an Objective-C
- // class.
- if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) {
- Diag(NameLoc, diag::err_unknown_receiver_suggest)
- << Name << Corrected.getCorrection()
- << FixItHint::CreateReplacement(SourceRange(NameLoc),
- ND->getNameAsString());
- Diag(ND->getLocation(), diag::note_previous_decl)
- << Corrected.getCorrection();
-
- QualType T = Context.getObjCInterfaceType(Class);
- TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
- ReceiverType = CreateParsedType(T, TSInfo);
- return ObjCClassMessage;
- }
- } else if (Corrected.isKeyword() &&
- Corrected.getCorrectionAsIdentifierInfo()->isStr("super")) {
- // If we've found the keyword "super", this is a send to super.
+ &Validator)) {
+ if (Corrected.isKeyword()) {
+ // If we've found the keyword "super" (the only keyword that would be
+ // returned by CorrectTypo), this is a send to super.
Diag(NameLoc, diag::err_unknown_receiver_suggest)
<< Name << Corrected.getCorrection()
<< FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
return ObjCSuperMessage;
+ } else if (ObjCInterfaceDecl *Class =
+ Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
+ // If we found a declaration, correct when it refers to an Objective-C
+ // class.
+ Diag(NameLoc, diag::err_unknown_receiver_suggest)
+ << Name << Corrected.getCorrection()
+ << FixItHint::CreateReplacement(SourceRange(NameLoc),
+ Class->getNameAsString());
+ Diag(Class->getLocation(), diag::note_previous_decl)
+ << Corrected.getCorrection();
+
+ QualType T = Context.getObjCInterfaceType(Class);
+ TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
+ ReceiverType = CreateParsedType(T, TSInfo);
+ return ObjCClassMessage;
}
}
@@ -1011,6 +1020,24 @@
LBracLoc, SelectorLocs, RBracLoc, move(Args));
}
+
+ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType,
+ bool isSuperReceiver,
+ SourceLocation Loc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ MultiExprArg Args) {
+ TypeSourceInfo *receiverTypeInfo = 0;
+ if (!ReceiverType.isNull())
+ receiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType);
+
+ return BuildClassMessage(receiverTypeInfo, ReceiverType,
+ /*SuperLoc=*/isSuperReceiver ? Loc : SourceLocation(),
+ Sel, Method, Loc, Loc, Loc, Args,
+ /*isImplicit=*/true);
+
+}
+
/// \brief Build an Objective-C class message expression.
///
/// This routine takes care of both normal class messages and
@@ -1047,7 +1074,8 @@
SourceLocation LBracLoc,
ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
- MultiExprArg ArgsIn) {
+ MultiExprArg ArgsIn,
+ bool isImplicit) {
SourceLocation Loc = SuperLoc.isValid()? SuperLoc
: ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin();
if (LBracLoc.isInvalid()) {
@@ -1065,7 +1093,8 @@
return Owned(ObjCMessageExpr::Create(Context, ReceiverType,
VK_RValue, LBracLoc, ReceiverTypeInfo,
Sel, SelectorLocs, /*Method=*/0,
- makeArrayRef(Args, NumArgs),RBracLoc));
+ makeArrayRef(Args, NumArgs),RBracLoc,
+ isImplicit));
}
// Find the class to which we are sending this message.
@@ -1131,12 +1160,12 @@
SuperLoc, /*IsInstanceSuper=*/false,
ReceiverType, Sel, SelectorLocs,
Method, makeArrayRef(Args, NumArgs),
- RBracLoc);
+ RBracLoc, isImplicit);
else
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
ReceiverTypeInfo, Sel, SelectorLocs,
Method, makeArrayRef(Args, NumArgs),
- RBracLoc);
+ RBracLoc, isImplicit);
return MaybeBindToTemporary(Result);
}
@@ -1164,6 +1193,18 @@
LBracLoc, SelectorLocs, RBracLoc, move(Args));
}
+ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
+ QualType ReceiverType,
+ SourceLocation Loc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ MultiExprArg Args) {
+ return BuildInstanceMessage(Receiver, ReceiverType,
+ /*SuperLoc=*/!Receiver ? Loc : SourceLocation(),
+ Sel, Method, Loc, Loc, Loc, Args,
+ /*isImplicit=*/true);
+}
+
/// \brief Build an Objective-C instance message expression.
///
/// This routine takes care of both normal instance messages and
@@ -1200,7 +1241,8 @@
SourceLocation LBracLoc,
ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
- MultiExprArg ArgsIn) {
+ MultiExprArg ArgsIn,
+ bool isImplicit) {
// The location of the receiver.
SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart();
@@ -1233,7 +1275,7 @@
VK_RValue, LBracLoc, Receiver, Sel,
SelectorLocs, /*Method=*/0,
makeArrayRef(Args, NumArgs),
- RBracLoc));
+ RBracLoc, isImplicit));
}
// If necessary, apply function/array conversion to the receiver.
@@ -1523,11 +1565,13 @@
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
SuperLoc, /*IsInstanceSuper=*/true,
ReceiverType, Sel, SelectorLocs, Method,
- makeArrayRef(Args, NumArgs), RBracLoc);
+ makeArrayRef(Args, NumArgs), RBracLoc,
+ isImplicit);
else
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
Receiver, Sel, SelectorLocs, Method,
- makeArrayRef(Args, NumArgs), RBracLoc);
+ makeArrayRef(Args, NumArgs), RBracLoc,
+ isImplicit);
if (getLangOptions().ObjCAutoRefCount) {
// In ARC, annotate delegate init calls.
Modified: cfe/branches/tooling/lib/Sema/SemaFixItUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaFixItUtils.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaFixItUtils.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaFixItUtils.cpp Fri Jan 20 10:14:22 2012
@@ -158,3 +158,39 @@
return false;
}
+
+static bool isMacroDefined(const Sema &S, StringRef Name) {
+ return S.PP.getMacroInfo(&S.getASTContext().Idents.get(Name));
+}
+
+const char *Sema::getFixItZeroInitializerForType(QualType T) const {
+ if (T->isScalarType()) {
+ // Suggest " = 0" for non-enumeration scalar types, unless we can find a
+ // better initializer.
+ if (T->isEnumeralType())
+ return 0;
+ if ((T->isObjCObjectPointerType() || T->isBlockPointerType()) &&
+ isMacroDefined(*this, "nil"))
+ return " = nil";
+ if (T->isRealFloatingType())
+ return " = 0.0";
+ if (T->isBooleanType() && LangOpts.CPlusPlus)
+ return " = false";
+ if (T->isPointerType() || T->isMemberPointerType()) {
+ if (LangOpts.CPlusPlus0x)
+ return " = nullptr";
+ else if (isMacroDefined(*this, "NULL"))
+ return " = NULL";
+ }
+ return " = 0";
+ }
+
+ const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+ if (!RD || !RD->hasDefinition())
+ return 0;
+ if (LangOpts.CPlusPlus0x && !RD->hasUserProvidedDefaultConstructor())
+ return "{}";
+ if (RD->isAggregate())
+ return " = {}";
+ return 0;
+}
Modified: cfe/branches/tooling/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaInit.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaInit.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaInit.cpp Fri Jan 20 10:14:22 2012
@@ -21,6 +21,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
+#include "llvm/ADT/APInt.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
@@ -171,9 +172,6 @@
bool hadError;
bool VerifyOnly; // no diagnostics, no structure building
bool AllowBraceElision;
- Expr *LastCheckedSubobject;
- unsigned LastCheckedSubobjectIndex;
-
std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
InitListExpr *FullyStructuredList;
@@ -473,8 +471,7 @@
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
InitListExpr *IL, QualType &T,
bool VerifyOnly, bool AllowBraceElision)
- : SemaRef(S), VerifyOnly(VerifyOnly), AllowBraceElision(AllowBraceElision),
- LastCheckedSubobject(0), LastCheckedSubobjectIndex(0) {
+ : SemaRef(S), VerifyOnly(VerifyOnly), AllowBraceElision(AllowBraceElision) {
hadError = false;
unsigned newIndex = 0;
@@ -796,40 +793,13 @@
if (Seq) {
if (!VerifyOnly) {
- // struct S {
- // S(int);
- // };
- //
- // S s[] = { [0 ... 2] = 3 };
- //
- // In code like this, we want to perform the initialization and then
- // update the syntactic list with the result. However, we reach this
- // point once for each subobject, but the update needs
- // to be done only once for each syntactic element. For this reason,
- // the initialization result and its syntactic Index are cached in
- // LastCheckedSubobject and LastCheckedSubobjectIndex and reused until
- // we move to the next Index.
- Expr *ResultExpr = LastCheckedSubobject;
-
- if (!ResultExpr || Index != LastCheckedSubobjectIndex) {
- ExprResult Result = Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1));
-
- if (Result.isInvalid()) {
- hadError = true;
- ResultExpr = 0;
- } else {
- ResultExpr = Result.takeAs<Expr>();
- }
-
- LastCheckedSubobject = ResultExpr;
- LastCheckedSubobjectIndex = Index;
- }
-
- // Update the syntactic list
- IList->setInit(Index, ResultExpr);
+ ExprResult Result =
+ Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1));
+ if (Result.isInvalid())
+ hadError = true;
UpdateStructuredListElement(StructuredList, StructuredIndex,
- ResultExpr);
+ Result.takeAs<Expr>());
}
++Index;
return;
@@ -1560,6 +1530,26 @@
DIE->usesGNUSyntax(), DIE->getInit());
}
+namespace {
+
+// Callback to only accept typo corrections that are for field members of
+// the given struct or union.
+class FieldInitializerValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ explicit FieldInitializerValidatorCCC(RecordDecl *RD)
+ : Record(RD) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ FieldDecl *FD = candidate.getCorrectionDeclAs<FieldDecl>();
+ return FD && FD->getDeclContext()->getRedeclContext()->Equals(Record);
+ }
+
+ private:
+ RecordDecl *Record;
+};
+
+}
+
/// @brief Check the well-formedness of a C99 designated initializer.
///
/// Determines whether the designated initializer @p DIE, which
@@ -1718,19 +1708,17 @@
if (Lookup.first == Lookup.second) {
// Name lookup didn't find anything. Determine whether this
// was a typo for another field name.
- LookupResult R(SemaRef, FieldName, D->getFieldLoc(),
- Sema::LookupMemberName);
+ FieldInitializerValidatorCCC Validator(RT->getDecl());
TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(FieldName, D->getFieldLoc()),
- Sema::LookupMemberName, /*Scope=*/NULL, /*SS=*/NULL,
- RT->getDecl(), false, Sema::CTC_NoKeywords);
- if ((ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>()) &&
- ReplacementField->getDeclContext()->getRedeclContext()
- ->Equals(RT->getDecl())) {
+ Sema::LookupMemberName, /*Scope=*/0, /*SS=*/0, &Validator,
+ RT->getDecl());
+ if (Corrected) {
std::string CorrectedStr(
Corrected.getAsString(SemaRef.getLangOptions()));
std::string CorrectedQuotedStr(
Corrected.getQuoted(SemaRef.getLangOptions()));
+ ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>();
SemaRef.Diag(D->getFieldLoc(),
diag::err_field_designator_unknown_suggest)
<< FieldName << CurrentObjectType << CorrectedQuotedStr
@@ -2273,10 +2261,7 @@
InitExpressions.data(), InitExpressions.size(),
Loc, GNUSyntax, Init.takeAs<Expr>());
- if (getLangOptions().CPlusPlus)
- Diag(DIE->getLocStart(), diag::ext_designated_init_cxx)
- << DIE->getSourceRange();
- else if (!getLangOptions().C99)
+ if (!getLangOptions().C99)
Diag(DIE->getLocStart(), diag::ext_designated_init)
<< DIE->getSourceRange();
@@ -2343,8 +2328,7 @@
return DeclarationName();
}
- // Silence GCC warning
- return DeclarationName();
+ llvm_unreachable("Invalid EntityKind!");
}
DeclaratorDecl *InitializedEntity::getDecl() const {
@@ -2369,8 +2353,7 @@
return 0;
}
- // Silence GCC warning
- return 0;
+ llvm_unreachable("Invalid EntityKind!");
}
bool InitializedEntity::allowsNRVO() const {
@@ -2426,6 +2409,7 @@
case SK_PassByIndirectCopyRestore:
case SK_PassByIndirectRestore:
case SK_ProduceObjCObject:
+ case SK_StdInitializerList:
break;
case SK_ConversionSequence:
@@ -2461,180 +2445,25 @@
case FK_ArrayTypeMismatch:
case FK_NonConstantArrayInit:
case FK_ListInitializationFailed:
+ case FK_VariableLengthArrayHasInitializer:
case FK_PlaceholderType:
+ case FK_InitListElementCopyFailure:
return false;
case FK_ReferenceInitOverloadFailed:
case FK_UserConversionOverloadFailed:
case FK_ConstructorOverloadFailed:
+ case FK_ListConstructorOverloadFailed:
return FailedOverloadResult == OR_Ambiguous;
}
- return false;
+ llvm_unreachable("Invalid EntityKind!");
}
bool InitializationSequence::isConstructorInitialization() const {
return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization;
}
-bool InitializationSequence::endsWithNarrowing(ASTContext &Ctx,
- const Expr *Initializer,
- bool *isInitializerConstant,
- APValue *ConstantValue) const {
- if (Steps.empty() || Initializer->isValueDependent())
- return false;
-
- const Step &LastStep = Steps.back();
- if (LastStep.Kind != SK_ConversionSequence)
- return false;
-
- const ImplicitConversionSequence &ICS = *LastStep.ICS;
- const StandardConversionSequence *SCS = NULL;
- switch (ICS.getKind()) {
- case ImplicitConversionSequence::StandardConversion:
- SCS = &ICS.Standard;
- break;
- case ImplicitConversionSequence::UserDefinedConversion:
- SCS = &ICS.UserDefined.After;
- break;
- case ImplicitConversionSequence::AmbiguousConversion:
- case ImplicitConversionSequence::EllipsisConversion:
- case ImplicitConversionSequence::BadConversion:
- return false;
- }
-
- // Check if SCS represents a narrowing conversion, according to C++0x
- // [dcl.init.list]p7:
- //
- // A narrowing conversion is an implicit conversion ...
- ImplicitConversionKind PossibleNarrowing = SCS->Second;
- QualType FromType = SCS->getToType(0);
- QualType ToType = SCS->getToType(1);
- switch (PossibleNarrowing) {
- // * from a floating-point type to an integer type, or
- //
- // * from an integer type or unscoped enumeration type to a floating-point
- // type, except where the source is a constant expression and the actual
- // value after conversion will fit into the target type and will produce
- // the original value when converted back to the original type, or
- case ICK_Floating_Integral:
- if (FromType->isRealFloatingType() && ToType->isIntegralType(Ctx)) {
- *isInitializerConstant = false;
- return true;
- } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) {
- llvm::APSInt IntConstantValue;
- if (Initializer &&
- Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) {
- // Convert the integer to the floating type.
- llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType));
- Result.convertFromAPInt(IntConstantValue, IntConstantValue.isSigned(),
- llvm::APFloat::rmNearestTiesToEven);
- // And back.
- llvm::APSInt ConvertedValue = IntConstantValue;
- bool ignored;
- Result.convertToInteger(ConvertedValue,
- llvm::APFloat::rmTowardZero, &ignored);
- // If the resulting value is different, this was a narrowing conversion.
- if (IntConstantValue != ConvertedValue) {
- *isInitializerConstant = true;
- *ConstantValue = APValue(IntConstantValue);
- return true;
- }
- } else {
- // Variables are always narrowings.
- *isInitializerConstant = false;
- return true;
- }
- }
- return false;
-
- // * from long double to double or float, or from double to float, except
- // where the source is a constant expression and the actual value after
- // conversion is within the range of values that can be represented (even
- // if it cannot be represented exactly), or
- case ICK_Floating_Conversion:
- if (1 == Ctx.getFloatingTypeOrder(FromType, ToType)) {
- // FromType is larger than ToType.
- Expr::EvalResult InitializerValue;
- // FIXME: Check whether Initializer is a constant expression according
- // to C++0x [expr.const], rather than just whether it can be folded.
- if (Initializer->EvaluateAsRValue(InitializerValue, Ctx) &&
- !InitializerValue.HasSideEffects && InitializerValue.Val.isFloat()) {
- // Constant! (Except for FIXME above.)
- llvm::APFloat FloatVal = InitializerValue.Val.getFloat();
- // Convert the source value into the target type.
- bool ignored;
- llvm::APFloat::opStatus ConvertStatus = FloatVal.convert(
- Ctx.getFloatTypeSemantics(ToType),
- llvm::APFloat::rmNearestTiesToEven, &ignored);
- // If there was no overflow, the source value is within the range of
- // values that can be represented.
- if (ConvertStatus & llvm::APFloat::opOverflow) {
- *isInitializerConstant = true;
- *ConstantValue = InitializerValue.Val;
- return true;
- }
- } else {
- *isInitializerConstant = false;
- return true;
- }
- }
- return false;
-
- // * from an integer type or unscoped enumeration type to an integer type
- // that cannot represent all the values of the original type, except where
- // the source is a constant expression and the actual value after
- // conversion will fit into the target type and will produce the original
- // value when converted back to the original type.
- case ICK_Boolean_Conversion: // Bools are integers too.
- if (!FromType->isIntegralOrUnscopedEnumerationType()) {
- // Boolean conversions can be from pointers and pointers to members
- // [conv.bool], and those aren't considered narrowing conversions.
- return false;
- } // Otherwise, fall through to the integral case.
- case ICK_Integral_Conversion: {
- assert(FromType->isIntegralOrUnscopedEnumerationType());
- assert(ToType->isIntegralOrUnscopedEnumerationType());
- const bool FromSigned = FromType->isSignedIntegerOrEnumerationType();
- const unsigned FromWidth = Ctx.getIntWidth(FromType);
- const bool ToSigned = ToType->isSignedIntegerOrEnumerationType();
- const unsigned ToWidth = Ctx.getIntWidth(ToType);
-
- if (FromWidth > ToWidth ||
- (FromWidth == ToWidth && FromSigned != ToSigned)) {
- // Not all values of FromType can be represented in ToType.
- llvm::APSInt InitializerValue;
- if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) {
- *isInitializerConstant = true;
- *ConstantValue = APValue(InitializerValue);
-
- // Add a bit to the InitializerValue so we don't have to worry about
- // signed vs. unsigned comparisons.
- InitializerValue = InitializerValue.extend(
- InitializerValue.getBitWidth() + 1);
- // Convert the initializer to and from the target width and signed-ness.
- llvm::APSInt ConvertedValue = InitializerValue;
- ConvertedValue = ConvertedValue.trunc(ToWidth);
- ConvertedValue.setIsSigned(ToSigned);
- ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
- ConvertedValue.setIsSigned(InitializerValue.isSigned());
- // If the result is different, this was a narrowing conversion.
- return ConvertedValue != InitializerValue;
- } else {
- // Variables are always narrowings.
- *isInitializerConstant = false;
- return true;
- }
- }
- return false;
- }
-
- default:
- // Other kinds of conversions are not narrowings.
- return false;
- }
-}
-
void
InitializationSequence
::AddAddressOverloadResolutionStep(FunctionDecl *Function,
@@ -2656,7 +2485,6 @@
case VK_RValue: S.Kind = SK_CastDerivedToBaseRValue; break;
case VK_XValue: S.Kind = SK_CastDerivedToBaseXValue; break;
case VK_LValue: S.Kind = SK_CastDerivedToBaseLValue; break;
- default: llvm_unreachable("No such category");
}
S.Type = BaseType;
Steps.push_back(S);
@@ -2732,9 +2560,10 @@
::AddConstructorInitializationStep(CXXConstructorDecl *Constructor,
AccessSpecifier Access,
QualType T,
- bool HadMultipleCandidates) {
+ bool HadMultipleCandidates,
+ bool FromInitList) {
Step S;
- S.Kind = SK_ConstructorInitialization;
+ S.Kind = FromInitList ? SK_ListConstructorCall : SK_ConstructorInitialization;
S.Type = T;
S.Function.HadMultipleCandidates = HadMultipleCandidates;
S.Function.Function = Constructor;
@@ -2793,6 +2622,13 @@
Steps.push_back(S);
}
+void InitializationSequence::AddStdInitializerListConstructionStep(QualType T) {
+ Step S;
+ S.Kind = SK_StdInitializerList;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::RewrapReferenceInitList(QualType T,
InitListExpr *Syntactic) {
assert(Syntactic->getNumInits() == 1 &&
@@ -2846,6 +2682,200 @@
}
}
+/// \brief When initializing from init list via constructor, deal with the
+/// empty init list and std::initializer_list special cases.
+///
+/// \return True if this was a special case, false otherwise.
+static bool TryListConstructionSpecialCases(Sema &S,
+ Expr **Args, unsigned NumArgs,
+ CXXRecordDecl *DestRecordDecl,
+ QualType DestType,
+ InitializationSequence &Sequence) {
+ // C++11 [dcl.init.list]p3:
+ // List-initialization of an object of type T is defined as follows:
+ // - If the initializer list has no elements and T is a class type with
+ // a default constructor, the object is value-initialized.
+ if (NumArgs == 0) {
+ if (CXXConstructorDecl *DefaultConstructor =
+ S.LookupDefaultConstructor(DestRecordDecl)) {
+ if (DefaultConstructor->isDeleted() ||
+ S.isFunctionConsideredUnavailable(DefaultConstructor)) {
+ // Fake an overload resolution failure.
+ OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
+ DeclAccessPair FoundDecl = DeclAccessPair::make(DefaultConstructor,
+ DefaultConstructor->getAccess());
+ if (FunctionTemplateDecl *ConstructorTmpl =
+ dyn_cast<FunctionTemplateDecl>(DefaultConstructor))
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ /*ExplicitArgs*/ 0,
+ Args, NumArgs, CandidateSet,
+ /*SuppressUserConversions*/ false);
+ else
+ S.AddOverloadCandidate(DefaultConstructor, FoundDecl,
+ Args, NumArgs, CandidateSet,
+ /*SuppressUserConversions*/ false);
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_ListConstructorOverloadFailed,
+ OR_Deleted);
+ } else
+ Sequence.AddConstructorInitializationStep(DefaultConstructor,
+ DefaultConstructor->getAccess(),
+ DestType,
+ /*MultipleCandidates=*/false,
+ /*FromInitList=*/true);
+ return true;
+ }
+ }
+
+ // - Otherwise, if T is a specialization of std::initializer_list, [...]
+ QualType E;
+ if (S.isStdInitializerList(DestType, &E)) {
+ // Check that each individual element can be copy-constructed. But since we
+ // have no place to store further information, we'll recalculate everything
+ // later.
+ InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
+ S.Context.getConstantArrayType(E,
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),NumArgs),
+ ArrayType::Normal, 0));
+ InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
+ 0, HiddenArray);
+ for (unsigned i = 0; i < NumArgs; ++i) {
+ Element.setElementIndex(i);
+ if (!S.CanPerformCopyInitialization(Element, Args[i])) {
+ Sequence.SetFailed(
+ InitializationSequence::FK_InitListElementCopyFailure);
+ return true;
+ }
+ }
+ Sequence.AddStdInitializerListConstructionStep(DestType);
+ return true;
+ }
+
+ // Not a special case.
+ return false;
+}
+
+/// \brief Attempt initialization by constructor (C++ [dcl.init]), which
+/// enumerates the constructors of the initialized entity and performs overload
+/// resolution to select the best.
+/// If FromInitList is true, this is list-initialization of a non-aggregate
+/// class type.
+static void TryConstructorInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr **Args, unsigned NumArgs,
+ QualType DestType,
+ InitializationSequence &Sequence,
+ bool FromInitList = false) {
+ // Check constructor arguments for self reference.
+ if (DeclaratorDecl *DD = Entity.getDecl())
+ // Parameters arguments are occassionially constructed with itself,
+ // for instance, in recursive functions. Skip them.
+ if (!isa<ParmVarDecl>(DD))
+ for (unsigned i = 0; i < NumArgs; ++i)
+ S.CheckSelfReference(DD, Args[i]);
+
+ // Build the candidate set directly in the initialization sequence
+ // structure, so that it will persist if we fail.
+ OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
+ CandidateSet.clear();
+
+ // Determine whether we are allowed to call explicit constructors or
+ // explicit conversion operators.
+ bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct ||
+ Kind.getKind() == InitializationKind::IK_Value ||
+ Kind.getKind() == InitializationKind::IK_Default);
+
+ // The type we're constructing needs to be complete.
+ if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
+ Sequence.SetFailed(InitializationSequence::FK_Incomplete);
+ }
+
+ const RecordType *DestRecordType = DestType->getAs<RecordType>();
+ assert(DestRecordType && "Constructor initialization requires record type");
+ CXXRecordDecl *DestRecordDecl
+ = cast<CXXRecordDecl>(DestRecordType->getDecl());
+
+ if (FromInitList &&
+ TryListConstructionSpecialCases(S, Args, NumArgs, DestRecordDecl,
+ DestType, Sequence))
+ return;
+
+ // - Otherwise, if T is a class type, constructors are considered. The
+ // applicable constructors are enumerated, and the best one is chosen
+ // through overload resolution.
+ DeclContext::lookup_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl);
+ Con != ConEnd; ++Con) {
+ NamedDecl *D = *Con;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
+ bool SuppressUserConversions = false;
+
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
+ if (ConstructorTmpl)
+ Constructor = cast<CXXConstructorDecl>(
+ ConstructorTmpl->getTemplatedDecl());
+ else {
+ Constructor = cast<CXXConstructorDecl>(D);
+
+ // If we're performing copy initialization using a copy constructor, we
+ // suppress user-defined conversions on the arguments.
+ // FIXME: Move constructors?
+ if (Kind.getKind() == InitializationKind::IK_Copy &&
+ Constructor->isCopyConstructor())
+ SuppressUserConversions = true;
+ }
+
+ if (!Constructor->isInvalidDecl() &&
+ (AllowExplicit || !Constructor->isExplicit())) {
+ if (ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ /*ExplicitArgs*/ 0,
+ Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
+ else
+ S.AddOverloadCandidate(Constructor, FoundDecl,
+ Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
+ }
+ }
+
+ SourceLocation DeclLoc = Kind.getLocation();
+
+ // Perform overload resolution. If it fails, return the failed result.
+ OverloadCandidateSet::iterator Best;
+ if (OverloadingResult Result
+ = CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
+ Sequence.SetOverloadFailure(FromInitList ?
+ InitializationSequence::FK_ListConstructorOverloadFailed :
+ InitializationSequence::FK_ConstructorOverloadFailed,
+ Result);
+ return;
+ }
+
+ // C++0x [dcl.init]p6:
+ // If a program calls for the default initialization of an object
+ // of a const-qualified type T, T shall be a class type with a
+ // user-provided default constructor.
+ if (Kind.getKind() == InitializationKind::IK_Default &&
+ Entity.getType().isConstQualified() &&
+ cast<CXXConstructorDecl>(Best->Function)->isImplicit()) {
+ Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+ return;
+ }
+
+ // Add the constructor initialization step. Any cv-qualification conversion is
+ // subsumed by the initialization.
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+ CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
+ Sequence.AddConstructorInitializationStep(CtorDecl,
+ Best->FoundDecl.getAccess(),
+ DestType, HadMultipleCandidates,
+ FromInitList);
+}
+
static bool
ResolveOverloadedFunctionForReferenceBinding(Sema &S,
Expr *Initializer,
@@ -2973,9 +3003,13 @@
TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence);
return;
}
- // FIXME: C++11 defines behavior for this case.
if (DestType->isRecordType() && !DestType->isAggregateType()) {
- Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
+ if (S.getLangOptions().CPlusPlus0x)
+ TryConstructorInitialization(S, Entity, Kind, InitList->getInits(),
+ InitList->getNumInits(), DestType, Sequence,
+ /*FromInitList=*/true);
+ else
+ Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
return;
}
@@ -3451,117 +3485,6 @@
Sequence.AddStringInitStep(Entity.getType());
}
-/// \brief Attempt initialization by constructor (C++ [dcl.init]), which
-/// enumerates the constructors of the initialized entity and performs overload
-/// resolution to select the best.
-static void TryConstructorInitialization(Sema &S,
- const InitializedEntity &Entity,
- const InitializationKind &Kind,
- Expr **Args, unsigned NumArgs,
- QualType DestType,
- InitializationSequence &Sequence) {
- // Check constructor arguments for self reference.
- if (DeclaratorDecl *DD = Entity.getDecl())
- // Parameters arguments are occassionially constructed with itself,
- // for instance, in recursive functions. Skip them.
- if (!isa<ParmVarDecl>(DD))
- for (unsigned i = 0; i < NumArgs; ++i)
- S.CheckSelfReference(DD, Args[i]);
-
- // Build the candidate set directly in the initialization sequence
- // structure, so that it will persist if we fail.
- OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
- CandidateSet.clear();
-
- // Determine whether we are allowed to call explicit constructors or
- // explicit conversion operators.
- bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct ||
- Kind.getKind() == InitializationKind::IK_Value ||
- Kind.getKind() == InitializationKind::IK_Default);
-
- // The type we're constructing needs to be complete.
- if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
- Sequence.SetFailed(InitializationSequence::FK_Incomplete);
- return;
- }
-
- // The type we're converting to is a class type. Enumerate its constructors
- // to see if one is suitable.
- const RecordType *DestRecordType = DestType->getAs<RecordType>();
- assert(DestRecordType && "Constructor initialization requires record type");
- CXXRecordDecl *DestRecordDecl
- = cast<CXXRecordDecl>(DestRecordType->getDecl());
-
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl);
- Con != ConEnd; ++Con) {
- NamedDecl *D = *Con;
- DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
- bool SuppressUserConversions = false;
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
- FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
- if (ConstructorTmpl)
- Constructor = cast<CXXConstructorDecl>(
- ConstructorTmpl->getTemplatedDecl());
- else {
- Constructor = cast<CXXConstructorDecl>(D);
-
- // If we're performing copy initialization using a copy constructor, we
- // suppress user-defined conversions on the arguments.
- // FIXME: Move constructors?
- if (Kind.getKind() == InitializationKind::IK_Copy &&
- Constructor->isCopyConstructor())
- SuppressUserConversions = true;
- }
-
- if (!Constructor->isInvalidDecl() &&
- (AllowExplicit || !Constructor->isExplicit())) {
- if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
- Args, NumArgs, CandidateSet,
- SuppressUserConversions);
- else
- S.AddOverloadCandidate(Constructor, FoundDecl,
- Args, NumArgs, CandidateSet,
- SuppressUserConversions);
- }
- }
-
- SourceLocation DeclLoc = Kind.getLocation();
-
- // Perform overload resolution. If it fails, return the failed result.
- OverloadCandidateSet::iterator Best;
- if (OverloadingResult Result
- = CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
- Sequence.SetOverloadFailure(
- InitializationSequence::FK_ConstructorOverloadFailed,
- Result);
- return;
- }
-
- // C++0x [dcl.init]p6:
- // If a program calls for the default initialization of an object
- // of a const-qualified type T, T shall be a class type with a
- // user-provided default constructor.
- if (Kind.getKind() == InitializationKind::IK_Default &&
- Entity.getType().isConstQualified() &&
- cast<CXXConstructorDecl>(Best->Function)->isImplicit()) {
- Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
- return;
- }
-
- // Add the constructor initialization step. Any cv-qualification conversion is
- // subsumed by the initialization.
- bool HadMultipleCandidates = (CandidateSet.size() > 1);
- CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
- Sequence.AddConstructorInitializationStep(CtorDecl,
- Best->FoundDecl.getAccess(),
- DestType, HadMultipleCandidates);
-}
-
/// \brief Attempt value initialization (C++ [dcl.init]p7).
static void TryValueInitialization(Sema &S,
const InitializedEntity &Entity,
@@ -4026,6 +3949,11 @@
// - Otherwise, if the destination type is an array, the program is
// ill-formed.
if (const ArrayType *DestAT = Context.getAsArrayType(DestType)) {
+ if (Initializer && isa<VariableArrayType>(DestAT)) {
+ SetFailed(FK_VariableLengthArrayHasInitializer);
+ return;
+ }
+
if (Initializer && IsStringInit(Initializer, DestAT, Context)) {
TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this);
return;
@@ -4206,7 +4134,7 @@
return Sema::AA_Initializing;
}
- return Sema::AA_Converting;
+ llvm_unreachable("Invalid EntityKind!");
}
/// \brief Whether we should binding a created object as a temporary when
@@ -4557,6 +4485,117 @@
s.Kind == InitializationSequence::SK_BindReferenceToTemporary;
}
+static ExprResult
+PerformConstructorInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ MultiExprArg Args,
+ const InitializationSequence::Step& Step,
+ bool &ConstructorInitRequiresZeroInit) {
+ unsigned NumArgs = Args.size();
+ CXXConstructorDecl *Constructor
+ = cast<CXXConstructorDecl>(Step.Function.Function);
+ bool HadMultipleCandidates = Step.Function.HadMultipleCandidates;
+
+ // Build a call to the selected constructor.
+ ASTOwningVector<Expr*> ConstructorArgs(S);
+ SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid())
+ ? Kind.getEqualLoc()
+ : Kind.getLocation();
+
+ if (Kind.getKind() == InitializationKind::IK_Default) {
+ // Force even a trivial, implicit default constructor to be
+ // semantically checked. We do this explicitly because we don't build
+ // the definition for completely trivial constructors.
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
+ assert(ClassDecl && "No parent class for constructor.");
+ if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
+ ClassDecl->hasTrivialDefaultConstructor() &&
+ !Constructor->isUsed(false))
+ S.DefineImplicitDefaultConstructor(Loc, Constructor);
+ }
+
+ ExprResult CurInit = S.Owned((Expr *)0);
+
+ // Determine the arguments required to actually perform the constructor
+ // call.
+ if (S.CompleteConstructorCall(Constructor, move(Args),
+ Loc, ConstructorArgs))
+ return ExprError();
+
+
+ if (Entity.getKind() == InitializedEntity::EK_Temporary &&
+ NumArgs != 1 && // FIXME: Hack to work around cast weirdness
+ (Kind.getKind() == InitializationKind::IK_Direct ||
+ Kind.getKind() == InitializationKind::IK_Value)) {
+ // An explicitly-constructed temporary, e.g., X(1, 2).
+ unsigned NumExprs = ConstructorArgs.size();
+ Expr **Exprs = (Expr **)ConstructorArgs.take();
+ S.MarkDeclarationReferenced(Loc, Constructor);
+ S.DiagnoseUseOfDecl(Constructor, Loc);
+
+ TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
+ if (!TSInfo)
+ TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc);
+
+ CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context,
+ Constructor,
+ TSInfo,
+ Exprs,
+ NumExprs,
+ Kind.getParenRange(),
+ HadMultipleCandidates,
+ ConstructorInitRequiresZeroInit));
+ } else {
+ CXXConstructExpr::ConstructionKind ConstructKind =
+ CXXConstructExpr::CK_Complete;
+
+ if (Entity.getKind() == InitializedEntity::EK_Base) {
+ ConstructKind = Entity.getBaseSpecifier()->isVirtual() ?
+ CXXConstructExpr::CK_VirtualBase :
+ CXXConstructExpr::CK_NonVirtualBase;
+ } else if (Entity.getKind() == InitializedEntity::EK_Delegating) {
+ ConstructKind = CXXConstructExpr::CK_Delegating;
+ }
+
+ // Only get the parenthesis range if it is a direct construction.
+ SourceRange parenRange =
+ Kind.getKind() == InitializationKind::IK_Direct ?
+ Kind.getParenRange() : SourceRange();
+
+ // If the entity allows NRVO, mark the construction as elidable
+ // unconditionally.
+ if (Entity.allowsNRVO())
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor, /*Elidable=*/true,
+ move_arg(ConstructorArgs),
+ HadMultipleCandidates,
+ ConstructorInitRequiresZeroInit,
+ ConstructKind,
+ parenRange);
+ else
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor,
+ move_arg(ConstructorArgs),
+ HadMultipleCandidates,
+ ConstructorInitRequiresZeroInit,
+ ConstructKind,
+ parenRange);
+ }
+ if (CurInit.isInvalid())
+ return ExprError();
+
+ // Only check access if all of that succeeded.
+ S.CheckConstructorAccess(Loc, Constructor, Entity,
+ Step.Function.FoundDecl.getAccess());
+ S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc);
+
+ if (shouldBindAsTemporary(Entity))
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+
+ return move(CurInit);
+}
+
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@@ -4653,7 +4692,8 @@
case SK_ArrayInit:
case SK_PassByIndirectCopyRestore:
case SK_PassByIndirectRestore:
- case SK_ProduceObjCObject: {
+ case SK_ProduceObjCObject:
+ case SK_StdInitializerList: {
assert(Args.size() == 1);
CurInit = Args.get()[0];
if (!CurInit.get()) return ExprError();
@@ -4941,8 +4981,14 @@
break;
}
- case SK_ListConstructorCall:
- assert(false && "List constructor calls not yet supported.");
+ case SK_ListConstructorCall: {
+ InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
+ MultiExprArg Arg(InitList->getInits(), InitList->getNumInits());
+ CurInit = PerformConstructorInitialization(S, Entity, Kind,
+ move(Arg), *Step,
+ ConstructorInitRequiresZeroInit);
+ break;
+ }
case SK_UnwrapInitList:
CurInit = S.Owned(cast<InitListExpr>(CurInit.take())->getInit(0));
@@ -4960,108 +5006,11 @@
break;
}
- case SK_ConstructorInitialization: {
- unsigned NumArgs = Args.size();
- CXXConstructorDecl *Constructor
- = cast<CXXConstructorDecl>(Step->Function.Function);
- bool HadMultipleCandidates = Step->Function.HadMultipleCandidates;
-
- // Build a call to the selected constructor.
- ASTOwningVector<Expr*> ConstructorArgs(S);
- SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid())
- ? Kind.getEqualLoc()
- : Kind.getLocation();
-
- if (Kind.getKind() == InitializationKind::IK_Default) {
- // Force even a trivial, implicit default constructor to be
- // semantically checked. We do this explicitly because we don't build
- // the definition for completely trivial constructors.
- CXXRecordDecl *ClassDecl = Constructor->getParent();
- assert(ClassDecl && "No parent class for constructor.");
- if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
- ClassDecl->hasTrivialDefaultConstructor() &&
- !Constructor->isUsed(false))
- S.DefineImplicitDefaultConstructor(Loc, Constructor);
- }
-
- // Determine the arguments required to actually perform the constructor
- // call.
- if (S.CompleteConstructorCall(Constructor, move(Args),
- Loc, ConstructorArgs))
- return ExprError();
-
-
- if (Entity.getKind() == InitializedEntity::EK_Temporary &&
- NumArgs != 1 && // FIXME: Hack to work around cast weirdness
- (Kind.getKind() == InitializationKind::IK_Direct ||
- Kind.getKind() == InitializationKind::IK_Value)) {
- // An explicitly-constructed temporary, e.g., X(1, 2).
- unsigned NumExprs = ConstructorArgs.size();
- Expr **Exprs = (Expr **)ConstructorArgs.take();
- S.MarkDeclarationReferenced(Loc, Constructor);
- S.DiagnoseUseOfDecl(Constructor, Loc);
-
- TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
- if (!TSInfo)
- TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc);
-
- CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context,
- Constructor,
- TSInfo,
- Exprs,
- NumExprs,
- Kind.getParenRange(),
- HadMultipleCandidates,
- ConstructorInitRequiresZeroInit));
- } else {
- CXXConstructExpr::ConstructionKind ConstructKind =
- CXXConstructExpr::CK_Complete;
-
- if (Entity.getKind() == InitializedEntity::EK_Base) {
- ConstructKind = Entity.getBaseSpecifier()->isVirtual() ?
- CXXConstructExpr::CK_VirtualBase :
- CXXConstructExpr::CK_NonVirtualBase;
- } else if (Entity.getKind() == InitializedEntity::EK_Delegating) {
- ConstructKind = CXXConstructExpr::CK_Delegating;
- }
-
- // Only get the parenthesis range if it is a direct construction.
- SourceRange parenRange =
- Kind.getKind() == InitializationKind::IK_Direct ?
- Kind.getParenRange() : SourceRange();
-
- // If the entity allows NRVO, mark the construction as elidable
- // unconditionally.
- if (Entity.allowsNRVO())
- CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
- Constructor, /*Elidable=*/true,
- move_arg(ConstructorArgs),
- HadMultipleCandidates,
- ConstructorInitRequiresZeroInit,
- ConstructKind,
- parenRange);
- else
- CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
- Constructor,
- move_arg(ConstructorArgs),
- HadMultipleCandidates,
- ConstructorInitRequiresZeroInit,
- ConstructKind,
- parenRange);
- }
- if (CurInit.isInvalid())
- return ExprError();
-
- // Only check access if all of that succeeded.
- S.CheckConstructorAccess(Loc, Constructor, Entity,
- Step->Function.FoundDecl.getAccess());
- S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Loc);
-
- if (shouldBindAsTemporary(Entity))
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
-
+ case SK_ConstructorInitialization:
+ CurInit = PerformConstructorInitialization(S, Entity, Kind, move(Args),
+ *Step,
+ ConstructorInitRequiresZeroInit);
break;
- }
case SK_ZeroInitialization: {
step_iterator NextStep = Step;
@@ -5171,6 +5120,40 @@
CK_ARCProduceObject,
CurInit.take(), 0, VK_RValue));
break;
+
+ case SK_StdInitializerList: {
+ QualType Dest = Step->Type;
+ QualType E;
+ bool Success = S.isStdInitializerList(Dest, &E);
+ (void)Success;
+ assert(Success && "Destination type changed?");
+ InitListExpr *ILE = cast<InitListExpr>(CurInit.take());
+ unsigned NumInits = ILE->getNumInits();
+ SmallVector<Expr*, 16> Converted(NumInits);
+ InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
+ S.Context.getConstantArrayType(E,
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ NumInits),
+ ArrayType::Normal, 0));
+ InitializedEntity Element =InitializedEntity::InitializeElement(S.Context,
+ 0, HiddenArray);
+ for (unsigned i = 0; i < NumInits; ++i) {
+ Element.setElementIndex(i);
+ ExprResult Init = S.Owned(ILE->getInit(i));
+ ExprResult Res = S.PerformCopyInitialization(Element,
+ Init.get()->getExprLoc(),
+ Init);
+ assert(!Res.isInvalid() && "Result changed since try phase.");
+ Converted[i] = Res.take();
+ }
+ InitListExpr *Semantic = new (S.Context)
+ InitListExpr(S.Context, ILE->getLBraceLoc(),
+ Converted.data(), NumInits, ILE->getRBraceLoc());
+ Semantic->setSyntacticForm(ILE);
+ Semantic->setType(Dest);
+ CurInit = S.Owned(Semantic);
+ break;
+ }
}
}
@@ -5223,6 +5206,11 @@
<< Args[0]->getSourceRange();
break;
+ case FK_VariableLengthArrayHasInitializer:
+ S.Diag(Kind.getLocation(), diag::err_variable_object_no_init)
+ << Args[0]->getSourceRange();
+ break;
+
case FK_AddressOfOverloadFailed: {
DeclAccessPair Found;
S.ResolveAddressOfOverloadedFunction(Args[0],
@@ -5274,7 +5262,6 @@
case OR_Success:
llvm_unreachable("Conversion did not fail!");
- break;
}
break;
@@ -5373,12 +5360,20 @@
<< (DestType->isRecordType()) << DestType << Args[0]->getSourceRange();
break;
+ case FK_ListConstructorOverloadFailed:
case FK_ConstructorOverloadFailed: {
SourceRange ArgsRange;
if (NumArgs)
ArgsRange = SourceRange(Args[0]->getLocStart(),
Args[NumArgs - 1]->getLocEnd());
+ if (Failure == FK_ListConstructorOverloadFailed) {
+ assert(NumArgs == 1 && "List construction from other than 1 argument.");
+ InitListExpr *InitList = cast<InitListExpr>(Args[0]);
+ Args = InitList->getInits();
+ NumArgs = InitList->getNumInits();
+ }
+
// FIXME: Using "DestType" for the entity we're printing is probably
// bad.
switch (FailedOverloadResult) {
@@ -5451,10 +5446,9 @@
case OR_Success:
llvm_unreachable("Conversion did not fail!");
- break;
}
- break;
}
+ break;
case FK_DefaultInitOfConst:
if (Entity.getKind() == InitializedEntity::EK_Member &&
@@ -5498,6 +5492,37 @@
// FIXME: Already diagnosed!
break;
}
+
+ case FK_InitListElementCopyFailure: {
+ // Try to perform all copies again.
+ InitListExpr* InitList = cast<InitListExpr>(Args[0]);
+ unsigned NumInits = InitList->getNumInits();
+ QualType DestType = Entity.getType();
+ QualType E;
+ bool Success = S.isStdInitializerList(DestType, &E);
+ (void)Success;
+ assert(Success && "Where did the std::initializer_list go?");
+ InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
+ S.Context.getConstantArrayType(E,
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ NumInits),
+ ArrayType::Normal, 0));
+ InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
+ 0, HiddenArray);
+ // Show at most 3 errors. Otherwise, you'd get a lot of errors for errors
+ // where the init list type is wrong, e.g.
+ // std::initializer_list<void*> list = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ // FIXME: Emit a note if we hit the limit?
+ int ErrorCount = 0;
+ for (unsigned i = 0; i < NumInits && ErrorCount < 3; ++i) {
+ Element.setElementIndex(i);
+ ExprResult Init = S.Owned(InitList->getInit(i));
+ if (S.PerformCopyInitialization(Element, Init.get()->getExprLoc(), Init)
+ .isInvalid())
+ ++ErrorCount;
+ }
+ break;
+ }
}
PrintInitLocationNote(S, Entity);
@@ -5597,9 +5622,21 @@
OS << "list initialization checker failure";
break;
+ case FK_VariableLengthArrayHasInitializer:
+ OS << "variable length array has an initializer";
+ break;
+
case FK_PlaceholderType:
OS << "initializer expression isn't contextually valid";
break;
+
+ case FK_ListConstructorOverloadFailed:
+ OS << "list constructor overloading failed";
+ break;
+
+ case FK_InitListElementCopyFailure:
+ OS << "copy construction of initializer list element failed";
+ break;
}
OS << '\n';
return;
@@ -5721,6 +5758,10 @@
case SK_ProduceObjCObject:
OS << "Objective-C object retension";
break;
+
+ case SK_StdInitializerList:
+ OS << "std::initializer_list from initializer list";
+ break;
}
}
}
@@ -5729,25 +5770,83 @@
dump(llvm::errs());
}
-static void DiagnoseNarrowingInInitList(
- Sema& S, QualType EntityType, const Expr *InitE,
- bool Constant, const APValue &ConstantValue) {
- if (Constant) {
- S.Diag(InitE->getLocStart(),
+static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
+ QualType EntityType,
+ const Expr *PreInit,
+ const Expr *PostInit) {
+ if (Seq.step_begin() == Seq.step_end() || PreInit->isValueDependent())
+ return;
+
+ // A narrowing conversion can only appear as the final implicit conversion in
+ // an initialization sequence.
+ const InitializationSequence::Step &LastStep = Seq.step_end()[-1];
+ if (LastStep.Kind != InitializationSequence::SK_ConversionSequence)
+ return;
+
+ const ImplicitConversionSequence &ICS = *LastStep.ICS;
+ const StandardConversionSequence *SCS = 0;
+ switch (ICS.getKind()) {
+ case ImplicitConversionSequence::StandardConversion:
+ SCS = &ICS.Standard;
+ break;
+ case ImplicitConversionSequence::UserDefinedConversion:
+ SCS = &ICS.UserDefined.After;
+ break;
+ case ImplicitConversionSequence::AmbiguousConversion:
+ case ImplicitConversionSequence::EllipsisConversion:
+ case ImplicitConversionSequence::BadConversion:
+ return;
+ }
+
+ // Determine the type prior to the narrowing conversion. If a conversion
+ // operator was used, this may be different from both the type of the entity
+ // and of the pre-initialization expression.
+ QualType PreNarrowingType = PreInit->getType();
+ if (Seq.step_begin() + 1 != Seq.step_end())
+ PreNarrowingType = Seq.step_end()[-2].Type;
+
+ // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion.
+ APValue ConstantValue;
+ switch (SCS->getNarrowingKind(S.Context, PostInit, ConstantValue)) {
+ case NK_Not_Narrowing:
+ // No narrowing occurred.
+ return;
+
+ case NK_Type_Narrowing:
+ // This was a floating-to-integer conversion, which is always considered a
+ // narrowing conversion even if the value is a constant and can be
+ // represented exactly as an integer.
+ S.Diag(PostInit->getLocStart(),
+ S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt
+ ? diag::err_init_list_type_narrowing
+ : diag::warn_init_list_type_narrowing)
+ << PostInit->getSourceRange()
+ << PreNarrowingType.getLocalUnqualifiedType()
+ << EntityType.getLocalUnqualifiedType();
+ break;
+
+ case NK_Constant_Narrowing:
+ // A constant value was narrowed.
+ S.Diag(PostInit->getLocStart(),
S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt
? diag::err_init_list_constant_narrowing
: diag::warn_init_list_constant_narrowing)
- << InitE->getSourceRange()
+ << PostInit->getSourceRange()
<< ConstantValue.getAsString(S.getASTContext(), EntityType)
<< EntityType.getLocalUnqualifiedType();
- } else
- S.Diag(InitE->getLocStart(),
+ break;
+
+ case NK_Variable_Narrowing:
+ // A variable's value may have been narrowed.
+ S.Diag(PostInit->getLocStart(),
S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt
? diag::err_init_list_variable_narrowing
: diag::warn_init_list_variable_narrowing)
- << InitE->getSourceRange()
- << InitE->getType().getLocalUnqualifiedType()
+ << PostInit->getSourceRange()
+ << PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getLocalUnqualifiedType();
+ break;
+ }
llvm::SmallString<128> StaticCast;
llvm::raw_svector_ostream OS(StaticCast);
@@ -5767,11 +5866,11 @@
return;
}
OS << ">(";
- S.Diag(InitE->getLocStart(), diag::note_init_list_narrowing_override)
- << InitE->getSourceRange()
- << FixItHint::CreateInsertion(InitE->getLocStart(), OS.str())
+ S.Diag(PostInit->getLocStart(), diag::note_init_list_narrowing_override)
+ << PostInit->getSourceRange()
+ << FixItHint::CreateInsertion(PostInit->getLocStart(), OS.str())
<< FixItHint::CreateInsertion(
- S.getPreprocessor().getLocForEndOfToken(InitE->getLocEnd()), ")");
+ S.getPreprocessor().getLocForEndOfToken(PostInit->getLocEnd()), ")");
}
//===----------------------------------------------------------------------===//
@@ -5811,12 +5910,11 @@
InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
Init.release();
- bool Constant = false;
- APValue Result;
- if (TopLevelOfInitList &&
- Seq.endsWithNarrowing(Context, InitE, &Constant, &Result)) {
- DiagnoseNarrowingInInitList(*this, Entity.getType(), InitE,
- Constant, Result);
- }
- return Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1));
+ ExprResult Result = Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1));
+
+ if (!Result.isInvalid() && TopLevelOfInitList)
+ DiagnoseNarrowingInInitList(*this, Seq, Entity.getType(),
+ InitE, Result.get());
+
+ return Result;
}
Modified: cfe/branches/tooling/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaLookup.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaLookup.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaLookup.cpp Fri Jan 20 10:14:22 2012
@@ -1053,22 +1053,6 @@
return !R.empty();
}
-/// \brief Retrieve the previous declaration of D.
-static NamedDecl *getPreviousDeclaration(NamedDecl *D) {
- if (TagDecl *TD = dyn_cast<TagDecl>(D))
- return TD->getPreviousDeclaration();
- if (VarDecl *VD = dyn_cast<VarDecl>(D))
- return VD->getPreviousDeclaration();
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return FD->getPreviousDeclaration();
- if (RedeclarableTemplateDecl *RTD = dyn_cast<RedeclarableTemplateDecl>(D))
- return RTD->getPreviousDeclaration();
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
- return ID->getPreviousDeclaration();
-
- return 0;
-}
-
/// \brief Retrieve the visible declaration corresponding to D, if any.
///
/// This routine determines whether the declaration D is visible in the current
@@ -1081,9 +1065,12 @@
if (LookupResult::isVisible(D))
return D;
- while ((D = getPreviousDeclaration(D))) {
- if (LookupResult::isVisible(D))
- return D;
+ for (Decl::redecl_iterator RD = D->redecls_begin(), RDEnd = D->redecls_end();
+ RD != RDEnd; ++RD) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*RD)) {
+ if (LookupResult::isVisible(ND))
+ return ND;
+ }
}
return 0;
@@ -1167,36 +1154,56 @@
// If this declaration is module-private and it came from an AST
// file, we can't see it.
- NamedDecl *D = getVisibleDecl(*I);
+ NamedDecl *D = R.isHiddenDeclarationVisible()? *I : getVisibleDecl(*I);
if (!D)
continue;
R.addDecl(D);
- if ((*I)->getAttr<OverloadableAttr>()) {
- // If this declaration has the "overloadable" attribute, we
- // might have a set of overloaded functions.
-
- // Figure out what scope the identifier is in.
- while (!(S->getFlags() & Scope::DeclScope) ||
- !S->isDeclScope(*I))
+ // Check whether there are any other declarations with the same name
+ // and in the same scope.
+ if (I != IEnd) {
+ // Find the scope in which this declaration was declared (if it
+ // actually exists in a Scope).
+ while (S && !S->isDeclScope(D))
S = S->getParent();
-
- // Find the last declaration in this scope (with the same
- // name, naturally).
+
+ // If the scope containing the declaration is the translation unit,
+ // then we'll need to perform our checks based on the matching
+ // DeclContexts rather than matching scopes.
+ if (S && isNamespaceOrTranslationUnitScope(S))
+ S = 0;
+
+ // Compute the DeclContext, if we need it.
+ DeclContext *DC = 0;
+ if (!S)
+ DC = (*I)->getDeclContext()->getRedeclContext();
+
IdentifierResolver::iterator LastI = I;
for (++LastI; LastI != IEnd; ++LastI) {
- if (!S->isDeclScope(*LastI))
- break;
+ if (S) {
+ // Match based on scope.
+ if (!S->isDeclScope(*LastI))
+ break;
+ } else {
+ // Match based on DeclContext.
+ DeclContext *LastDC
+ = (*LastI)->getDeclContext()->getRedeclContext();
+ if (!LastDC->Equals(DC))
+ break;
+ }
- D = getVisibleDecl(*LastI);
+ // If the declaration isn't in the right namespace, skip it.
+ if (!(*LastI)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ D = R.isHiddenDeclarationVisible()? *LastI : getVisibleDecl(*LastI);
if (D)
R.addDecl(D);
}
- }
-
- R.resolveKind();
+ R.resolveKind();
+ }
return true;
}
} else {
@@ -2176,9 +2183,10 @@
/// \brief Find the protocol with the given name, if any.
ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II,
- SourceLocation IdLoc) {
+ SourceLocation IdLoc,
+ RedeclarationKind Redecl) {
Decl *D = LookupSingleName(TUScope, II, IdLoc,
- LookupObjCProtocolName);
+ LookupObjCProtocolName, Redecl);
return cast_or_null<ObjCProtocolDecl>(D);
}
@@ -2534,7 +2542,7 @@
FunctionDecl *Cursor = NewFD;
while (true) {
- Cursor = Cursor->getPreviousDeclaration();
+ Cursor = Cursor->getPreviousDecl();
// If we got to the end without finding OldFD, OldFD is the newer
// declaration; leave things as they are.
@@ -2752,8 +2760,10 @@
Result.getSema().ForceDeclarationOfImplicitMembers(Class);
// Enumerate all of the results in this context.
- for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
- CurCtx = CurCtx->getNextContext()) {
+ llvm::SmallVector<DeclContext *, 2> Contexts;
+ Ctx->collectAllContexts(Contexts);
+ for (unsigned I = 0, N = Contexts.size(); I != N; ++I) {
+ DeclContext *CurCtx = Contexts[I];
for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
DEnd = CurCtx->decls_end();
D != DEnd; ++D) {
@@ -2762,24 +2772,6 @@
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
Visited.add(ND);
}
- } else if (ObjCForwardProtocolDecl *ForwardProto
- = dyn_cast<ObjCForwardProtocolDecl>(*D)) {
- for (ObjCForwardProtocolDecl::protocol_iterator
- P = ForwardProto->protocol_begin(),
- PEnd = ForwardProto->protocol_end();
- P != PEnd;
- ++P) {
- if (NamedDecl *ND = Result.getAcceptableDecl(*P)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
- Visited.add(ND);
- }
- }
- } else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) {
- ObjCInterfaceDecl *IFace = Class->getForwardInterfaceDecl();
- if (NamedDecl *ND = Result.getAcceptableDecl(IFace)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
- Visited.add(ND);
- }
}
// Visit transparent contexts and inline namespaces inside this context.
@@ -3338,13 +3330,13 @@
Scope *S, CXXScopeSpec *SS,
DeclContext *MemberContext,
bool EnteringContext,
- Sema::CorrectTypoContext CTC) {
+ bool isObjCIvarLookup) {
Res.suppressDiagnostics();
Res.clear();
Res.setLookupName(Name);
if (MemberContext) {
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(MemberContext)) {
- if (CTC == Sema::CTC_ObjCIvarLookup) {
+ if (isObjCIvarLookup) {
if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(Name)) {
Res.addDecl(Ivar);
Res.resolveKind();
@@ -3385,61 +3377,11 @@
/// \brief Add keywords to the consumer as possible typo corrections.
static void AddKeywordsToConsumer(Sema &SemaRef,
TypoCorrectionConsumer &Consumer,
- Scope *S, Sema::CorrectTypoContext CTC) {
- // Add context-dependent keywords.
- bool WantTypeSpecifiers = false;
- bool WantExpressionKeywords = false;
- bool WantCXXNamedCasts = false;
- bool WantRemainingKeywords = false;
- switch (CTC) {
- case Sema::CTC_Unknown:
- WantTypeSpecifiers = true;
- WantExpressionKeywords = true;
- WantCXXNamedCasts = true;
- WantRemainingKeywords = true;
-
- if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl())
- if (Method->getClassInterface() &&
- Method->getClassInterface()->getSuperClass())
- Consumer.addKeywordResult("super");
-
- break;
-
- case Sema::CTC_NoKeywords:
- break;
+ Scope *S, CorrectionCandidateCallback &CCC) {
+ if (CCC.WantObjCSuper)
+ Consumer.addKeywordResult("super");
- case Sema::CTC_Type:
- WantTypeSpecifiers = true;
- break;
-
- case Sema::CTC_ObjCMessageReceiver:
- Consumer.addKeywordResult("super");
- // Fall through to handle message receivers like expressions.
-
- case Sema::CTC_Expression:
- if (SemaRef.getLangOptions().CPlusPlus)
- WantTypeSpecifiers = true;
- WantExpressionKeywords = true;
- // Fall through to get C++ named casts.
-
- case Sema::CTC_CXXCasts:
- WantCXXNamedCasts = true;
- break;
-
- case Sema::CTC_ObjCPropertyLookup:
- // FIXME: Add "isa"?
- break;
-
- case Sema::CTC_MemberLookup:
- if (SemaRef.getLangOptions().CPlusPlus)
- Consumer.addKeywordResult("template");
- break;
-
- case Sema::CTC_ObjCIvarLookup:
- break;
- }
-
- if (WantTypeSpecifiers) {
+ if (CCC.WantTypeSpecifiers) {
// Add type-specifier keywords to the set of results.
const char *CTypeSpecs[] = {
"char", "const", "double", "enum", "float", "int", "long", "short",
@@ -3478,14 +3420,14 @@
Consumer.addKeywordResult("typeof");
}
- if (WantCXXNamedCasts && SemaRef.getLangOptions().CPlusPlus) {
+ if (CCC.WantCXXNamedCasts && SemaRef.getLangOptions().CPlusPlus) {
Consumer.addKeywordResult("const_cast");
Consumer.addKeywordResult("dynamic_cast");
Consumer.addKeywordResult("reinterpret_cast");
Consumer.addKeywordResult("static_cast");
}
- if (WantExpressionKeywords) {
+ if (CCC.WantExpressionKeywords) {
Consumer.addKeywordResult("sizeof");
if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus) {
Consumer.addKeywordResult("false");
@@ -3511,7 +3453,7 @@
}
}
- if (WantRemainingKeywords) {
+ if (CCC.WantRemainingKeywords) {
if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) {
// Statements.
const char *CStmts[] = {
@@ -3575,15 +3517,16 @@
/// \param SS the nested-name-specifier that precedes the name we're
/// looking for, if present.
///
+/// \param CCC A CorrectionCandidateCallback object that provides further
+/// validation of typo correction candidates. It also provides flags for
+/// determining the set of keywords permitted.
+///
/// \param MemberContext if non-NULL, the context in which to look for
/// a member access expression.
///
/// \param EnteringContext whether we're entering the context described by
/// the nested-name-specifier SS.
///
-/// \param CTC The context in which typo correction occurs, which impacts the
-/// set of keywords permitted.
-///
/// \param OPT when non-NULL, the search for visible declarations will
/// also walk the protocols in the qualified interfaces of \p OPT.
///
@@ -3594,9 +3537,9 @@
TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
Sema::LookupNameKind LookupKind,
Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback *CCC,
DeclContext *MemberContext,
bool EnteringContext,
- CorrectTypoContext CTC,
const ObjCObjectPointerType *OPT) {
if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking)
return TypoCorrection();
@@ -3656,7 +3599,8 @@
IsUnqualifiedLookup = true;
UnqualifiedTyposCorrectedMap::iterator Cached
= UnqualifiedTyposCorrected.find(Typo);
- if (Cached == UnqualifiedTyposCorrected.end()) {
+ if (Cached == UnqualifiedTyposCorrected.end() ||
+ (Cached->second && CCC && !CCC->ValidateCandidate(Cached->second))) {
// Provide a stop gap for files that are just seriously broken. Trying
// to correct all typos can turn into a HUGE performance penalty, causing
// some files to take minutes to get rejected by the parser.
@@ -3693,7 +3637,8 @@
}
}
- AddKeywordsToConsumer(*this, Consumer, S, CTC);
+ CorrectionCandidateCallback DefaultCCC;
+ AddKeywordsToConsumer(*this, Consumer, S, CCC ? *CCC : DefaultCCC);
// If we haven't found anything, we're done.
if (Consumer.empty()) {
@@ -3733,7 +3678,8 @@
Namespaces.AddNamespace(KNI->first);
}
- // Weed out any names that could not be found by name lookup.
+ // Weed out any names that could not be found by name lookup or, if a
+ // CorrectionCandidateCallback object was provided, failed validation.
llvm::SmallPtrSet<IdentifierInfo*, 16> QualifiedResults;
LookupResult TmpRes(*this, TypoName, LookupKind);
TmpRes.suppressDiagnostics();
@@ -3743,16 +3689,21 @@
for (TypoCorrectionConsumer::result_iterator I = DI->second->begin(),
IEnd = DI->second->end();
I != IEnd; /* Increment in loop. */) {
- // If the item already has been looked up or is a keyword, keep it
+ // If the item already has been looked up or is a keyword, keep it.
+ // If a validator callback object was given, drop the correction
+ // unless it passes validation.
if (I->second.isResolved()) {
+ TypoCorrectionConsumer::result_iterator Prev = I;
++I;
+ if (CCC && !CCC->ValidateCandidate(Prev->second))
+ DI->second->erase(Prev);
continue;
}
// Perform name lookup on this name.
IdentifierInfo *Name = I->second.getCorrectionAsIdentifierInfo();
LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext,
- EnteringContext, CTC);
+ EnteringContext, CCC && CCC->IsObjCIvarLookup);
switch (TmpRes.getResultKind()) {
case LookupResult::NotFound:
@@ -3774,20 +3725,28 @@
return TypoCorrection();
case LookupResult::FoundOverloaded: {
+ TypoCorrectionConsumer::result_iterator Prev = I;
// Store all of the Decls for overloaded symbols
for (LookupResult::iterator TRD = TmpRes.begin(),
TRDEnd = TmpRes.end();
TRD != TRDEnd; ++TRD)
I->second.addCorrectionDecl(*TRD);
++I;
+ if (CCC && !CCC->ValidateCandidate(Prev->second))
+ DI->second->erase(Prev);
break;
}
- case LookupResult::Found:
+ case LookupResult::Found: {
+ TypoCorrectionConsumer::result_iterator Prev = I;
I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
++I;
+ if (CCC && !CCC->ValidateCandidate(Prev->second))
+ DI->second->erase(Prev);
break;
}
+
+ }
}
if (DI->second->empty())
@@ -3818,6 +3777,8 @@
TmpRes.setLookupName(*QRI);
if (!LookupQualifiedName(TmpRes, Ctx)) continue;
+ // Any corrections added below will be validated in subsequent
+ // iterations of the main while() loop over the Consumer's contents.
switch (TmpRes.getResultKind()) {
case LookupResult::Found:
Consumer.addName((*QRI)->getName(), TmpRes.getAsSingle<NamedDecl>(),
@@ -3891,7 +3852,12 @@
return Result;
}
- else if (BestResults.size() > 1 && CTC == CTC_ObjCMessageReceiver
+ else if (BestResults.size() > 1
+ // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver;
+ // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for
+ // some instances of CTC_Unknown, while WantRemainingKeywords is true
+ // for CTC_Unknown but not for CTC_ObjCMessageReceiver.
+ && CCC && CCC->WantObjCSuper && !CCC->WantRemainingKeywords
&& BestResults["super"].isKeyword()) {
// Prefer 'super' when we're completing in a message-receiver
// context.
Modified: cfe/branches/tooling/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaObjCProperty.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaObjCProperty.cpp Fri Jan 20 10:14:22 2012
@@ -518,6 +518,33 @@
S.Diag(property->getLocation(), diag::note_property_declare);
}
+/// setImpliedPropertyAttributeForReadOnlyProperty -
+/// This routine evaludates life-time attributes for a 'readonly'
+/// property with no known lifetime of its own, using backing
+/// 'ivar's attribute, if any. If no backing 'ivar', property's
+/// life-time is assumed 'strong'.
+static void setImpliedPropertyAttributeForReadOnlyProperty(
+ ObjCPropertyDecl *property, ObjCIvarDecl *ivar) {
+ Qualifiers::ObjCLifetime propertyLifetime =
+ getImpliedARCOwnership(property->getPropertyAttributes(),
+ property->getType());
+ if (propertyLifetime != Qualifiers::OCL_None)
+ return;
+
+ if (!ivar) {
+ // if no backing ivar, make property 'strong'.
+ property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+ return;
+ }
+ // property assumes owenership of backing ivar.
+ QualType ivarType = ivar->getType();
+ Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
+ if (ivarLifetime == Qualifiers::OCL_Strong)
+ property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+ else if (ivarLifetime == Qualifiers::OCL_Weak)
+ property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
+ return;
+}
/// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared
@@ -608,11 +635,21 @@
// @synthesize
if (!PropertyIvar)
PropertyIvar = PropertyId;
- ObjCPropertyDecl::PropertyAttributeKind kind
- = property->getPropertyAttributes();
+ // Check that this is a previously declared 'ivar' in 'IDecl' interface
+ ObjCInterfaceDecl *ClassDeclared;
+ Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
QualType PropType = property->getType();
-
QualType PropertyIvarType = PropType.getNonReferenceType();
+
+ if (getLangOptions().ObjCAutoRefCount &&
+ (property->getPropertyAttributesAsWritten() &
+ ObjCPropertyDecl::OBJC_PR_readonly) &&
+ PropertyIvarType->isObjCRetainableType()) {
+ setImpliedPropertyAttributeForReadOnlyProperty(property, Ivar);
+ }
+
+ ObjCPropertyDecl::PropertyAttributeKind kind
+ = property->getPropertyAttributes();
// Add GC __weak to the ivar type if the property is weak.
if ((kind & ObjCPropertyDecl::OBJC_PR_weak) &&
@@ -627,9 +664,6 @@
}
}
- // Check that this is a previously declared 'ivar' in 'IDecl' interface
- ObjCInterfaceDecl *ClassDeclared;
- Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
if (!Ivar) {
// In ARC, give the ivar a lifetime qualifier based on the
// property attributes.
@@ -830,9 +864,13 @@
dyn_cast_or_null<CXXOperatorCallExpr>(callExpr))
if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())
if (!FuncDecl->isTrivial())
- Diag(PropertyLoc,
- diag::warn_atomic_property_nontrivial_assign_op)
+ if (property->getType()->isReferenceType()) {
+ Diag(PropertyLoc,
+ diag::err_atomic_property_nontrivial_assign_op)
<< property->getType();
+ Diag(FuncDecl->getLocStart(),
+ diag::note_callee_decl) << FuncDecl;
+ }
}
PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>());
}
@@ -856,7 +894,8 @@
}
IC->addPropertyImplementation(PIDecl);
if (getLangOptions().ObjCDefaultSynthProperties &&
- getLangOptions().ObjCNonFragileABI2) {
+ getLangOptions().ObjCNonFragileABI2 &&
+ !IDecl->isObjCRequiresPropertyDefs()) {
// Diagnose if an ivar was lazily synthesdized due to a previous
// use and if 1) property is @dynamic or 2) property is synthesized
// but it requires an ivar of different name.
@@ -1355,7 +1394,8 @@
if (!IC)
return;
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
- DefaultSynthesizeProperties(S, IC, IDecl);
+ if (!IDecl->isObjCRequiresPropertyDefs())
+ DefaultSynthesizeProperties(S, IC, IDecl);
}
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
@@ -1392,6 +1432,11 @@
<< Prop->getDeclName() << Prop->getGetterName();
Diag(Prop->getLocation(),
diag::note_property_declare);
+ if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2)
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
+ if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
+ Diag(RID->getLocation(), diag::note_suppressed_class_declare);
+
}
if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
@@ -1402,6 +1447,10 @@
<< Prop->getDeclName() << Prop->getSetterName();
Diag(Prop->getLocation(),
diag::note_property_declare);
+ if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2)
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
+ if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
+ Diag(RID->getLocation(), diag::note_suppressed_class_declare);
}
}
}
@@ -1666,6 +1715,21 @@
ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);
QualType PropertyTy = PropertyDecl->getType();
+ if (getLangOptions().ObjCAutoRefCount &&
+ (Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ PropertyTy->isObjCRetainableType()) {
+ // 'readonly' property with no obvious lifetime.
+ // its life time will be determined by its backing ivar.
+ unsigned rel = (ObjCDeclSpec::DQ_PR_unsafe_unretained |
+ ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong |
+ ObjCDeclSpec::DQ_PR_weak |
+ ObjCDeclSpec::DQ_PR_assign);
+ if ((Attributes & rel) == 0)
+ return;
+ }
+
// readonly and readwrite/assign/retain/copy conflict.
if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
(Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
@@ -1795,6 +1859,14 @@
// not specified; including when property is 'readonly'.
PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
else if (!(Attributes & ObjCDeclSpec::DQ_PR_readonly)) {
+ bool isAnyClassTy =
+ (PropertyTy->isObjCClassType() ||
+ PropertyTy->isObjCQualifiedClassType());
+ // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to
+ // issue any warning.
+ if (isAnyClassTy && getLangOptions().getGC() == LangOptions::NonGC)
+ ;
+ else {
// Skip this warning in gc-only mode.
if (getLangOptions().getGC() != LangOptions::GCOnly)
Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
@@ -1802,6 +1874,7 @@
// If non-gc code warn that this is likely inappropriate.
if (getLangOptions().getGC() == LangOptions::NonGC)
Diag(Loc, diag::warn_objc_property_default_assign_on_object);
+ }
}
// FIXME: Implement warning dependent on NSCopying being
Modified: cfe/branches/tooling/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaOverload.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaOverload.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaOverload.cpp Fri Jan 20 10:14:22 2012
@@ -258,6 +258,164 @@
return false;
}
+/// Skip any implicit casts which could be either part of a narrowing conversion
+/// or after one in an implicit conversion.
+static const Expr *IgnoreNarrowingConversion(const Expr *Converted) {
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Converted)) {
+ switch (ICE->getCastKind()) {
+ case CK_NoOp:
+ case CK_IntegralCast:
+ case CK_IntegralToBoolean:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingToBoolean:
+ case CK_FloatingCast:
+ Converted = ICE->getSubExpr();
+ continue;
+
+ default:
+ return Converted;
+ }
+ }
+
+ return Converted;
+}
+
+/// Check if this standard conversion sequence represents a narrowing
+/// conversion, according to C++11 [dcl.init.list]p7.
+///
+/// \param Ctx The AST context.
+/// \param Converted The result of applying this standard conversion sequence.
+/// \param ConstantValue If this is an NK_Constant_Narrowing conversion, the
+/// value of the expression prior to the narrowing conversion.
+NarrowingKind
+StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
+ const Expr *Converted,
+ APValue &ConstantValue) const {
+ assert(Ctx.getLangOptions().CPlusPlus && "narrowing check outside C++");
+
+ // C++11 [dcl.init.list]p7:
+ // A narrowing conversion is an implicit conversion ...
+ QualType FromType = getToType(0);
+ QualType ToType = getToType(1);
+ switch (Second) {
+ // -- from a floating-point type to an integer type, or
+ //
+ // -- from an integer type or unscoped enumeration type to a floating-point
+ // type, except where the source is a constant expression and the actual
+ // value after conversion will fit into the target type and will produce
+ // the original value when converted back to the original type, or
+ case ICK_Floating_Integral:
+ if (FromType->isRealFloatingType() && ToType->isIntegralType(Ctx)) {
+ return NK_Type_Narrowing;
+ } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) {
+ llvm::APSInt IntConstantValue;
+ const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ if (Initializer &&
+ Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) {
+ // Convert the integer to the floating type.
+ llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType));
+ Result.convertFromAPInt(IntConstantValue, IntConstantValue.isSigned(),
+ llvm::APFloat::rmNearestTiesToEven);
+ // And back.
+ llvm::APSInt ConvertedValue = IntConstantValue;
+ bool ignored;
+ Result.convertToInteger(ConvertedValue,
+ llvm::APFloat::rmTowardZero, &ignored);
+ // If the resulting value is different, this was a narrowing conversion.
+ if (IntConstantValue != ConvertedValue) {
+ ConstantValue = APValue(IntConstantValue);
+ return NK_Constant_Narrowing;
+ }
+ } else {
+ // Variables are always narrowings.
+ return NK_Variable_Narrowing;
+ }
+ }
+ return NK_Not_Narrowing;
+
+ // -- from long double to double or float, or from double to float, except
+ // where the source is a constant expression and the actual value after
+ // conversion is within the range of values that can be represented (even
+ // if it cannot be represented exactly), or
+ case ICK_Floating_Conversion:
+ if (FromType->isRealFloatingType() && ToType->isRealFloatingType() &&
+ Ctx.getFloatingTypeOrder(FromType, ToType) == 1) {
+ // FromType is larger than ToType.
+ const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ if (Initializer->isCXX11ConstantExpr(Ctx, &ConstantValue)) {
+ // Constant!
+ assert(ConstantValue.isFloat());
+ llvm::APFloat FloatVal = ConstantValue.getFloat();
+ // Convert the source value into the target type.
+ bool ignored;
+ llvm::APFloat::opStatus ConvertStatus = FloatVal.convert(
+ Ctx.getFloatTypeSemantics(ToType),
+ llvm::APFloat::rmNearestTiesToEven, &ignored);
+ // If there was no overflow, the source value is within the range of
+ // values that can be represented.
+ if (ConvertStatus & llvm::APFloat::opOverflow)
+ return NK_Constant_Narrowing;
+ } else {
+ return NK_Variable_Narrowing;
+ }
+ }
+ return NK_Not_Narrowing;
+
+ // -- from an integer type or unscoped enumeration type to an integer type
+ // that cannot represent all the values of the original type, except where
+ // the source is a constant expression and the actual value after
+ // conversion will fit into the target type and will produce the original
+ // value when converted back to the original type.
+ case ICK_Boolean_Conversion: // Bools are integers too.
+ if (!FromType->isIntegralOrUnscopedEnumerationType()) {
+ // Boolean conversions can be from pointers and pointers to members
+ // [conv.bool], and those aren't considered narrowing conversions.
+ return NK_Not_Narrowing;
+ } // Otherwise, fall through to the integral case.
+ case ICK_Integral_Conversion: {
+ assert(FromType->isIntegralOrUnscopedEnumerationType());
+ assert(ToType->isIntegralOrUnscopedEnumerationType());
+ const bool FromSigned = FromType->isSignedIntegerOrEnumerationType();
+ const unsigned FromWidth = Ctx.getIntWidth(FromType);
+ const bool ToSigned = ToType->isSignedIntegerOrEnumerationType();
+ const unsigned ToWidth = Ctx.getIntWidth(ToType);
+
+ if (FromWidth > ToWidth ||
+ (FromWidth == ToWidth && FromSigned != ToSigned)) {
+ // Not all values of FromType can be represented in ToType.
+ llvm::APSInt InitializerValue;
+ const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) {
+ ConstantValue = APValue(InitializerValue);
+
+ // Add a bit to the InitializerValue so we don't have to worry about
+ // signed vs. unsigned comparisons.
+ InitializerValue = InitializerValue.extend(
+ InitializerValue.getBitWidth() + 1);
+ // Convert the initializer to and from the target width and signed-ness.
+ llvm::APSInt ConvertedValue = InitializerValue;
+ ConvertedValue = ConvertedValue.trunc(ToWidth);
+ ConvertedValue.setIsSigned(ToSigned);
+ ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
+ ConvertedValue.setIsSigned(InitializerValue.isSigned());
+ // If the result is different, this was a narrowing conversion.
+ if (ConvertedValue != InitializerValue)
+ return NK_Constant_Narrowing;
+ } else {
+ // Variables are always narrowings.
+ return NK_Variable_Narrowing;
+ }
+ }
+ return NK_Not_Narrowing;
+ }
+
+ default:
+ // Other kinds of conversions are not narrowings.
+ return NK_Not_Narrowing;
+ }
+}
+
/// DebugPrint - Print this standard conversion sequence to standard
/// error. Useful for debugging overloading issues.
void StandardConversionSequence::DebugPrint() const {
@@ -541,7 +699,11 @@
}
void OverloadCandidateSet::clear() {
- inherited::clear();
+ for (iterator i = begin(), e = end(); i != e; ++i)
+ for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
+ i->Conversions[ii].~ImplicitConversionSequence();
+ NumInlineSequences = 0;
+ Candidates.clear();
Functions.clear();
}
@@ -824,6 +986,86 @@
return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable();
}
+/// \brief Tries a user-defined conversion from From to ToType.
+///
+/// Produces an implicit conversion sequence for when a standard conversion
+/// is not an option. See TryImplicitConversion for more information.
+static ImplicitConversionSequence
+TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool AllowExplicit,
+ bool InOverloadResolution,
+ bool CStyle,
+ bool AllowObjCWritebackConversion) {
+ ImplicitConversionSequence ICS;
+
+ if (SuppressUserConversions) {
+ // We're not in the case above, so there is no conversion that
+ // we can perform.
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
+ return ICS;
+ }
+
+ // Attempt user-defined conversion.
+ OverloadCandidateSet Conversions(From->getExprLoc());
+ OverloadingResult UserDefResult
+ = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
+ AllowExplicit);
+
+ if (UserDefResult == OR_Success) {
+ ICS.setUserDefined();
+ // C++ [over.ics.user]p4:
+ // A conversion of an expression of class type to the same class
+ // type is given Exact Match rank, and a conversion of an
+ // expression of class type to a base class of that type is
+ // given Conversion rank, in spite of the fact that a copy
+ // constructor (i.e., a user-defined conversion function) is
+ // called for those cases.
+ if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
+ QualType FromCanon
+ = S.Context.getCanonicalType(From->getType().getUnqualifiedType());
+ QualType ToCanon
+ = S.Context.getCanonicalType(ToType).getUnqualifiedType();
+ if (Constructor->isCopyConstructor() &&
+ (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
+ // Turn this into a "standard" conversion sequence, so that it
+ // gets ranked with standard conversion sequences.
+ ICS.setStandard();
+ ICS.Standard.setAsIdentityConversion();
+ ICS.Standard.setFromType(From->getType());
+ ICS.Standard.setAllToTypes(ToType);
+ ICS.Standard.CopyConstructor = Constructor;
+ if (ToCanon != FromCanon)
+ ICS.Standard.Second = ICK_Derived_To_Base;
+ }
+ }
+
+ // C++ [over.best.ics]p4:
+ // However, when considering the argument of a user-defined
+ // conversion function that is a candidate by 13.3.1.3 when
+ // invoked for the copying of the temporary in the second step
+ // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
+ // 13.3.1.6 in all cases, only standard conversion sequences and
+ // ellipsis conversion sequences are allowed.
+ if (SuppressUserConversions && ICS.isUserDefined()) {
+ ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
+ }
+ } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
+ ICS.setAmbiguous();
+ ICS.Ambiguous.setFromType(From->getType());
+ ICS.Ambiguous.setToType(ToType);
+ for (OverloadCandidateSet::iterator Cand = Conversions.begin();
+ Cand != Conversions.end(); ++Cand)
+ if (Cand->Viable)
+ ICS.Ambiguous.addConversion(Cand->Function);
+ } else {
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
+ }
+
+ return ICS;
+}
+
/// TryImplicitConversion - Attempt to perform an implicit conversion
/// from the given expression (Expr) to the given type (ToType). This
/// function returns an implicit conversion sequence that can be used
@@ -899,71 +1141,9 @@
return ICS;
}
- if (SuppressUserConversions) {
- // We're not in the case above, so there is no conversion that
- // we can perform.
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- return ICS;
- }
-
- // Attempt user-defined conversion.
- OverloadCandidateSet Conversions(From->getExprLoc());
- OverloadingResult UserDefResult
- = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
- AllowExplicit);
-
- if (UserDefResult == OR_Success) {
- ICS.setUserDefined();
- // C++ [over.ics.user]p4:
- // A conversion of an expression of class type to the same class
- // type is given Exact Match rank, and a conversion of an
- // expression of class type to a base class of that type is
- // given Conversion rank, in spite of the fact that a copy
- // constructor (i.e., a user-defined conversion function) is
- // called for those cases.
- if (CXXConstructorDecl *Constructor
- = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
- QualType FromCanon
- = S.Context.getCanonicalType(From->getType().getUnqualifiedType());
- QualType ToCanon
- = S.Context.getCanonicalType(ToType).getUnqualifiedType();
- if (Constructor->isCopyConstructor() &&
- (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
- // Turn this into a "standard" conversion sequence, so that it
- // gets ranked with standard conversion sequences.
- ICS.setStandard();
- ICS.Standard.setAsIdentityConversion();
- ICS.Standard.setFromType(From->getType());
- ICS.Standard.setAllToTypes(ToType);
- ICS.Standard.CopyConstructor = Constructor;
- if (ToCanon != FromCanon)
- ICS.Standard.Second = ICK_Derived_To_Base;
- }
- }
-
- // C++ [over.best.ics]p4:
- // However, when considering the argument of a user-defined
- // conversion function that is a candidate by 13.3.1.3 when
- // invoked for the copying of the temporary in the second step
- // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
- // 13.3.1.6 in all cases, only standard conversion sequences and
- // ellipsis conversion sequences are allowed.
- if (SuppressUserConversions && ICS.isUserDefined()) {
- ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
- }
- } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
- ICS.setAmbiguous();
- ICS.Ambiguous.setFromType(From->getType());
- ICS.Ambiguous.setToType(ToType);
- for (OverloadCandidateSet::iterator Cand = Conversions.begin();
- Cand != Conversions.end(); ++Cand)
- if (Cand->Viable)
- ICS.Ambiguous.addConversion(Cand->Function);
- } else {
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- }
-
- return ICS;
+ return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
+ AllowExplicit, InOverloadResolution, CStyle,
+ AllowObjCWritebackConversion);
}
ImplicitConversionSequence
@@ -2612,6 +2792,18 @@
// We're not going to find any constructors.
} else if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
+
+ Expr **Args = &From;
+ unsigned NumArgs = 1;
+ bool ListInitializing = false;
+ // If we're list-initializing, we pass the individual elements as
+ // arguments, not the entire list.
+ if (InitListExpr *InitList = dyn_cast<InitListExpr>(From)) {
+ Args = InitList->getInits();
+ NumArgs = InitList->getNumInits();
+ ListInitializing = true;
+ }
+
DeclContext::lookup_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = S.LookupConstructors(ToRecordDecl);
Con != ConEnd; ++Con) {
@@ -2628,28 +2820,33 @@
else
Constructor = cast<CXXConstructorDecl>(D);
- if (!Constructor->isInvalidDecl() &&
- Constructor->isConvertingConstructor(AllowExplicit)) {
+ bool Usable = !Constructor->isInvalidDecl();
+ if (ListInitializing)
+ Usable = Usable && (AllowExplicit || !Constructor->isExplicit());
+ else
+ Usable = Usable &&Constructor->isConvertingConstructor(AllowExplicit);
+ if (Usable) {
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
- &From, 1, CandidateSet,
+ Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/
- !ConstructorsOnly);
+ !ConstructorsOnly &&
+ !ListInitializing);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
S.AddOverloadCandidate(Constructor, FoundDecl,
- &From, 1, CandidateSet,
+ Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/
- !ConstructorsOnly);
+ !ConstructorsOnly && !ListInitializing);
}
}
}
}
// Enumerate conversion functions, if we're allowed to.
- if (ConstructorsOnly) {
+ if (ConstructorsOnly || isa<InitListExpr>(From)) {
} else if (S.RequireCompleteType(From->getLocStart(), From->getType(),
S.PDiag(0) << From->getSourceRange())) {
// No conversion functions from incomplete types.
@@ -2705,11 +2902,16 @@
// the argument of the constructor.
//
QualType ThisType = Constructor->getThisType(S.Context);
- if (Best->Conversions[0].isEllipsis())
- User.EllipsisConversion = true;
- else {
- User.Before = Best->Conversions[0].Standard;
- User.EllipsisConversion = false;
+ if (isa<InitListExpr>(From)) {
+ // Initializer lists don't have conversions as such.
+ User.Before.setAsIdentityConversion();
+ } else {
+ if (Best->Conversions[0].isEllipsis())
+ User.EllipsisConversion = true;
+ else {
+ User.Before = Best->Conversions[0].Standard;
+ User.EllipsisConversion = false;
+ }
}
User.HadMultipleCandidates = HadMultipleCandidates;
User.ConversionFunction = Constructor;
@@ -2718,7 +2920,8 @@
User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
User.After.setAllToTypes(ToType);
return OR_Success;
- } else if (CXXConversionDecl *Conversion
+ }
+ if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
S.MarkDeclarationReferenced(From->getLocStart(), Conversion);
@@ -2745,10 +2948,8 @@
// 13.3.3.1).
User.After = Best->FinalConversion;
return OR_Success;
- } else {
- llvm_unreachable("Not a constructor or conversion function?");
- return OR_No_Viable_Function;
}
+ llvm_unreachable("Not a constructor or conversion function?");
case OR_No_Viable_Function:
return OR_No_Viable_Function;
@@ -2760,7 +2961,7 @@
return OR_Ambiguous;
}
- return OR_No_Viable_Function;
+ llvm_unreachable("Invalid OverloadResult!");
}
bool
@@ -2808,7 +3009,7 @@
// from any other user-defined conversion sequence.
if (ICS1.getKindRank() < ICS2.getKindRank())
return ImplicitConversionSequence::Better;
- else if (ICS2.getKindRank() < ICS1.getKindRank())
+ if (ICS2.getKindRank() < ICS1.getKindRank())
return ImplicitConversionSequence::Worse;
// The following checks require both conversion sequences to be of
@@ -3620,7 +3821,7 @@
return false;
}
- return false;
+ llvm_unreachable("Invalid OverloadResult!");
}
/// \brief Compute an implicit conversion sequence for reference
@@ -3910,15 +4111,42 @@
Result.setBad(BadConversionSequence::no_conversion, From, ToType);
Result.setListInitializationSequence();
+ // We need a complete type for what follows. Incomplete types can bever be
+ // initialized from init lists.
+ if (S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag()))
+ return Result;
+
// C++11 [over.ics.list]p2:
// If the parameter type is std::initializer_list<X> or "array of X" and
// all the elements can be implicitly converted to X, the implicit
// conversion sequence is the worst conversion necessary to convert an
// element of the list to X.
- // FIXME: Recognize std::initializer_list.
- // FIXME: Arrays don't make sense until we can deal with references.
+ QualType X;
if (ToType->isArrayType())
+ X = S.Context.getBaseElementType(ToType);
+ else
+ (void)S.isStdInitializerList(ToType, &X);
+ if (!X.isNull()) {
+ for (unsigned i = 0, e = From->getNumInits(); i < e; ++i) {
+ Expr *Init = From->getInit(i);
+ ImplicitConversionSequence ICS =
+ TryCopyInitialization(S, Init, X, SuppressUserConversions,
+ InOverloadResolution,
+ AllowObjCWritebackConversion);
+ // If a single element isn't convertible, fail.
+ if (ICS.isBad()) {
+ Result = ICS;
+ break;
+ }
+ // Otherwise, look for the worst conversion.
+ if (Result.isBad() ||
+ CompareImplicitConversionSequences(S, ICS, Result) ==
+ ImplicitConversionSequence::Worse)
+ Result = ICS;
+ }
+ Result.setListInitializationSequence();
return Result;
+ }
// C++11 [over.ics.list]p3:
// Otherwise, if the parameter is a non-aggregate class X and overload
@@ -3926,9 +4154,15 @@
// conversion sequence is a user-defined conversion sequence. If multiple
// constructors are viable but none is better than the others, the
// implicit conversion sequence is a user-defined conversion sequence.
- // FIXME: Implement this.
- if (ToType->isRecordType() && !ToType->isAggregateType())
+ if (ToType->isRecordType() && !ToType->isAggregateType()) {
+ // This function can deal with initializer lists.
+ Result = TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ InOverloadResolution, /*CStyle=*/false,
+ AllowObjCWritebackConversion);
+ Result.setListInitializationSequence();
return Result;
+ }
// C++11 [over.ics.list]p4:
// Otherwise, if the parameter has an aggregate type which can be
@@ -4029,7 +4263,6 @@
// - if the initializer list has one element, the implicit conversion
// sequence is the one required to convert the element to the
// parameter type.
- // FIXME: Catch narrowing here?
unsigned NumInits = From->getNumInits();
if (NumInits == 1)
Result = TryCopyInitialization(S, From->getInit(0), ToType,
@@ -4299,6 +4532,167 @@
return ExprError();
}
+/// Check that the specified conversion is permitted in a converted constant
+/// expression, according to C++11 [expr.const]p3. Return true if the conversion
+/// is acceptable.
+static bool CheckConvertedConstantConversions(Sema &S,
+ StandardConversionSequence &SCS) {
+ // Since we know that the target type is an integral or unscoped enumeration
+ // type, most conversion kinds are impossible. All possible First and Third
+ // conversions are fine.
+ switch (SCS.Second) {
+ case ICK_Identity:
+ case ICK_Integral_Promotion:
+ case ICK_Integral_Conversion:
+ return true;
+
+ case ICK_Boolean_Conversion:
+ // Conversion from an integral or unscoped enumeration type to bool is
+ // classified as ICK_Boolean_Conversion, but it's also an integral
+ // conversion, so it's permitted in a converted constant expression.
+ return SCS.getFromType()->isIntegralOrUnscopedEnumerationType() &&
+ SCS.getToType(2)->isBooleanType();
+
+ case ICK_Floating_Integral:
+ case ICK_Complex_Real:
+ return false;
+
+ case ICK_Lvalue_To_Rvalue:
+ case ICK_Array_To_Pointer:
+ case ICK_Function_To_Pointer:
+ case ICK_NoReturn_Adjustment:
+ case ICK_Qualification:
+ case ICK_Compatible_Conversion:
+ case ICK_Vector_Conversion:
+ case ICK_Vector_Splat:
+ case ICK_Derived_To_Base:
+ case ICK_Pointer_Conversion:
+ case ICK_Pointer_Member:
+ case ICK_Block_Pointer_Conversion:
+ case ICK_Writeback_Conversion:
+ case ICK_Floating_Promotion:
+ case ICK_Complex_Promotion:
+ case ICK_Complex_Conversion:
+ case ICK_Floating_Conversion:
+ case ICK_TransparentUnionConversion:
+ llvm_unreachable("unexpected second conversion kind");
+
+ case ICK_Num_Conversion_Kinds:
+ break;
+ }
+
+ llvm_unreachable("unknown conversion kind");
+}
+
+/// CheckConvertedConstantExpression - Check that the expression From is a
+/// converted constant expression of type T, perform the conversion and produce
+/// the converted expression, per C++11 [expr.const]p3.
+ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
+ llvm::APSInt &Value,
+ CCEKind CCE) {
+ assert(LangOpts.CPlusPlus0x && "converted constant expression outside C++11");
+ assert(T->isIntegralOrEnumerationType() && "unexpected converted const type");
+
+ if (checkPlaceholderForOverload(*this, From))
+ return ExprError();
+
+ // C++11 [expr.const]p3 with proposed wording fixes:
+ // A converted constant expression of type T is a core constant expression,
+ // implicitly converted to a prvalue of type T, where the converted
+ // expression is a literal constant expression and the implicit conversion
+ // sequence contains only user-defined conversions, lvalue-to-rvalue
+ // conversions, integral promotions, and integral conversions other than
+ // narrowing conversions.
+ ImplicitConversionSequence ICS =
+ TryImplicitConversion(From, T,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*InOverloadResolution=*/false,
+ /*CStyle=*/false,
+ /*AllowObjcWritebackConversion=*/false);
+ StandardConversionSequence *SCS = 0;
+ switch (ICS.getKind()) {
+ case ImplicitConversionSequence::StandardConversion:
+ if (!CheckConvertedConstantConversions(*this, ICS.Standard))
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_converted_constant_expression_disallowed)
+ << From->getType() << From->getSourceRange() << T;
+ SCS = &ICS.Standard;
+ break;
+ case ImplicitConversionSequence::UserDefinedConversion:
+ // We are converting from class type to an integral or enumeration type, so
+ // the Before sequence must be trivial.
+ if (!CheckConvertedConstantConversions(*this, ICS.UserDefined.After))
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_converted_constant_expression_disallowed)
+ << From->getType() << From->getSourceRange() << T;
+ SCS = &ICS.UserDefined.After;
+ break;
+ case ImplicitConversionSequence::AmbiguousConversion:
+ case ImplicitConversionSequence::BadConversion:
+ if (!DiagnoseMultipleUserDefinedConversion(From, T))
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_converted_constant_expression)
+ << From->getType() << From->getSourceRange() << T;
+ return ExprError();
+
+ case ImplicitConversionSequence::EllipsisConversion:
+ llvm_unreachable("ellipsis conversion in converted constant expression");
+ }
+
+ ExprResult Result = PerformImplicitConversion(From, T, ICS, AA_Converting);
+ if (Result.isInvalid())
+ return Result;
+
+ // Check for a narrowing implicit conversion.
+ APValue PreNarrowingValue;
+ switch (SCS->getNarrowingKind(Context, Result.get(), PreNarrowingValue)) {
+ case NK_Variable_Narrowing:
+ // Implicit conversion to a narrower type, and the value is not a constant
+ // expression. We'll diagnose this in a moment.
+ case NK_Not_Narrowing:
+ break;
+
+ case NK_Constant_Narrowing:
+ Diag(From->getSourceRange().getBegin(), diag::err_cce_narrowing)
+ << CCE << /*Constant*/1
+ << PreNarrowingValue.getAsString(Context, QualType()) << T;
+ break;
+
+ case NK_Type_Narrowing:
+ Diag(From->getSourceRange().getBegin(), diag::err_cce_narrowing)
+ << CCE << /*Constant*/0 << From->getType() << T;
+ break;
+ }
+
+ // Check the expression is a constant expression.
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ Expr::EvalResult Eval;
+ Eval.Diag = &Notes;
+
+ if (!Result.get()->EvaluateAsRValue(Eval, Context)) {
+ // The expression can't be folded, so we can't keep it at this position in
+ // the AST.
+ Result = ExprError();
+ } else if (Notes.empty()) {
+ // It's a constant expression.
+ Value = Eval.Val.getInt();
+ return Result;
+ }
+
+ // It's not a constant expression. Produce an appropriate diagnostic.
+ if (Notes.size() == 1 &&
+ Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr)
+ Diag(Notes[0].first, diag::err_expr_not_cce) << CCE;
+ else {
+ Diag(From->getSourceRange().getBegin(), diag::err_expr_not_cce)
+ << CCE << From->getSourceRange();
+ for (unsigned I = 0; I < Notes.size(); ++I)
+ Diag(Notes[I].first, Notes[I].second);
+ }
+ return ExprError();
+}
+
/// dropPointerConversions - If the given standard conversion sequence
/// involves any pointer conversions, remove them. This may change
/// the result type of the conversion sequence.
@@ -4601,8 +4995,7 @@
}
// Add this candidate
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate& Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(NumArgs);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Function;
Candidate.Viable = true;
@@ -4646,7 +5039,6 @@
// Determine the implicit conversion sequences for each of the
// arguments.
- Candidate.Conversions.resize(NumArgs);
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
if (ArgIdx < NumArgsInProto) {
// (C++ 13.3.2p3): for F to be a viable function, there shall
@@ -4769,8 +5161,7 @@
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate& Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(NumArgs + 1);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Method;
Candidate.IsSurrogate = false;
@@ -4802,7 +5193,6 @@
}
Candidate.Viable = true;
- Candidate.Conversions.resize(NumArgs + 1);
if (Method->isStatic() || ObjectType.isNull())
// The implicit object argument is ignored.
@@ -4879,8 +5269,7 @@
if (TemplateDeductionResult Result
= DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs,
Args, NumArgs, Specialization, Info)) {
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate &Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
Candidate.FoundDecl = FoundDecl;
Candidate.Function = MethodTmpl->getTemplatedDecl();
Candidate.Viable = false;
@@ -4930,8 +5319,7 @@
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
Args, NumArgs, Specialization, Info)) {
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate &Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
@@ -4973,8 +5361,7 @@
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate& Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(1);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Conversion;
Candidate.IsSurrogate = false;
@@ -4983,7 +5370,6 @@
Candidate.FinalConversion.setFromType(ConvType);
Candidate.FinalConversion.setAllToTypes(ToType);
Candidate.Viable = true;
- Candidate.Conversions.resize(1);
Candidate.ExplicitCallArguments = 1;
// C++ [over.match.funcs]p4:
@@ -5117,8 +5503,7 @@
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ToType,
Specialization, Info)) {
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate &Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
@@ -5156,15 +5541,13 @@
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate& Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(NumArgs + 1);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = 0;
Candidate.Surrogate = Conversion;
Candidate.Viable = true;
Candidate.IsSurrogate = true;
Candidate.IgnoreObjectArgument = false;
- Candidate.Conversions.resize(NumArgs + 1);
Candidate.ExplicitCallArguments = NumArgs;
// Determine the implicit conversion sequence for the implicit
@@ -5309,8 +5692,7 @@
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate& Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(NumArgs);
Candidate.FoundDecl = DeclAccessPair::make(0, AS_none);
Candidate.Function = 0;
Candidate.IsSurrogate = false;
@@ -5322,7 +5704,6 @@
// Determine the implicit conversion sequences for each of the
// arguments.
Candidate.Viable = true;
- Candidate.Conversions.resize(NumArgs);
Candidate.ExplicitCallArguments = NumArgs;
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
// C++ [over.match.oper]p4:
@@ -6985,8 +7366,8 @@
// A viable function F1 is defined to be a better function than another
// viable function F2 if for all arguments i, ICSi(F1) is not a worse
// conversion sequence than ICSi(F2), and then...
- unsigned NumArgs = Cand1.Conversions.size();
- assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch");
+ unsigned NumArgs = Cand1.NumConversions;
+ assert(Cand2.NumConversions == NumArgs && "Overload candidate mismatch");
bool HasBetterConversion = false;
for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
switch (CompareImplicitConversionSequences(S,
@@ -7440,9 +7821,8 @@
<< (unsigned) (Cand->Fix.Kind);
// If we can fix the conversion, suggest the FixIts.
- for (SmallVector<FixItHint, 1>::iterator
- HI = Cand->Fix.Hints.begin(), HE = Cand->Fix.Hints.end();
- HI != HE; ++HI)
+ for (std::vector<FixItHint>::iterator HI = Cand->Fix.Hints.begin(),
+ HE = Cand->Fix.Hints.end(); HI != HE; ++HI)
FDiag << *HI;
S.Diag(Fn->getLocation(), FDiag);
@@ -7685,7 +8065,7 @@
case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
- for (unsigned N = Cand->Conversions.size(); I != N; ++I)
+ for (unsigned N = Cand->NumConversions; I != N; ++I)
if (Cand->Conversions[I].isBad())
return DiagnoseBadConversion(S, Cand, I);
@@ -7737,12 +8117,12 @@
const char *Opc,
SourceLocation OpLoc,
OverloadCandidate *Cand) {
- assert(Cand->Conversions.size() <= 2 && "builtin operator is not binary");
+ assert(Cand->NumConversions <= 2 && "builtin operator is not binary");
std::string TypeStr("operator");
TypeStr += Opc;
TypeStr += "(";
TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
- if (Cand->Conversions.size() == 1) {
+ if (Cand->NumConversions == 1) {
TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
} else {
@@ -7755,7 +8135,7 @@
void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
OverloadCandidate *Cand) {
- unsigned NoOperands = Cand->Conversions.size();
+ unsigned NoOperands = Cand->NumConversions;
for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
if (ICS.isBad()) break; // all meaningless after first invalid
@@ -7859,11 +8239,11 @@
// If there's any ordering between the defined conversions...
// FIXME: this might not be transitive.
- assert(L->Conversions.size() == R->Conversions.size());
+ assert(L->NumConversions == R->NumConversions);
int leftBetter = 0;
unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument);
- for (unsigned E = L->Conversions.size(); I != E; ++I) {
+ for (unsigned E = L->NumConversions; I != E; ++I) {
switch (CompareImplicitConversionSequences(S,
L->Conversions[I],
R->Conversions[I])) {
@@ -7926,7 +8306,7 @@
// Skip forward to the first bad conversion.
unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
- unsigned ConvCount = Cand->Conversions.size();
+ unsigned ConvCount = Cand->NumConversions;
while (true) {
assert(ConvIdx != ConvCount && "no bad conversion in candidate");
ConvIdx++;
@@ -8812,10 +9192,13 @@
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
+ CorrectionCandidateCallback Validator;
+ Validator.WantTypeSpecifiers = SemaRef.getLangOptions().CPlusPlus;
+ Validator.WantRemainingKeywords = false;
if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
ExplicitTemplateArgs, Args, NumArgs) &&
(!EmptyLookup ||
- SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression,
+ SemaRef.DiagnoseEmptyLookup(S, SS, R, Validator,
ExplicitTemplateArgs, Args, NumArgs)))
return ExprError();
@@ -8957,7 +9340,6 @@
return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs,
RParenLoc, ExecConfig);
}
- break;
}
// Overload resolution failed.
@@ -10355,6 +10737,7 @@
SourceLocation Loc = MemExpr->getMemberLoc();
if (MemExpr->getQualifier())
Loc = MemExpr->getQualifierLoc().getBeginLoc();
+ CheckCXXThisCapture(Loc);
Base = new (Context) CXXThisExpr(Loc,
MemExpr->getBaseType(),
/*isImplicit=*/true);
@@ -10385,7 +10768,6 @@
}
llvm_unreachable("Invalid reference to overloaded function");
- return E;
}
ExprResult Sema::FixOverloadedFunctionReference(ExprResult E,
Modified: cfe/branches/tooling/lib/Sema/SemaPseudoObject.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaPseudoObject.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaPseudoObject.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaPseudoObject.cpp Fri Jan 20 10:14:22 2012
@@ -492,11 +492,9 @@
assert(Getter);
QualType receiverType;
- SourceLocation superLoc;
if (RefExpr->isClassReceiver()) {
receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver());
} else if (RefExpr->isSuperReceiver()) {
- superLoc = RefExpr->getReceiverLocation();
receiverType = RefExpr->getSuperReceiverType();
} else {
assert(InstanceReceiver);
@@ -507,19 +505,14 @@
ExprResult msg;
if (Getter->isInstanceMethod() || RefExpr->isObjectReceiver()) {
assert(InstanceReceiver || RefExpr->isSuperReceiver());
- msg = S.BuildInstanceMessage(InstanceReceiver, receiverType, superLoc,
- Getter->getSelector(), Getter,
- GenericLoc, GenericLoc, GenericLoc,
- MultiExprArg());
+ msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType,
+ GenericLoc, Getter->getSelector(),
+ Getter, MultiExprArg());
} else {
- TypeSourceInfo *receiverTypeInfo = 0;
- if (!RefExpr->isSuperReceiver())
- receiverTypeInfo = S.Context.getTrivialTypeSourceInfo(receiverType);
-
- msg = S.BuildClassMessage(receiverTypeInfo, receiverType, superLoc,
- Getter->getSelector(), Getter,
- GenericLoc, GenericLoc, GenericLoc,
- MultiExprArg());
+ msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(),
+ GenericLoc,
+ Getter->getSelector(), Getter,
+ MultiExprArg());
}
return msg;
}
@@ -534,11 +527,9 @@
assert(hasSetter); (void) hasSetter;
QualType receiverType;
- SourceLocation superLoc;
if (RefExpr->isClassReceiver()) {
receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver());
} else if (RefExpr->isSuperReceiver()) {
- superLoc = RefExpr->getReceiverLocation();
receiverType = RefExpr->getSuperReceiverType();
} else {
assert(InstanceReceiver);
@@ -570,19 +561,14 @@
// Build a message-send.
ExprResult msg;
if (Setter->isInstanceMethod() || RefExpr->isObjectReceiver()) {
- msg = S.BuildInstanceMessage(InstanceReceiver, receiverType, superLoc,
- SetterSelector, Setter,
- GenericLoc, GenericLoc, GenericLoc,
- MultiExprArg(args, 1));
+ msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType,
+ GenericLoc, SetterSelector, Setter,
+ MultiExprArg(args, 1));
} else {
- TypeSourceInfo *receiverTypeInfo = 0;
- if (!RefExpr->isSuperReceiver())
- receiverTypeInfo = S.Context.getTrivialTypeSourceInfo(receiverType);
-
- msg = S.BuildClassMessage(receiverTypeInfo, receiverType, superLoc,
- SetterSelector, Setter,
- GenericLoc, GenericLoc, GenericLoc,
- MultiExprArg(args, 1));
+ msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(),
+ GenericLoc,
+ SetterSelector, Setter,
+ MultiExprArg(args, 1));
}
if (!msg.isInvalid() && captureSetValueAsResult) {
Modified: cfe/branches/tooling/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaStmt.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaStmt.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaStmt.cpp Fri Jan 20 10:14:22 2012
@@ -16,7 +16,6 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
-#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
@@ -153,7 +152,8 @@
SourceLocation Loc;
SourceRange R1, R2;
- if (!E->isUnusedResultAWarning(Loc, R1, R2, Context))
+ if (SourceMgr.isInSystemMacro(E->getExprLoc()) ||
+ !E->isUnusedResultAWarning(Loc, R1, R2, Context))
return;
// Okay, we have an unused result. Depending on what the base expression is,
@@ -266,24 +266,26 @@
SourceLocation ColonLoc) {
assert((LHSVal != 0) && "missing expression in case statement");
- // C99 6.8.4.2p3: The expression shall be an integer constant.
- // However, GCC allows any evaluatable integer expression.
- if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
- VerifyIntegerConstantExpression(LHSVal))
- return StmtError();
-
- // GCC extension: The expression shall be an integer constant.
-
- if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() &&
- VerifyIntegerConstantExpression(RHSVal)) {
- RHSVal = 0; // Recover by just forgetting about it.
- }
-
if (getCurFunction()->SwitchStack.empty()) {
Diag(CaseLoc, diag::err_case_not_in_switch);
return StmtError();
}
+ if (!getLangOptions().CPlusPlus0x) {
+ // C99 6.8.4.2p3: The expression shall be an integer constant.
+ // However, GCC allows any evaluatable integer expression.
+ if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
+ VerifyIntegerConstantExpression(LHSVal))
+ return StmtError();
+
+ // GCC extension: The expression shall be an integer constant.
+
+ if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() &&
+ VerifyIntegerConstantExpression(RHSVal)) {
+ RHSVal = 0; // Recover by just forgetting about it.
+ }
+ }
+
CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
ColonLoc);
getCurFunction()->SwitchStack.back()->addSwitchCase(CS);
@@ -622,8 +624,6 @@
} else {
CaseStmt *CS = cast<CaseStmt>(SC);
- // We already verified that the expression has a i-c-e value (C99
- // 6.8.4.2p3) - get that value now.
Expr *Lo = CS->getLHS();
if (Lo->isTypeDependent() || Lo->isValueDependent()) {
@@ -631,19 +631,39 @@
break;
}
- llvm::APSInt LoVal = Lo->EvaluateKnownConstInt(Context);
+ llvm::APSInt LoVal;
- // Convert the value to the same width/sign as the condition.
+ if (getLangOptions().CPlusPlus0x) {
+ // C++11 [stmt.switch]p2: the constant-expression shall be a converted
+ // constant expression of the promoted type of the switch condition.
+ ExprResult ConvLo =
+ CheckConvertedConstantExpression(Lo, CondType, LoVal, CCEK_CaseValue);
+ if (ConvLo.isInvalid()) {
+ CaseListIsErroneous = true;
+ continue;
+ }
+ Lo = ConvLo.take();
+ } else {
+ // We already verified that the expression has a i-c-e value (C99
+ // 6.8.4.2p3) - get that value now.
+ LoVal = Lo->EvaluateKnownConstInt(Context);
+
+ // If the LHS is not the same type as the condition, insert an implicit
+ // cast.
+ Lo = DefaultLvalueConversion(Lo).take();
+ Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take();
+ }
+
+ // Convert the value to the same width/sign as the condition had prior to
+ // integral promotions.
+ //
+ // FIXME: This causes us to reject valid code:
+ // switch ((char)c) { case 256: case 0: return 0; }
+ // Here we claim there is a duplicated condition value, but there is not.
ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
Lo->getLocStart(),
diag::warn_case_value_overflow);
- // If the LHS is not the same type as the condition, insert an implicit
- // cast.
- // FIXME: In C++11, the value is a converted constant expression of the
- // promoted type of the switch condition.
- Lo = DefaultLvalueConversion(Lo).take();
- Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take();
CS->setLHS(Lo);
// If this is a case range, remember it in CaseRanges, otherwise CaseVals.
@@ -664,20 +684,15 @@
// condition is constant.
llvm::APSInt ConstantCondValue;
bool HasConstantCond = false;
- bool ShouldCheckConstantCond = false;
if (!HasDependentValue && !TheDefaultStmt) {
- Expr::EvalResult Result;
HasConstantCond
- = CondExprBeforePromotion->EvaluateAsRValue(Result, Context);
- if (HasConstantCond) {
- assert(Result.Val.isInt() && "switch condition evaluated to non-int");
- ConstantCondValue = Result.Val.getInt();
- ShouldCheckConstantCond = true;
-
- assert(ConstantCondValue.getBitWidth() == CondWidth &&
- ConstantCondValue.isSigned() == CondIsSigned);
- }
+ = CondExprBeforePromotion->EvaluateAsInt(ConstantCondValue, Context,
+ Expr::SE_AllowSideEffects);
+ assert(!HasConstantCond ||
+ (ConstantCondValue.getBitWidth() == CondWidth &&
+ ConstantCondValue.isSigned() == CondIsSigned));
}
+ bool ShouldCheckConstantCond = HasConstantCond;
// Sort all the scalar case values so we can easily detect duplicates.
std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals);
@@ -714,19 +729,33 @@
llvm::APSInt &LoVal = CaseRanges[i].first;
CaseStmt *CR = CaseRanges[i].second;
Expr *Hi = CR->getRHS();
- llvm::APSInt HiVal = Hi->EvaluateKnownConstInt(Context);
+ llvm::APSInt HiVal;
+
+ if (getLangOptions().CPlusPlus0x) {
+ // C++11 [stmt.switch]p2: the constant-expression shall be a converted
+ // constant expression of the promoted type of the switch condition.
+ ExprResult ConvHi =
+ CheckConvertedConstantExpression(Hi, CondType, HiVal,
+ CCEK_CaseValue);
+ if (ConvHi.isInvalid()) {
+ CaseListIsErroneous = true;
+ continue;
+ }
+ Hi = ConvHi.take();
+ } else {
+ HiVal = Hi->EvaluateKnownConstInt(Context);
+
+ // If the RHS is not the same type as the condition, insert an
+ // implicit cast.
+ Hi = DefaultLvalueConversion(Hi).take();
+ Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take();
+ }
// Convert the value to the same width/sign as the condition.
ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
Hi->getLocStart(),
diag::warn_case_value_overflow);
- // If the RHS is not the same type as the condition, insert an implicit
- // cast.
- // FIXME: In C++11, the value is a converted constant expression of the
- // promoted type of the switch condition.
- Hi = DefaultLvalueConversion(Hi).take();
- Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take();
CR->setRHS(Hi);
// If the low value is bigger than the high value, the case is empty.
@@ -1169,7 +1198,7 @@
// Deduce the type for the iterator variable now rather than leaving it to
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
TypeSourceInfo *InitTSI = 0;
- if (Init->getType()->isVoidType() ||
+ if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) ||
!SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI))
SemaRef.Diag(Loc, diag) << Init->getType();
if (!InitTSI) {
@@ -1797,8 +1826,7 @@
QualType FnRetType = CurBlock->ReturnType;
if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
- Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
- << getCurFunctionOrMethodDecl()->getDeclName();
+ Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr);
return StmtError();
}
@@ -1875,7 +1903,7 @@
if (FD->hasAttr<NoReturnAttr>() ||
FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
- << getCurFunctionOrMethodDecl()->getDeclName();
+ << FD->getDeclName();
} else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
DeclaredRetType = MD->getResultType();
if (MD->hasRelatedResultType() && MD->getClassInterface()) {
Modified: cfe/branches/tooling/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaTemplate.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaTemplate.cpp Fri Jan 20 10:14:22 2012
@@ -249,6 +249,12 @@
isDependent = ObjectType->isDependentType();
assert((isDependent || !ObjectType->isIncompleteType()) &&
"Caller should have completed object type");
+
+ // Template names cannot appear inside an Objective-C class or object type.
+ if (ObjectType->isObjCObjectOrInterfaceType()) {
+ Found.clear();
+ return;
+ }
} else if (SS.isSet()) {
// This nested-name-specifier occurs after another nested-name-specifier,
// so long into the context associated with the prior nested-name-specifier.
@@ -295,10 +301,15 @@
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
Found.clear();
+ // Simple filter callback that, for keywords, only accepts the C++ *_cast
+ CorrectionCandidateCallback FilterCCC;
+ FilterCCC.WantTypeSpecifiers = false;
+ FilterCCC.WantExpressionKeywords = false;
+ FilterCCC.WantRemainingKeywords = false;
+ FilterCCC.WantCXXNamedCasts = true;
if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(),
Found.getLookupKind(), S, &SS,
- LookupCtx, false,
- CTC_CXXCasts)) {
+ &FilterCCC, LookupCtx)) {
Found.setLookupName(Corrected.getCorrection());
if (Corrected.getCorrectionDecl())
Found.addDecl(Corrected.getCorrectionDecl());
@@ -491,7 +502,6 @@
}
llvm_unreachable("Unhandled parsed template argument");
- return TemplateArgumentLoc();
}
/// \brief Translates template arguments as provided by the parser
@@ -1013,15 +1023,8 @@
NewClass, PrevClassTemplate);
NewClass->setDescribedClassTemplate(NewTemplate);
- if (PrevClassTemplate && PrevClassTemplate->isModulePrivate()) {
+ if (ModulePrivateLoc.isValid())
NewTemplate->setModulePrivate();
- } else if (ModulePrivateLoc.isValid()) {
- if (PrevClassTemplate && !PrevClassTemplate->isModulePrivate())
- diagnoseModulePrivateRedeclaration(NewTemplate, PrevClassTemplate,
- ModulePrivateLoc);
- else
- NewTemplate->setModulePrivate();
- }
// Build the type for the class template declaration now.
QualType T = NewTemplate->getInjectedClassNameSpecialization();
@@ -1135,7 +1138,7 @@
// declaration (and it is a definition). Strange!
}
- return false;
+ llvm_unreachable("Invalid TemplateParamListContext!");
}
/// \brief Check for unexpanded parameter packs within the template parameters
@@ -2785,7 +2788,6 @@
case TemplateArgument::Pack:
llvm_unreachable("Caller must expand template argument packs");
- break;
}
return false;
@@ -2835,17 +2837,12 @@
return true;
case TemplateArgument::Declaration:
- llvm_unreachable(
- "Declaration argument with template template parameter");
- break;
+ llvm_unreachable("Declaration argument with template template parameter");
case TemplateArgument::Integral:
- llvm_unreachable(
- "Integral argument with template template parameter");
- break;
+ llvm_unreachable("Integral argument with template template parameter");
case TemplateArgument::Pack:
llvm_unreachable("Caller must expand template argument packs");
- break;
}
return false;
@@ -3302,7 +3299,7 @@
case NestedNameSpecifier::TypeSpecWithTemplate:
return Visit(QualType(NNS->getAsType(), 0));
}
- return false;
+ llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
@@ -3740,14 +3737,70 @@
// template-argument cannot be converted to the type of the
// corresponding template-parameter then the program is
// ill-formed.
- //
- // -- for a non-type template-parameter of integral or
- // enumeration type, integral promotions (4.5) and integral
- // conversions (4.7) are applied.
QualType ParamType = InstantiatedParamType;
if (ParamType->isIntegralOrEnumerationType()) {
- // FIXME: In C++11, the argument is a converted constant expression of the
- // type of the template parameter.
+ // C++11:
+ // -- for a non-type template-parameter of integral or
+ // enumeration type, conversions permitted in a converted
+ // constant expression are applied.
+ //
+ // C++98:
+ // -- for a non-type template-parameter of integral or
+ // enumeration type, integral promotions (4.5) and integral
+ // conversions (4.7) are applied.
+
+ if (CTAK == CTAK_Deduced &&
+ !Context.hasSameUnqualifiedType(ParamType, Arg->getType())) {
+ // C++ [temp.deduct.type]p17:
+ // If, in the declaration of a function template with a non-type
+ // template-parameter, the non-type template-parameter is used
+ // in an expression in the function parameter-list and, if the
+ // corresponding template-argument is deduced, the
+ // template-argument type shall match the type of the
+ // template-parameter exactly, except that a template-argument
+ // deduced from an array bound may be of any integral type.
+ Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
+ << Arg->getType().getUnqualifiedType()
+ << ParamType.getUnqualifiedType();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return ExprError();
+ }
+
+ if (getLangOptions().CPlusPlus0x) {
+ // We can't check arbitrary value-dependent arguments.
+ // FIXME: If there's no viable conversion to the template parameter type,
+ // we should be able to diagnose that prior to instantiation.
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ return Owned(Arg);
+ }
+
+ // C++ [temp.arg.nontype]p1:
+ // A template-argument for a non-type, non-template template-parameter
+ // shall be one of:
+ //
+ // -- for a non-type template-parameter of integral or enumeration
+ // type, a converted constant expression of the type of the
+ // template-parameter; or
+ llvm::APSInt Value;
+ ExprResult ArgResult =
+ CheckConvertedConstantExpression(Arg, ParamType, Value,
+ CCEK_TemplateArg);
+ if (ArgResult.isInvalid())
+ return ExprError();
+
+ // Widen the argument value to sizeof(parameter type). This is almost
+ // always a no-op, except when the parameter type is bool. In
+ // that case, this may extend the argument from 1 bit to 8 bits.
+ QualType IntegerType = ParamType;
+ if (const EnumType *Enum = IntegerType->getAs<EnumType>())
+ IntegerType = Enum->getDecl()->getIntegerType();
+ Value = Value.extOrTrunc(Context.getTypeSize(IntegerType));
+
+ Converted = TemplateArgument(Value, Context.getCanonicalType(ParamType));
+ return ArgResult;
+ }
+
ExprResult ArgResult = DefaultLvalueConversion(Arg);
if (ArgResult.isInvalid())
return ExprError();
@@ -3785,19 +3838,6 @@
// Try to convert the argument to the parameter's type.
if (Context.hasSameType(ParamType, ArgType)) {
// Okay: no conversion necessary
- } else if (CTAK == CTAK_Deduced) {
- // C++ [temp.deduct.type]p17:
- // If, in the declaration of a function template with a non-type
- // template-parameter, the non-type template- parameter is used
- // in an expression in the function parameter-list and, if the
- // corresponding template-argument is deduced, the
- // template-argument type shall match the type of the
- // template-parameter exactly, except that a template-argument
- // deduced from an array bound may be of any integral type.
- Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
- << ArgType << ParamType;
- Diag(Param->getLocation(), diag::note_template_param_here);
- return ExprError();
} else if (ParamType->isBooleanType()) {
// This is an integral-to-boolean conversion.
Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralToBoolean).take();
@@ -4485,7 +4525,7 @@
/// \brief Determine what kind of template specialization the given declaration
/// is.
-static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) {
+static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D) {
if (!D)
return TSK_Undeclared;
@@ -4763,23 +4803,6 @@
return false;
}
-/// \brief Retrieve the previous declaration of the given declaration.
-static NamedDecl *getPreviousDecl(NamedDecl *ND) {
- if (VarDecl *VD = dyn_cast<VarDecl>(ND))
- return VD->getPreviousDeclaration();
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
- return FD->getPreviousDeclaration();
- if (TagDecl *TD = dyn_cast<TagDecl>(ND))
- return TD->getPreviousDeclaration();
- if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(ND))
- return TD->getPreviousDeclaration();
- if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
- return FTD->getPreviousDeclaration();
- if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(ND))
- return CTD->getPreviousDeclaration();
- return 0;
-}
-
DeclResult
Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TagUseKind TUK,
@@ -5110,7 +5133,7 @@
// use occurs; no diagnostic is required.
if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) {
bool Okay = false;
- for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) {
+ for (Decl *Prev = PrevDecl; Prev; Prev = Prev->getPreviousDecl()) {
// Is there any previous explicit specialization declaration?
if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) {
Okay = true;
@@ -5241,6 +5264,23 @@
}
}
+/// \brief Compute the diagnostic location for an explicit instantiation
+// declaration or definition.
+static SourceLocation DiagLocForExplicitInstantiation(
+ NamedDecl* D, SourceLocation PointOfInstantiation) {
+ // Explicit instantiations following a specialization have no effect and
+ // hence no PointOfInstantiation. In that case, walk decl backwards
+ // until a valid name loc is found.
+ SourceLocation PrevDiagLoc = PointOfInstantiation;
+ for (Decl *Prev = D; Prev && !PrevDiagLoc.isValid();
+ Prev = Prev->getPreviousDecl()) {
+ PrevDiagLoc = Prev->getLocation();
+ }
+ assert(PrevDiagLoc.isValid() &&
+ "Explicit instantiation without point of instantiation?");
+ return PrevDiagLoc;
+}
+
/// \brief Diagnose cases where we have an explicit template specialization
/// before/after an explicit template instantiation, producing diagnostics
/// for those cases where they are required and determining whether the
@@ -5307,7 +5347,7 @@
// before the first use of that specialization that would cause an
// implicit instantiation to take place, in every translation unit in
// which such a use occurs; no diagnostic is required.
- for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) {
+ for (Decl *Prev = PrevDecl; Prev; Prev = Prev->getPreviousDecl()) {
// Is there any previous explicit specialization declaration?
if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization)
return false;
@@ -5320,7 +5360,6 @@
return true;
}
- break;
case TSK_ExplicitInstantiationDeclaration:
switch (PrevTSK) {
@@ -5351,14 +5390,15 @@
// translation unit, the definition shall follow the declaration.
Diag(NewLoc,
diag::err_explicit_instantiation_declaration_after_definition);
- Diag(PrevPointOfInstantiation,
+
+ // Explicit instantiations following a specialization have no effect and
+ // hence no PrevPointOfInstantiation. In that case, walk decl backwards
+ // until a valid name loc is found.
+ Diag(DiagLocForExplicitInstantiation(PrevDecl, PrevPointOfInstantiation),
diag::note_explicit_instantiation_definition_here);
- assert(PrevPointOfInstantiation.isValid() &&
- "Explicit instantiation without point of instantiation?");
HasNoEffect = true;
return false;
}
- break;
case TSK_ExplicitInstantiationDefinition:
switch (PrevTSK) {
@@ -5390,6 +5430,20 @@
case TSK_ExplicitInstantiationDeclaration:
// We're explicity instantiating a definition for something for which we
// were previously asked to suppress instantiations. That's fine.
+
+ // C++0x [temp.explicit]p4:
+ // For a given set of template parameters, if an explicit instantiation
+ // of a template appears after a declaration of an explicit
+ // specialization for that template, the explicit instantiation has no
+ // effect.
+ for (Decl *Prev = PrevDecl; Prev; Prev = Prev->getPreviousDecl()) {
+ // Is there any previous explicit specialization declaration?
+ if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) {
+ HasNoEffect = true;
+ break;
+ }
+ }
+
return false;
case TSK_ExplicitInstantiationDefinition:
@@ -5399,12 +5453,11 @@
// in a program,
Diag(NewLoc, diag::err_explicit_instantiation_duplicate)
<< PrevDecl;
- Diag(PrevPointOfInstantiation,
+ Diag(DiagLocForExplicitInstantiation(PrevDecl, PrevPointOfInstantiation),
diag::note_previous_explicit_instantiation);
HasNoEffect = true;
return false;
}
- break;
}
llvm_unreachable("Missing specialization/instantiation case?");
@@ -5684,7 +5737,7 @@
// C++ [temp.expl.spec]p6:
// If a template, a member template or the member of a class template is
- // explicitly specialized then that spe- cialization shall be declared
+ // explicitly specialized then that specialization shall be declared
// before the first use of that specialization that would cause an implicit
// instantiation to take place, in every translation unit in which such a
// use occurs; no diagnostic is required.
@@ -5973,6 +6026,9 @@
Specialization->setExternLoc(ExternLoc);
Specialization->setTemplateKeywordLoc(TemplateLoc);
+ if (Attr)
+ ProcessDeclAttributeList(S, Specialization, Attr);
+
// Add the explicit instantiation into its lexical context. However,
// since explicit instantiations are never found by name lookup, we
// just put it into the declaration context directly.
@@ -6041,7 +6097,7 @@
KWLoc, SS, Name, NameLoc, Attr, AS_none,
/*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(*this, 0, 0),
- Owned, IsDependent, false, false,
+ Owned, IsDependent, SourceLocation(), false,
TypeResult());
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
@@ -6094,7 +6150,7 @@
// Verify that it is okay to explicitly instantiate here.
CXXRecordDecl *PrevDecl
- = cast_or_null<CXXRecordDecl>(Record->getPreviousDeclaration());
+ = cast_or_null<CXXRecordDecl>(Record->getPreviousDecl());
if (!PrevDecl && Record->getDefinition())
PrevDecl = Record;
if (PrevDecl) {
@@ -6369,7 +6425,7 @@
return true;
}
- FunctionDecl *PrevDecl = Specialization->getPreviousDeclaration();
+ FunctionDecl *PrevDecl = Specialization->getPreviousDecl();
if (!PrevDecl && Specialization->isThisDeclarationADefinition())
PrevDecl = Specialization;
@@ -6389,6 +6445,9 @@
}
Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
+ AttributeList *Attr = D.getDeclSpec().getAttributes().getList();
+ if (Attr)
+ ProcessDeclAttributeList(S, Specialization, Attr);
if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization);
Modified: cfe/branches/tooling/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaTemplateDeduction.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaTemplateDeduction.cpp Fri Jan 20 10:14:22 2012
@@ -112,15 +112,16 @@
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S,
- TemplateParameterList *TemplateParams,
- QualType Param,
- QualType Arg,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned TDF,
- bool PartialOrdering = false,
- SmallVectorImpl<RefParamPartialOrderingComparison> *
+DeduceTemplateArgumentsByTypeMatch(Sema &S,
+ TemplateParameterList *TemplateParams,
+ QualType Param,
+ QualType Arg,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &
+ Deduced,
+ unsigned TDF,
+ bool PartialOrdering = false,
+ SmallVectorImpl<RefParamPartialOrderingComparison> *
RefParamComparisons = 0);
static Sema::TemplateDeductionResult
@@ -705,12 +706,11 @@
}
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- Params[ParamIdx],
- Args[ArgIdx],
- Info, Deduced, TDF,
- PartialOrdering,
- RefParamComparisons))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ Params[ParamIdx], Args[ArgIdx],
+ Info, Deduced, TDF,
+ PartialOrdering,
+ RefParamComparisons))
return Result;
++ArgIdx;
@@ -766,9 +766,10 @@
// Deduce template arguments from the pattern.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx],
- Info, Deduced, TDF, PartialOrdering,
- RefParamComparisons))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern,
+ Args[ArgIdx], Info, Deduced,
+ TDF, PartialOrdering,
+ RefParamComparisons))
return Result;
// Capture the deduced template arguments for each parameter pack expanded
@@ -858,14 +859,15 @@
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S,
- TemplateParameterList *TemplateParams,
- QualType ParamIn, QualType ArgIn,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned TDF,
- bool PartialOrdering,
- SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
+DeduceTemplateArgumentsByTypeMatch(Sema &S,
+ TemplateParameterList *TemplateParams,
+ QualType ParamIn, QualType ArgIn,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ unsigned TDF,
+ bool PartialOrdering,
+ SmallVectorImpl<RefParamPartialOrderingComparison> *
+ RefParamComparisons) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
QualType Param = S.Context.getCanonicalType(ParamIn);
@@ -1110,17 +1112,17 @@
// _Complex T [placeholder extension]
case Type::Complex:
if (const ComplexType *ComplexArg = Arg->getAs<ComplexType>())
- return DeduceTemplateArguments(S, TemplateParams,
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
cast<ComplexType>(Param)->getElementType(),
- ComplexArg->getElementType(),
- Info, Deduced, TDF);
+ ComplexArg->getElementType(),
+ Info, Deduced, TDF);
return Sema::TDK_NonDeducedMismatch;
// _Atomic T [extension]
case Type::Atomic:
if (const AtomicType *AtomicArg = Arg->getAs<AtomicType>())
- return DeduceTemplateArguments(S, TemplateParams,
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
cast<AtomicType>(Param)->getValueType(),
AtomicArg->getValueType(),
Info, Deduced, TDF);
@@ -1140,8 +1142,8 @@
}
unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
- return DeduceTemplateArguments(S, TemplateParams,
- cast<PointerType>(Param)->getPointeeType(),
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ cast<PointerType>(Param)->getPointeeType(),
PointeeType,
Info, Deduced, SubTDF);
}
@@ -1152,10 +1154,9 @@
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(S, TemplateParams,
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
cast<LValueReferenceType>(Param)->getPointeeType(),
- ReferenceArg->getPointeeType(),
- Info, Deduced, 0);
+ ReferenceArg->getPointeeType(), Info, Deduced, 0);
}
// T && [C++0x]
@@ -1164,10 +1165,10 @@
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(S, TemplateParams,
- cast<RValueReferenceType>(Param)->getPointeeType(),
- ReferenceArg->getPointeeType(),
- Info, Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ cast<RValueReferenceType>(Param)->getPointeeType(),
+ ReferenceArg->getPointeeType(),
+ Info, Deduced, 0);
}
// T [] (implied, but not stated explicitly)
@@ -1178,10 +1179,10 @@
return Sema::TDK_NonDeducedMismatch;
unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
- return DeduceTemplateArguments(S, TemplateParams,
- S.Context.getAsIncompleteArrayType(Param)->getElementType(),
- IncompleteArrayArg->getElementType(),
- Info, Deduced, SubTDF);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ S.Context.getAsIncompleteArrayType(Param)->getElementType(),
+ IncompleteArrayArg->getElementType(),
+ Info, Deduced, SubTDF);
}
// T [integer-constant]
@@ -1197,10 +1198,10 @@
return Sema::TDK_NonDeducedMismatch;
unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
- return DeduceTemplateArguments(S, TemplateParams,
- ConstantArrayParm->getElementType(),
- ConstantArrayArg->getElementType(),
- Info, Deduced, SubTDF);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ ConstantArrayParm->getElementType(),
+ ConstantArrayArg->getElementType(),
+ Info, Deduced, SubTDF);
}
// type [i]
@@ -1215,10 +1216,10 @@
const DependentSizedArrayType *DependentArrayParm
= S.Context.getAsDependentSizedArrayType(Param);
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- DependentArrayParm->getElementType(),
- ArrayArg->getElementType(),
- Info, Deduced, SubTDF))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ DependentArrayParm->getElementType(),
+ ArrayArg->getElementType(),
+ Info, Deduced, SubTDF))
return Result;
// Determine the array bound is something we can deduce.
@@ -1272,10 +1273,10 @@
// Check return types.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- FunctionProtoParam->getResultType(),
- FunctionProtoArg->getResultType(),
- Info, Deduced, 0))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ FunctionProtoParam->getResultType(),
+ FunctionProtoArg->getResultType(),
+ Info, Deduced, 0))
return Result;
return DeduceTemplateArguments(S, TemplateParams,
@@ -1399,17 +1400,17 @@
return Sema::TDK_NonDeducedMismatch;
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- MemPtrParam->getPointeeType(),
- MemPtrArg->getPointeeType(),
- Info, Deduced,
- TDF & TDF_IgnoreQualifiers))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ MemPtrParam->getPointeeType(),
+ MemPtrArg->getPointeeType(),
+ Info, Deduced,
+ TDF & TDF_IgnoreQualifiers))
return Result;
- return DeduceTemplateArguments(S, TemplateParams,
- QualType(MemPtrParam->getClass(), 0),
- QualType(MemPtrArg->getClass(), 0),
- Info, Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ QualType(MemPtrParam->getClass(), 0),
+ QualType(MemPtrArg->getClass(), 0),
+ Info, Deduced, 0);
}
// (clang extension)
@@ -1424,10 +1425,10 @@
if (!BlockPtrArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(S, TemplateParams,
- BlockPtrParam->getPointeeType(),
- BlockPtrArg->getPointeeType(), Info,
- Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ BlockPtrParam->getPointeeType(),
+ BlockPtrArg->getPointeeType(),
+ Info, Deduced, 0);
}
// (clang extension)
@@ -1441,11 +1442,10 @@
return Sema::TDK_NonDeducedMismatch;
// Perform deduction on the element types.
- return DeduceTemplateArguments(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced,
- TDF);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced, TDF);
}
if (const DependentSizedExtVectorType *VectorArg
@@ -1455,11 +1455,10 @@
// ordering.
// Perform deduction on the element types.
- return DeduceTemplateArguments(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced,
- TDF);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced, TDF);
}
return Sema::TDK_NonDeducedMismatch;
@@ -1475,11 +1474,10 @@
if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
// Perform deduction on the element types.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced,
- TDF))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced, TDF))
return Result;
// Perform deduction on the vector size, if we can.
@@ -1498,11 +1496,10 @@
= dyn_cast<DependentSizedExtVectorType>(Arg)) {
// Perform deduction on the element types.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced,
- TDF))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced, TDF))
return Result;
// Perform deduction on the vector size, if we can.
@@ -1553,8 +1550,10 @@
case TemplateArgument::Type:
if (Arg.getKind() == TemplateArgument::Type)
- return DeduceTemplateArguments(S, TemplateParams, Param.getAsType(),
- Arg.getAsType(), Info, Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ Param.getAsType(),
+ Arg.getAsType(),
+ Info, Deduced, 0);
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
@@ -2737,9 +2736,8 @@
Deduced(TemplateParams->size());
TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- ParamType, ArgType,
- Info, Deduced, TDF);
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
+ ArgType, Info, Deduced, TDF);
if (Result) continue;
if (!Match.isNull()) return QualType();
Match = ArgType;
@@ -2973,15 +2971,37 @@
if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
continue;
+ // If the argument is an initializer list ...
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) {
+ // ... then the parameter is an undeduced context, unless the parameter
+ // type is (reference to cv) std::initializer_list<P'>, in which case
+ // deduction is done for each element of the initializer list, and the
+ // result is the deduced type if it's the same for all elements.
+ QualType X;
+ // Removing references was already done.
+ if (!isStdInitializerList(ParamType, &X))
+ continue;
+
+ for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) {
+ if (TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, X,
+ ILE->getInit(i)->getType(),
+ Info, Deduced, TDF))
+ return Result;
+ }
+ // Don't track the argument type, since an initializer list has none.
+ continue;
+ }
+
// Keep track of the argument type and corresponding parameter index,
// so we can check for compatibility between the deduced A and A.
OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1,
ArgType));
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this, TemplateParams,
- ParamType, ArgType, Info, Deduced,
- TDF))
+ = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
+ ParamType, ArgType,
+ Info, Deduced, TDF))
return Result;
continue;
@@ -3044,17 +3064,35 @@
break;
}
- // Keep track of the argument type and corresponding argument index,
- // so we can check for compatibility between the deduced A and A.
- if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
- OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx,
- ArgType));
+ // As above, initializer lists need special handling.
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) {
+ QualType X;
+ if (!isStdInitializerList(ParamType, &X)) {
+ ++ArgIdx;
+ break;
+ }
- if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this, TemplateParams,
- ParamType, ArgType, Info, Deduced,
- TDF))
- return Result;
+ for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) {
+ if (TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, X,
+ ILE->getInit(i)->getType(),
+ Info, Deduced, TDF))
+ return Result;
+ }
+ } else {
+
+ // Keep track of the argument type and corresponding argument index,
+ // so we can check for compatibility between the deduced A and A.
+ if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
+ OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx,
+ ArgType));
+
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
+ ParamType, ArgType, Info,
+ Deduced, TDF))
+ return Result;
+ }
// Capture the deduced template arguments for each parameter pack expanded
// by this pack expansion, add them to the list of arguments we've deduced
@@ -3144,7 +3182,7 @@
if (!ArgFunctionType.isNull()) {
// Deduce template arguments from the function type.
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this, TemplateParams,
+ = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
FunctionType, ArgFunctionType, Info,
Deduced, TDF_TopLevelParameterTypeList))
return Result;
@@ -3255,8 +3293,8 @@
(P->isMemberPointerType() && A->isMemberPointerType()))
TDF |= TDF_IgnoreQualifiers;
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this, TemplateParams,
- P, A, Info, Deduced, TDF))
+ = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
+ P, A, Info, Deduced, TDF))
return Result;
// Finish template argument deduction.
@@ -3384,20 +3422,36 @@
return false;
TemplateDeductionInfo Info(Context, Loc);
- if (::DeduceTemplateArguments(*this, &TemplateParams,
- FuncParam, InitType, Info, Deduced,
- TDF))
- return false;
+
+ InitListExpr * InitList = dyn_cast<InitListExpr>(Init);
+ if (InitList) {
+ for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
+ if (DeduceTemplateArgumentsByTypeMatch(*this, &TemplateParams, FuncParam,
+ InitList->getInit(i)->getType(),
+ Info, Deduced, TDF))
+ return false;
+ }
+ } else {
+ if (DeduceTemplateArgumentsByTypeMatch(*this, &TemplateParams, FuncParam,
+ InitType, Info, Deduced, TDF))
+ return false;
+ }
QualType DeducedType = Deduced[0].getAsType();
if (DeducedType.isNull())
return false;
-
+
+ if (InitList) {
+ DeducedType = BuildStdInitializerList(DeducedType, Loc);
+ if (DeducedType.isNull())
+ return false;
+ }
+
Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type);
-
+
// Check that the deduced argument type is compatible with the original
// argument type per C++ [temp.deduct.call]p4.
- if (Result &&
+ if (!InitList && Result &&
CheckOriginalCallArgDeduction(*this,
Sema::OriginalCallArg(FuncParam,0,InitType),
Result->getType())) {
@@ -3408,8 +3462,19 @@
return true;
}
+void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
+ if (isa<InitListExpr>(Init))
+ Diag(VDecl->getLocation(),
+ diag::err_auto_var_deduction_failure_from_init_list)
+ << VDecl->getDeclName() << VDecl->getType() << Init->getSourceRange();
+ else
+ Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
+ << VDecl->getDeclName() << VDecl->getType() << Init->getType()
+ << Init->getSourceRange();
+}
+
static void
-MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
+MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced,
unsigned Level,
SmallVectorImpl<bool> &Deduced);
@@ -3521,19 +3586,23 @@
case TPOC_Conversion:
// - In the context of a call to a conversion operator, the return types
// of the conversion function templates are used.
- if (DeduceTemplateArguments(S, TemplateParams, Proto2->getResultType(),
- Proto1->getResultType(), Info, Deduced,
- TDF_None, /*PartialOrdering=*/true,
- RefParamComparisons))
+ if (DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ Proto2->getResultType(),
+ Proto1->getResultType(),
+ Info, Deduced, TDF_None,
+ /*PartialOrdering=*/true,
+ RefParamComparisons))
return false;
break;
case TPOC_Other:
// - In other contexts (14.6.6.2) the function template's function type
// is used.
- if (DeduceTemplateArguments(S, TemplateParams, FD2->getType(),
- FD1->getType(), Info, Deduced, TDF_None,
- /*PartialOrdering=*/true, RefParamComparisons))
+ if (DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ FD2->getType(), FD1->getType(),
+ Info, Deduced, TDF_None,
+ /*PartialOrdering=*/true,
+ RefParamComparisons))
return false;
break;
}
@@ -3564,23 +3633,24 @@
std::min(Proto1->getNumArgs(),
Proto2->getNumArgs()));
if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1)
- ::MarkUsedTemplateParameters(S, Method2->getThisType(S.Context), false,
+ ::MarkUsedTemplateParameters(S.Context, Method2->getThisType(S.Context),
+ false,
TemplateParams->getDepth(), UsedParameters);
for (unsigned I = Skip2; I < NumParams; ++I)
- ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false,
+ ::MarkUsedTemplateParameters(S.Context, Proto2->getArgType(I), false,
TemplateParams->getDepth(),
UsedParameters);
break;
}
case TPOC_Conversion:
- ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false,
+ ::MarkUsedTemplateParameters(S.Context, Proto2->getResultType(), false,
TemplateParams->getDepth(),
UsedParameters);
break;
case TPOC_Other:
- ::MarkUsedTemplateParameters(S, FD2->getType(), false,
+ ::MarkUsedTemplateParameters(S.Context, FD2->getType(), false,
TemplateParams->getDepth(),
UsedParameters);
break;
@@ -3899,7 +3969,8 @@
// Determine whether PS1 is at least as specialized as PS2
Deduced.resize(PS2->getTemplateParameters()->size());
- bool Better1 = !::DeduceTemplateArguments(*this, PS2->getTemplateParameters(),
+ bool Better1 = !DeduceTemplateArgumentsByTypeMatch(*this,
+ PS2->getTemplateParameters(),
PT2, PT1, Info, Deduced, TDF_None,
/*PartialOrdering=*/true,
/*RefParamComparisons=*/0);
@@ -3914,7 +3985,8 @@
// Determine whether PS2 is at least as specialized as PS1
Deduced.clear();
Deduced.resize(PS1->getTemplateParameters()->size());
- bool Better2 = !::DeduceTemplateArguments(*this, PS1->getTemplateParameters(),
+ bool Better2 = !DeduceTemplateArgumentsByTypeMatch(*this,
+ PS1->getTemplateParameters(),
PT1, PT2, Info, Deduced, TDF_None,
/*PartialOrdering=*/true,
/*RefParamComparisons=*/0);
@@ -3933,7 +4005,7 @@
}
static void
-MarkUsedTemplateParameters(Sema &SemaRef,
+MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,
bool OnlyDeduced,
unsigned Depth,
@@ -3942,7 +4014,7 @@
/// \brief Mark the template parameters that are used by the given
/// expression.
static void
-MarkUsedTemplateParameters(Sema &SemaRef,
+MarkUsedTemplateParameters(ASTContext &Ctx,
const Expr *E,
bool OnlyDeduced,
unsigned Depth,
@@ -3973,7 +4045,7 @@
/// \brief Mark the template parameters that are used by the given
/// nested name specifier.
static void
-MarkUsedTemplateParameters(Sema &SemaRef,
+MarkUsedTemplateParameters(ASTContext &Ctx,
NestedNameSpecifier *NNS,
bool OnlyDeduced,
unsigned Depth,
@@ -3981,16 +4053,16 @@
if (!NNS)
return;
- MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Depth,
+ MarkUsedTemplateParameters(Ctx, NNS->getPrefix(), OnlyDeduced, Depth,
Used);
- MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0),
+ MarkUsedTemplateParameters(Ctx, QualType(NNS->getAsType(), 0),
OnlyDeduced, Depth, Used);
}
/// \brief Mark the template parameters that are used by the given
/// template name.
static void
-MarkUsedTemplateParameters(Sema &SemaRef,
+MarkUsedTemplateParameters(ASTContext &Ctx,
TemplateName Name,
bool OnlyDeduced,
unsigned Depth,
@@ -4005,17 +4077,17 @@
}
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName())
- MarkUsedTemplateParameters(SemaRef, QTN->getQualifier(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, QTN->getQualifier(), OnlyDeduced,
Depth, Used);
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName())
- MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, DTN->getQualifier(), OnlyDeduced,
Depth, Used);
}
/// \brief Mark the template parameters that are used by the given
/// type.
static void
-MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
+MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced,
unsigned Depth,
SmallVectorImpl<bool> &Used) {
@@ -4026,10 +4098,10 @@
if (!T->isDependentType())
return;
- T = SemaRef.Context.getCanonicalType(T);
+ T = Ctx.getCanonicalType(T);
switch (T->getTypeClass()) {
case Type::Pointer:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<PointerType>(T)->getPointeeType(),
OnlyDeduced,
Depth,
@@ -4037,7 +4109,7 @@
break;
case Type::BlockPointer:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<BlockPointerType>(T)->getPointeeType(),
OnlyDeduced,
Depth,
@@ -4046,7 +4118,7 @@
case Type::LValueReference:
case Type::RValueReference:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<ReferenceType>(T)->getPointeeType(),
OnlyDeduced,
Depth,
@@ -4055,29 +4127,29 @@
case Type::MemberPointer: {
const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
- MarkUsedTemplateParameters(SemaRef, MemPtr->getPointeeType(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, MemPtr->getPointeeType(), OnlyDeduced,
Depth, Used);
- MarkUsedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
+ MarkUsedTemplateParameters(Ctx, QualType(MemPtr->getClass(), 0),
OnlyDeduced, Depth, Used);
break;
}
case Type::DependentSizedArray:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<DependentSizedArrayType>(T)->getSizeExpr(),
OnlyDeduced, Depth, Used);
// Fall through to check the element type
case Type::ConstantArray:
case Type::IncompleteArray:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<ArrayType>(T)->getElementType(),
OnlyDeduced, Depth, Used);
break;
case Type::Vector:
case Type::ExtVector:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<VectorType>(T)->getElementType(),
OnlyDeduced, Depth, Used);
break;
@@ -4085,19 +4157,19 @@
case Type::DependentSizedExtVector: {
const DependentSizedExtVectorType *VecType
= cast<DependentSizedExtVectorType>(T);
- MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, VecType->getElementType(), OnlyDeduced,
Depth, Used);
- MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, VecType->getSizeExpr(), OnlyDeduced,
Depth, Used);
break;
}
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
- MarkUsedTemplateParameters(SemaRef, Proto->getResultType(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, Proto->getResultType(), OnlyDeduced,
Depth, Used);
for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(SemaRef, Proto->getArgType(I), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, Proto->getArgType(I), OnlyDeduced,
Depth, Used);
break;
}
@@ -4112,10 +4184,10 @@
case Type::SubstTemplateTypeParmPack: {
const SubstTemplateTypeParmPackType *Subst
= cast<SubstTemplateTypeParmPackType>(T);
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
QualType(Subst->getReplacedParameter(), 0),
OnlyDeduced, Depth, Used);
- MarkUsedTemplateParameters(SemaRef, Subst->getArgumentPack(),
+ MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(),
OnlyDeduced, Depth, Used);
break;
}
@@ -4127,7 +4199,7 @@
case Type::TemplateSpecialization: {
const TemplateSpecializationType *Spec
= cast<TemplateSpecializationType>(T);
- MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, Spec->getTemplateName(), OnlyDeduced,
Depth, Used);
// C++0x [temp.deduct.type]p9:
@@ -4139,28 +4211,28 @@
break;
for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth,
+ MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
Used);
break;
}
case Type::Complex:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<ComplexType>(T)->getElementType(),
OnlyDeduced, Depth, Used);
break;
case Type::Atomic:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<AtomicType>(T)->getValueType(),
OnlyDeduced, Depth, Used);
break;
case Type::DependentName:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<DependentNameType>(T)->getQualifier(),
OnlyDeduced, Depth, Used);
break;
@@ -4169,7 +4241,7 @@
const DependentTemplateSpecializationType *Spec
= cast<DependentTemplateSpecializationType>(T);
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef, Spec->getQualifier(),
+ MarkUsedTemplateParameters(Ctx, Spec->getQualifier(),
OnlyDeduced, Depth, Used);
// C++0x [temp.deduct.type]p9:
@@ -4181,47 +4253,47 @@
break;
for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth,
+ MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
Used);
break;
}
case Type::TypeOf:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<TypeOfType>(T)->getUnderlyingType(),
OnlyDeduced, Depth, Used);
break;
case Type::TypeOfExpr:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<TypeOfExprType>(T)->getUnderlyingExpr(),
OnlyDeduced, Depth, Used);
break;
case Type::Decltype:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<DecltypeType>(T)->getUnderlyingExpr(),
OnlyDeduced, Depth, Used);
break;
case Type::UnaryTransform:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<UnaryTransformType>(T)->getUnderlyingType(),
OnlyDeduced, Depth, Used);
break;
case Type::PackExpansion:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<PackExpansionType>(T)->getPattern(),
OnlyDeduced, Depth, Used);
break;
case Type::Auto:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<AutoType>(T)->getDeducedType(),
OnlyDeduced, Depth, Used);
@@ -4247,7 +4319,7 @@
/// \brief Mark the template parameters that are used by this
/// template argument.
static void
-MarkUsedTemplateParameters(Sema &SemaRef,
+MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,
bool OnlyDeduced,
unsigned Depth,
@@ -4259,19 +4331,19 @@
break;
case TemplateArgument::Type:
- MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsType(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, TemplateArg.getAsType(), OnlyDeduced,
Depth, Used);
break;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
TemplateArg.getAsTemplateOrTemplatePattern(),
OnlyDeduced, Depth, Used);
break;
case TemplateArgument::Expression:
- MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, TemplateArg.getAsExpr(), OnlyDeduced,
Depth, Used);
break;
@@ -4279,7 +4351,7 @@
for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(),
PEnd = TemplateArg.pack_end();
P != PEnd; ++P)
- MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Depth, Used);
+ MarkUsedTemplateParameters(Ctx, *P, OnlyDeduced, Depth, Used);
break;
}
}
@@ -4306,14 +4378,15 @@
return;
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
- ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced,
+ ::MarkUsedTemplateParameters(Context, TemplateArgs[I], OnlyDeduced,
Depth, Used);
}
/// \brief Marks all of the template parameters that will be deduced by a
/// call to the given function template.
void
-Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
+Sema::MarkDeducedTemplateParameters(ASTContext &Ctx,
+ FunctionTemplateDecl *FunctionTemplate,
SmallVectorImpl<bool> &Deduced) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
@@ -4322,7 +4395,7 @@
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I)
- ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(),
+ ::MarkUsedTemplateParameters(Ctx, Function->getParamDecl(I)->getType(),
true, TemplateParams->getDepth(), Deduced);
}
@@ -4336,7 +4409,7 @@
= FunctionTemplate->getTemplateParameters();
SmallVector<bool, 4> Deduced;
Deduced.resize(TemplateParams->size());
- ::MarkUsedTemplateParameters(S, T, true, TemplateParams->getDepth(),
+ ::MarkUsedTemplateParameters(S.Context, T, true, TemplateParams->getDepth(),
Deduced);
for (unsigned I = 0, N = Deduced.size(); I != N; ++I)
Modified: cfe/branches/tooling/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaTemplateInstantiate.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaTemplateInstantiate.cpp Fri Jan 20 10:14:22 2012
@@ -163,8 +163,8 @@
case DefaultTemplateArgumentChecking:
return false;
}
-
- return true;
+
+ llvm_unreachable("Invalid InstantiationKind!");
}
Sema::InstantiatingTemplate::
@@ -1709,6 +1709,13 @@
<< Context.getTypeDeclType(Instantiation);
Diag(Pattern->getLocation(), diag::note_template_decl_here);
}
+
+ // In general, Instantiation isn't marked invalid to get more than one
+ // error for multiple undefined instantiations. But the code that does
+ // explicit declaration -> explicit definition conversion can't handle
+ // invalid declarations, so mark as invalid in that case.
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
+ Instantiation->setInvalidDecl();
return true;
}
Pattern = PatternDef;
@@ -1719,7 +1726,7 @@
MSInfo->setTemplateSpecializationKind(TSK);
MSInfo->setPointOfInstantiation(PointOfInstantiation);
} else if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Instantiation)) {
+ = dyn_cast<ClassTemplateSpecializationDecl>(Instantiation)) {
Spec->setTemplateSpecializationKind(TSK);
Spec->setPointOfInstantiation(PointOfInstantiation);
}
@@ -1888,7 +1895,8 @@
// If this is an explicit instantiation definition, mark the
// vtable as used.
- if (TSK == TSK_ExplicitInstantiationDefinition)
+ if (TSK == TSK_ExplicitInstantiationDefinition &&
+ !ClassTemplateSpec->isInvalidDecl())
MarkVTableUsed(PointOfInstantiation, ClassTemplateSpec, true);
return false;
@@ -2122,7 +2130,7 @@
// Always skip the injected-class-name, along with any
// redeclarations of nested classes, since both would cause us
// to try to instantiate the members of a class twice.
- if (Record->isInjectedClassName() || Record->getPreviousDeclaration())
+ if (Record->isInjectedClassName() || Record->getPreviousDecl())
continue;
MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo();
@@ -2289,7 +2297,7 @@
// If this is a tag declaration, it's possible that we need to look for
// a previous declaration.
if (const TagDecl *Tag = dyn_cast<TagDecl>(CheckD))
- CheckD = Tag->getPreviousDeclaration();
+ CheckD = Tag->getPreviousDecl();
else
CheckD = 0;
} while (CheckD);
Modified: cfe/branches/tooling/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Jan 20 10:14:22 2012
@@ -66,17 +66,16 @@
// FIXME: This should be generalized to more than just the AlignedAttr.
if (const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr)) {
if (Aligned->isAlignmentDependent()) {
- // The alignment expression is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(*this,
- Sema::Unevaluated);
-
if (Aligned->isAlignmentExpr()) {
+ // The alignment expression is a constant expression.
+ EnterExpressionEvaluationContext Unevaluated(*this,
+ Sema::ConstantEvaluated);
+
ExprResult Result = SubstExpr(Aligned->getAlignmentExpr(),
TemplateArgs);
if (!Result.isInvalid())
AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>());
- }
- else {
+ } else {
TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(),
TemplateArgs,
Aligned->getLocation(),
@@ -164,13 +163,18 @@
}
}
- if (TypedefNameDecl *Prev = D->getPreviousDeclaration()) {
+ if (TypedefNameDecl *Prev = D->getPreviousDecl()) {
NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev,
TemplateArgs);
if (!InstPrev)
return 0;
- Typedef->setPreviousDeclaration(cast<TypedefNameDecl>(InstPrev));
+ TypedefNameDecl *InstPrevTypedef = cast<TypedefNameDecl>(InstPrev);
+
+ // If the typedef types are not identical, reject them.
+ SemaRef.isIncompatibleTypedef(InstPrevTypedef, Typedef);
+
+ Typedef->setPreviousDeclaration(InstPrevTypedef);
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
@@ -206,7 +210,7 @@
TypeAliasDecl *Pattern = D->getTemplatedDecl();
TypeAliasTemplateDecl *PrevAliasTemplate = 0;
- if (Pattern->getPreviousDeclaration()) {
+ if (Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (Found.first != Found.second) {
PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first);
@@ -326,6 +330,7 @@
Var->setThreadSpecified(D->isThreadSpecified());
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
+ Var->setConstexpr(D->isConstexpr());
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
@@ -360,8 +365,7 @@
SemaRef.CheckVariableDeclaration(Var, Previous);
if (D->isOutOfLine()) {
- if (!D->isStaticDataMember())
- D->getLexicalDeclContext()->addDecl(Var);
+ D->getLexicalDeclContext()->addDecl(Var);
Owner->makeDeclVisibleInContext(Var);
} else {
Owner->addDecl(Var);
@@ -380,7 +384,7 @@
// We already have an initializer in the class.
} else if (D->getInit()) {
if (Var->isStaticDataMember() && !D->isOutOfLine())
- SemaRef.PushExpressionEvaluationContext(Sema::Unevaluated);
+ SemaRef.PushExpressionEvaluationContext(Sema::ConstantEvaluated);
else
SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
@@ -390,16 +394,15 @@
if (!SemaRef.InstantiateInitializer(D->getInit(), TemplateArgs, LParenLoc,
InitArgs, RParenLoc)) {
bool TypeMayContainAuto = true;
- // Attach the initializer to the declaration, if we have one.
- if (InitArgs.size() == 0)
- SemaRef.ActOnUninitializedDecl(Var, TypeMayContainAuto);
- else if (D->hasCXXDirectInitializer()) {
+ if (D->hasCXXDirectInitializer()) {
// Add the direct initializer to the declaration.
SemaRef.AddCXXDirectInitializerToDecl(Var,
LParenLoc,
move_arg(InitArgs),
RParenLoc,
TypeMayContainAuto);
+ } else if (InitArgs.size() == 0) {
+ SemaRef.ActOnUninitializedDecl(Var, TypeMayContainAuto);
} else {
assert(InitArgs.size() == 1);
Expr *Init = InitArgs.take()[0];
@@ -462,8 +465,9 @@
if (Invalid)
BitWidth = 0;
else if (BitWidth) {
- // The bit-width expression is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ // The bit-width expression is a constant expression.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
ExprResult InstantiatedBitWidth
= SemaRef.SubstExpr(BitWidth, TemplateArgs);
@@ -591,8 +595,9 @@
Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
Expr *AssertExpr = D->getAssertExpr();
- // The expression in a static assertion is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ // The expression in a static assertion is a constant expression.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
ExprResult InstantiatedAssertExpr
= SemaRef.SubstExpr(AssertExpr, TemplateArgs);
@@ -653,9 +658,9 @@
// The specified value for the enumerator.
ExprResult Value = SemaRef.Owned((Expr *)0);
if (Expr *UninstValue = EC->getInitExpr()) {
- // The enumerator's value expression is not potentially evaluated.
+ // The enumerator's value expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::Unevaluated);
+ Sema::ConstantEvaluated);
Value = SemaRef.SubstExpr(UninstValue, TemplateArgs);
}
@@ -735,7 +740,7 @@
CXXRecordDecl *PrevDecl = 0;
ClassTemplateDecl *PrevClassTemplate = 0;
- if (!isFriend && Pattern->getPreviousDeclaration()) {
+ if (!isFriend && Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (Found.first != Found.second) {
PrevClassTemplate = dyn_cast<ClassTemplateDecl>(*Found.first);
@@ -972,9 +977,9 @@
CXXRecordDecl *PrevDecl = 0;
if (D->isInjectedClassName())
PrevDecl = cast<CXXRecordDecl>(Owner);
- else if (D->getPreviousDeclaration()) {
+ else if (D->getPreviousDecl()) {
NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
- D->getPreviousDeclaration(),
+ D->getPreviousDecl(),
TemplateArgs);
if (!Prev) return 0;
PrevDecl = cast<CXXRecordDecl>(Prev);
@@ -1234,9 +1239,9 @@
if (isFriend) {
NamedDecl *PrevDecl;
if (TemplateParams)
- PrevDecl = FunctionTemplate->getPreviousDeclaration();
+ PrevDecl = FunctionTemplate->getPreviousDecl();
else
- PrevDecl = Function->getPreviousDeclaration();
+ PrevDecl = Function->getPreviousDecl();
PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false);
@@ -2321,11 +2326,12 @@
}
Expr *NoexceptExpr = 0;
if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
if (E.isUsable())
E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart());
-
+
if (E.isUsable()) {
SourceLocation ErrLoc;
llvm::APSInt NoexceptVal;
@@ -3335,12 +3341,12 @@
// Don't try to instantiate declarations if the most recent redeclaration
// is invalid.
- if (Var->getMostRecentDeclaration()->isInvalidDecl())
+ if (Var->getMostRecentDecl()->isInvalidDecl())
continue;
// Check if the most recent declaration has changed the specialization kind
// and removed the need for implicit instantiation.
- switch (Var->getMostRecentDeclaration()->getTemplateSpecializationKind()) {
+ switch (Var->getMostRecentDecl()->getTemplateSpecializationKind()) {
case TSK_Undeclared:
llvm_unreachable("Cannot instantitiate an undeclared specialization.");
case TSK_ExplicitInstantiationDeclaration:
@@ -3349,7 +3355,7 @@
case TSK_ExplicitInstantiationDefinition:
// We only need an instantiation if the pending instantiation *is* the
// explicit instantiation.
- if (Var != Var->getMostRecentDeclaration()) continue;
+ if (Var != Var->getMostRecentDecl()) continue;
case TSK_ImplicitInstantiation:
break;
}
Modified: cfe/branches/tooling/lib/Sema/SemaTemplateVariadic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaTemplateVariadic.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaTemplateVariadic.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaTemplateVariadic.cpp Fri Jan 20 10:14:22 2012
@@ -708,6 +708,19 @@
return false;
}
+namespace {
+
+// Callback to only accept typo corrections that refer to parameter packs.
+class ParameterPackValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ NamedDecl *ND = candidate.getCorrectionDecl();
+ return ND && ND->isParameterPack();
+ }
+};
+
+}
+
/// \brief Called when an expression computing the size of a parameter pack
/// is parsed.
///
@@ -733,6 +746,7 @@
LookupName(R, S);
NamedDecl *ParameterPack = 0;
+ ParameterPackValidatorCCC Validator;
switch (R.getResultKind()) {
case LookupResult::Found:
ParameterPack = R.getFoundDecl();
@@ -741,19 +755,16 @@
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), S, 0, 0,
- false, CTC_NoKeywords)) {
- if (NamedDecl *CorrectedResult = Corrected.getCorrectionDecl())
- if (CorrectedResult->isParameterPack()) {
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
- ParameterPack = CorrectedResult;
- Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest)
- << &Name << CorrectedQuotedStr
- << FixItHint::CreateReplacement(
- NameLoc, Corrected.getAsString(getLangOptions()));
- Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here)
- << CorrectedQuotedStr;
- }
+ R.getLookupKind(), S, 0,
+ &Validator)) {
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
+ ParameterPack = Corrected.getCorrectionDecl();
+ Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest)
+ << &Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(
+ NameLoc, Corrected.getAsString(getLangOptions()));
+ Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here)
+ << CorrectedQuotedStr;
}
case LookupResult::FoundOverloaded:
Modified: cfe/branches/tooling/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/SemaType.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/SemaType.cpp (original)
+++ cfe/branches/tooling/lib/Sema/SemaType.cpp Fri Jan 20 10:14:22 2012
@@ -27,6 +27,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/Lookup.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -639,7 +640,10 @@
// If this is a missing declspec in a block literal return context, then it
// is inferred from the return statements inside the block.
- if (isOmittedBlockReturnType(declarator)) {
+ // The declspec is always missing in a lambda expr context; it is either
+ // specified with a trailing return type or inferred.
+ if (declarator.getContext() == Declarator::LambdaExprContext ||
+ isOmittedBlockReturnType(declarator)) {
Result = Context.DependentTy;
break;
}
@@ -1053,10 +1057,11 @@
} else if (type->isObjCARCImplicitlyUnretainedType()) {
implicitLifetime = Qualifiers::OCL_ExplicitNone;
- // If we are in an unevaluated context, like sizeof, assume ExplicitNone and
- // don't give error.
- } else if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) {
- implicitLifetime = Qualifiers::OCL_ExplicitNone;
+ // If we are in an unevaluated context, like sizeof, skip adding a
+ // qualification.
+ } else if (S.ExprEvalContexts.back().Context == Sema::Unevaluated ||
+ S.ExprEvalContexts.back().Context == Sema::ConstantEvaluated) {
+ return type;
// If that failed, give an error and recover using __autoreleasing.
} else {
@@ -1179,13 +1184,9 @@
// If we're in a GNU mode (like gnu99, but not c99) accept any evaluatable
// value as an extension.
- Expr::EvalResult Result;
- if (S.LangOpts.GNUMode && ArraySize->EvaluateAsRValue(Result, S.Context)) {
- if (!Result.hasSideEffects() && Result.Val.isInt()) {
- SizeVal = Result.Val.getInt();
- S.Diag(ArraySize->getLocStart(), diag::ext_vla_folded_to_constant);
- return false;
- }
+ if (S.LangOpts.GNUMode && ArraySize->EvaluateAsInt(SizeVal, S.Context)) {
+ S.Diag(ArraySize->getLocStart(), diag::ext_vla_folded_to_constant);
+ return false;
}
return true;
@@ -1266,6 +1267,13 @@
return QualType();
}
+ // Do placeholder conversions on the array size expression.
+ if (ArraySize && ArraySize->hasPlaceholderType()) {
+ ExprResult Result = CheckPlaceholderExpr(ArraySize);
+ if (Result.isInvalid()) return QualType();
+ ArraySize = Result.take();
+ }
+
// Do lvalue-to-rvalue conversions on the array size expression.
if (ArraySize && !ArraySize->isRValue()) {
ExprResult Result = DefaultLvalueConversion(ArraySize);
@@ -1360,9 +1368,9 @@
else
Diag(Loc, diag::ext_vla);
} else if (ASM != ArrayType::Normal || Quals != 0)
- Diag(Loc,
+ Diag(Loc,
getLangOptions().CPlusPlus? diag::err_c99_array_usage_cxx
- : diag::ext_c99_array_usage);
+ : diag::ext_c99_array_usage) << ASM;
}
return T;
@@ -1787,6 +1795,9 @@
case Declarator::KNRTypeListContext:
llvm_unreachable("K&R type lists aren't allowed in C++");
break;
+ case Declarator::LambdaExprContext:
+ llvm_unreachable("Can't specify a type specifier in lambda grammar");
+ break;
case Declarator::ObjCParameterContext:
case Declarator::ObjCResultContext:
case Declarator::PrototypeContext:
@@ -1877,6 +1888,7 @@
case Declarator::BlockContext:
case Declarator::ForContext:
case Declarator::BlockLiteralContext:
+ case Declarator::LambdaExprContext:
// C++0x [dcl.type]p3:
// A type-specifier-seq shall not define a class or enumeration unless
// it appears in the type-id of an alias-declaration (7.1.3) that is not
@@ -1960,7 +1972,6 @@
state.setCurrentChunkIndex(chunkIndex);
DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
switch (DeclType.Kind) {
- default: llvm_unreachable("Unknown decltype!");
case DeclaratorChunk::Paren:
T = S.BuildParenType(T);
break;
@@ -2060,7 +2071,8 @@
diag::err_trailing_return_in_parens)
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
- } else if (T.hasQualifiers() || !isa<AutoType>(T)) {
+ } else if (D.getContext() != Declarator::LambdaExprContext &&
+ (T.hasQualifiers() || !isa<AutoType>(T))) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
@@ -2372,7 +2384,8 @@
// top-level template type arguments.
bool FreeFunction;
if (!D.getCXXScopeSpec().isSet()) {
- FreeFunction = (D.getContext() != Declarator::MemberContext ||
+ FreeFunction = ((D.getContext() != Declarator::MemberContext &&
+ D.getContext() != Declarator::LambdaExprContext) ||
D.getDeclSpec().isFriendSpecified());
} else {
DeclContext *DC = S.computeDeclContext(D.getCXXScopeSpec());
@@ -2580,6 +2593,7 @@
case Declarator::CXXCatchContext:
case Declarator::ObjCCatchContext:
case Declarator::BlockLiteralContext:
+ case Declarator::LambdaExprContext:
case Declarator::TemplateTypeArgContext:
// FIXME: We may want to allow parameter packs in block-literal contexts
// in the future.
@@ -4062,8 +4076,23 @@
// "Can't ask whether a dependent type is complete");
// If we have a complete type, we're done.
- if (!T->isIncompleteType())
+ NamedDecl *Def = 0;
+ if (!T->isIncompleteType(&Def)) {
+ // If we know about the definition but it is not visible, complain.
+ if (diag != 0 && Def && !LookupResult::isVisible(Def)) {
+ // Suppress this error outside of a SFINAE context if we've already
+ // emitted the error once for this type. There's no usefulness in
+ // repeating the diagnostic.
+ // FIXME: Add a Fix-It that imports the corresponding module or includes
+ // the header.
+ if (isSFINAEContext() || HiddenDefinitions.insert(Def)) {
+ Diag(Loc, diag::err_module_private_definition) << T;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ }
+ }
+
return false;
+ }
const TagType *Tag = T->getAs<TagType>();
const ObjCInterfaceType *IFace = 0;
Modified: cfe/branches/tooling/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Sema/TreeTransform.h?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Sema/TreeTransform.h (original)
+++ cfe/branches/tooling/lib/Sema/TreeTransform.h Fri Jan 20 10:14:22 2012
@@ -1890,6 +1890,7 @@
ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
QualType ThisType,
bool isImplicit) {
+ getSema().CheckCXXThisCapture(ThisLoc);
return getSema().Owned(
new (getSema().Context) CXXThisExpr(ThisLoc, ThisType,
isImplicit));
@@ -2898,7 +2899,7 @@
Expr *SourceExpr = Input.getSourceDeclExpression();
if (SourceExpr) {
EnterExpressionEvaluationContext Unevaluated(getSema(),
- Sema::Unevaluated);
+ Sema::ConstantEvaluated);
ExprResult E = getDerived().TransformExpr(SourceExpr);
SourceExpr = (E.isInvalid() ? 0 : E.take());
}
@@ -2932,9 +2933,9 @@
llvm_unreachable("Caller should expand pack expansions");
case TemplateArgument::Expression: {
- // Template argument expressions are not potentially evaluated.
+ // Template argument expressions are constant expressions.
EnterExpressionEvaluationContext Unevaluated(getSema(),
- Sema::Unevaluated);
+ Sema::ConstantEvaluated);
Expr *InputExpr = Input.getSourceExpression();
if (!InputExpr) InputExpr = Input.getArgument().getAsExpr();
@@ -3182,6 +3183,9 @@
template<typename Derived>
TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) {
+ // Refine the base location to the type's location.
+ TemporaryBase Rebase(*this, DI->getTypeLoc().getBeginLoc(),
+ getDerived().getBaseEntity());
if (getDerived().AlreadyTransformed(DI->getType()))
return DI;
@@ -3595,7 +3599,8 @@
Expr *Size = TL.getSizeExpr();
if (Size) {
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
Size = getDerived().TransformExpr(Size).template takeAs<Expr>();
}
NewTL.setSizeExpr(Size);
@@ -3640,9 +3645,6 @@
if (ElementType.isNull())
return QualType();
- // Array bounds are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
-
ExprResult SizeResult
= getDerived().TransformExpr(T->getSizeExpr());
if (SizeResult.isInvalid())
@@ -3680,8 +3682,9 @@
if (ElementType.isNull())
return QualType();
- // Array bounds are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ // Array bounds are constant expressions.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
// Prefer the expression from the TypeLoc; the other may have been uniqued.
Expr *origSize = TL.getSizeExpr();
@@ -3728,8 +3731,9 @@
if (ElementType.isNull())
return QualType();
- // Vector sizes are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ // Vector sizes are constant expressions.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
ExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
if (Size.isInvalid())
@@ -4980,8 +4984,8 @@
TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) {
ExprResult LHS, RHS;
{
- // The case value expressions are not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
// Transform the left-hand case value.
LHS = getDerived().TransformExpr(S->getLHS());
@@ -6874,11 +6878,11 @@
E->getLocEnd());
}
- // We don't know whether the expression is potentially evaluated until
- // after we perform semantic analysis, so the expression is potentially
+ // We don't know whether the subexpression is potentially evaluated until
+ // after we perform semantic analysis. We speculatively assume it is
+ // unevaluated; it will get fixed later if the subexpression is in fact
// potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::PotentiallyPotentiallyEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand());
if (SubExpr.isInvalid())
@@ -6913,9 +6917,6 @@
E->getLocEnd());
}
- // We don't know whether the expression is potentially evaluated until
- // after we perform semantic analysis, so the expression is potentially
- // potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand());
@@ -8114,10 +8115,6 @@
BlockScopeInfo *blockScope = SemaRef.getCurBlock();
blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic());
- // We built a new blockScopeInfo in call to ActOnBlockStart
- // in above, CapturesCXXThis need be set here from the block
- // expression.
- blockScope->CapturesCXXThis = oldBlock->capturesCXXThis();
blockScope->TheDecl->setBlockMissingReturnType(
oldBlock->blockMissingReturnType());
Modified: cfe/branches/tooling/lib/Serialization/ASTCommon.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/ASTCommon.h?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/ASTCommon.h (original)
+++ cfe/branches/tooling/lib/Serialization/ASTCommon.h Fri Jan 20 10:14:22 2012
@@ -22,12 +22,10 @@
namespace serialization {
enum DeclUpdateKind {
- UPD_CXX_SET_DEFINITIONDATA,
UPD_CXX_ADDED_IMPLICIT_MEMBER,
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
- UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
- UPD_OBJC_SET_CLASS_DEFINITIONDATA
+ UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER
};
TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);
Modified: cfe/branches/tooling/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/ASTReader.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/ASTReader.cpp (original)
+++ cfe/branches/tooling/lib/Serialization/ASTReader.cpp Fri Jan 20 10:14:22 2012
@@ -514,7 +514,7 @@
II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
Reader.SetIdentifierInfo(ID, II);
II->setIsFromAST();
- II->setOutOfDate(false);
+ Reader.markIdentifierUpToDate(II);
return II;
}
@@ -529,8 +529,8 @@
Bits >>= 1;
bool hasMacroDefinition = Bits & 0x01;
Bits >>= 1;
- unsigned ObjCOrBuiltinID = Bits & 0x3FF;
- Bits >>= 10;
+ unsigned ObjCOrBuiltinID = Bits & 0x7FF;
+ Bits >>= 11;
assert(Bits == 0 && "Extra bits in the identifier?");
DataLen -= 6;
@@ -540,7 +540,7 @@
IdentifierInfo *II = KnownII;
if (!II)
II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
- II->setOutOfDate(false);
+ Reader.markIdentifierUpToDate(II);
II->setIsFromAST();
// Set or check the various bits in the IdentifierInfo structure.
@@ -747,7 +747,7 @@
unsigned DataLen) {
using namespace clang::io;
unsigned NumDecls = ReadUnalignedLE16(d);
- DeclID *Start = (DeclID *)d;
+ LE32DeclID *Start = (LE32DeclID *)d;
return std::make_pair(Start, Start + NumDecls);
}
@@ -1398,10 +1398,8 @@
Macro->AddTokenToBody(Tok);
break;
}
+ }
}
- }
-
- return;
}
PreprocessedEntityID
@@ -1562,14 +1560,20 @@
/// \brief Visitor class used to look up identifirs in an AST file.
class IdentifierLookupVisitor {
StringRef Name;
+ unsigned PriorGeneration;
IdentifierInfo *Found;
public:
- explicit IdentifierLookupVisitor(StringRef Name) : Name(Name), Found() { }
+ IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration)
+ : Name(Name), PriorGeneration(PriorGeneration), Found() { }
static bool visit(ModuleFile &M, void *UserData) {
IdentifierLookupVisitor *This
= static_cast<IdentifierLookupVisitor *>(UserData);
+ // If we've already searched this module file, skip it now.
+ if (M.Generation <= This->PriorGeneration)
+ return true;
+
ASTIdentifierLookupTable *IdTable
= (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
if (!IdTable)
@@ -1595,7 +1599,24 @@
}
void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
- get(II.getName());
+ unsigned PriorGeneration = 0;
+ if (getContext().getLangOptions().Modules)
+ PriorGeneration = IdentifierGeneration[&II];
+
+ IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration);
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
+ markIdentifierUpToDate(&II);
+}
+
+void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
+ if (!II)
+ return;
+
+ II->setOutOfDate(false);
+
+ // Update the generation for this identifier.
+ if (getContext().getLangOptions().Modules)
+ IdentifierGeneration[II] = CurrentGeneration;
}
const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
@@ -1817,8 +1838,9 @@
GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F));
// Introduce the local -> global mapping for types within this module.
- F.TypeRemap.insert(std::make_pair(LocalBaseTypeIndex,
- F.BaseTypeIndex - LocalBaseTypeIndex));
+ F.TypeRemap.insertOrReplace(
+ std::make_pair(LocalBaseTypeIndex,
+ F.BaseTypeIndex - LocalBaseTypeIndex));
TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes);
}
@@ -1843,8 +1865,12 @@
// Introduce the local -> global mapping for declarations within this
// module.
- F.DeclRemap.insert(std::make_pair(LocalBaseDeclID,
- F.BaseDeclID - LocalBaseDeclID));
+ F.DeclRemap.insertOrReplace(
+ std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID));
+
+ // Introduce the global -> local mapping for declarations within this
+ // module.
+ F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID;
DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls);
}
@@ -1877,16 +1903,6 @@
break;
}
- case REDECLS_UPDATE_LATEST: {
- assert(Record.size() % 2 == 0 && "Expected pairs of DeclIDs");
- for (unsigned i = 0, e = Record.size(); i < e; /* in loop */) {
- DeclID First = ReadDeclID(F, Record, i);
- DeclID Latest = ReadDeclID(F, Record, i);
- FirstLatestDeclIDs[First] = Latest;
- }
- break;
- }
-
case LANGUAGE_OPTIONS:
if (ParseLanguageOptions(Record) && !DisableValidation)
return IgnorePCH;
@@ -1923,9 +1939,9 @@
// Introduce the local -> global mapping for identifiers within this
// module.
- F.IdentifierRemap.insert(
- std::make_pair(LocalBaseIdentifierID,
- F.BaseIdentifierID - LocalBaseIdentifierID));
+ F.IdentifierRemap.insertOrReplace(
+ std::make_pair(LocalBaseIdentifierID,
+ F.BaseIdentifierID - LocalBaseIdentifierID));
IdentifiersLoaded.resize(IdentifiersLoaded.size()
+ F.LocalNumIdentifiers);
@@ -2000,8 +2016,9 @@
// Introduce the local -> global mapping for selectors within this
// module.
- F.SelectorRemap.insert(std::make_pair(LocalBaseSelectorID,
- F.BaseSelectorID - LocalBaseSelectorID));
+ F.SelectorRemap.insertOrReplace(
+ std::make_pair(LocalBaseSelectorID,
+ F.BaseSelectorID - LocalBaseSelectorID));
SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors);
}
@@ -2125,6 +2142,9 @@
TypeRemap.insert(std::make_pair(TypeIndexOffset,
OM->BaseTypeIndex - TypeIndexOffset));
+
+ // Global -> local mappings.
+ F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
}
break;
}
@@ -2268,7 +2288,7 @@
// Introduce the local -> global mapping for preprocessed entities in
// this module.
- F.PreprocessedEntityRemap.insert(
+ F.PreprocessedEntityRemap.insertOrReplace(
std::make_pair(LocalBasePreprocessedEntityID,
F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID));
}
@@ -2396,7 +2416,32 @@
}
}
break;
+ }
+
+ case LOCAL_REDECLARATIONS: {
+ F.RedeclarationChains.swap(Record);
+ break;
+ }
+
+ case LOCAL_REDECLARATIONS_MAP: {
+ if (F.LocalNumRedeclarationsInMap != 0) {
+ Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
+ return Failure;
+ }
+ F.LocalNumRedeclarationsInMap = Record[0];
+ F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart;
+ break;
+ }
+
+ case MERGED_DECLARATIONS: {
+ for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) {
+ GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]);
+ SmallVectorImpl<GlobalDeclID> &Decls = StoredMergedDecls[CanonID];
+ for (unsigned N = Record[Idx++]; N > 0; --N)
+ Decls.push_back(getGlobalDeclID(F, Record[Idx++]));
+ }
+ break;
}
}
}
@@ -2477,9 +2522,15 @@
void ASTReader::makeNamesVisible(const HiddenNames &Names) {
for (unsigned I = 0, N = Names.size(); I != N; ++I) {
if (Decl *D = Names[I].dyn_cast<Decl *>())
- D->ModulePrivate = false;
- else
- Names[I].get<IdentifierInfo *>()->setHasMacroDefinition(true);
+ D->Hidden = false;
+ else {
+ IdentifierInfo *II = Names[I].get<IdentifierInfo *>();
+ if (!II->hasMacroDefinition()) {
+ II->setHasMacroDefinition(true);
+ if (DeserializationListener)
+ DeserializationListener->MacroVisible(II);
+ }
+ }
}
}
@@ -2498,6 +2549,11 @@
continue;
}
+ if (!Mod->isAvailable()) {
+ // Modules that aren't available cannot be made visible.
+ continue;
+ }
+
// Update the module's name visibility.
Mod->NameVisibility = NameVisibility;
@@ -2511,11 +2567,11 @@
// Push any non-explicit submodules onto the stack to be marked as
// visible.
- for (llvm::StringMap<Module *>::iterator Sub = Mod->SubModules.begin(),
- SubEnd = Mod->SubModules.end();
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
Sub != SubEnd; ++Sub) {
- if (!Sub->getValue()->IsExplicit && Visited.insert(Sub->getValue()))
- Stack.push_back(Sub->getValue());
+ if (!(*Sub)->IsExplicit && Visited.insert(*Sub))
+ Stack.push_back(*Sub);
}
// Push any exported modules onto the stack to be marked as visible.
@@ -2579,6 +2635,9 @@
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleKind Type) {
+ // Bump the generation number.
+ ++CurrentGeneration;
+
switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) {
case Failure: return Failure;
case IgnorePCH: return IgnorePCH;
@@ -2586,7 +2645,7 @@
}
// Here comes stuff that we only do once the entire chain is loaded.
-
+
// Check the predefines buffers.
if (!DisableValidation && Type == MK_PCH &&
// FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines;
@@ -2602,7 +2661,7 @@
IdEnd = PP.getIdentifierTable().end();
Id != IdEnd; ++Id)
Id->second->setOutOfDate(true);
-
+
// Resolve any unresolved module exports.
for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) {
UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I];
@@ -2626,14 +2685,17 @@
if (DeserializationListener)
DeserializationListener->ReaderInitialized(this);
- // If this AST file is a precompiled preamble, then set the preamble file ID
- // of the source manager to the file source file from which the preamble was
- // built.
- if (Type == MK_Preamble) {
- if (!OriginalFileID.isInvalid()) {
- OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID
- + OriginalFileID.getOpaqueValue() - 1);
+ if (!OriginalFileID.isInvalid()) {
+ OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID
+ + OriginalFileID.getOpaqueValue() - 1);
+
+ // If this AST file is a precompiled preamble, then set the preamble file ID
+ // of the source manager to the file source file from which the preamble was
+ // built.
+ if (Type == MK_Preamble) {
SourceMgr.setPreambleFileID(OriginalFileID);
+ } else if (Type == MK_MainFile) {
+ SourceMgr.setMainFileID(OriginalFileID);
}
}
@@ -2647,7 +2709,7 @@
bool NewModule;
std::string ErrorStr;
llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy,
- ErrorStr);
+ CurrentGeneration, ErrorStr);
if (!M) {
// We couldn't load the module.
@@ -2777,17 +2839,12 @@
// built-in types. Right now, we just ignore the problem.
// Load the special types.
- if (SpecialTypes.size() > NumSpecialTypeIDs) {
+ if (SpecialTypes.size() >= NumSpecialTypeIDs) {
if (Context.getBuiltinVaListType().isNull()) {
Context.setBuiltinVaListType(
GetType(SpecialTypes[SPECIAL_TYPE_BUILTIN_VA_LIST]));
}
- if (unsigned Proto = SpecialTypes[SPECIAL_TYPE_OBJC_PROTOCOL]) {
- if (Context.ObjCProtoType.isNull())
- Context.ObjCProtoType = GetType(Proto);
- }
-
if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) {
if (!Context.CFConstantStringTypeDecl)
Context.setCFConstantStringType(GetType(String));
@@ -3077,6 +3134,7 @@
return Failure;
}
+ CurrentModule->IsFromModuleFile = true;
CurrentModule->InferSubmodules = InferSubmodules;
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
@@ -3167,7 +3225,7 @@
// Introduce the local -> global mapping for submodules within this
// module.
- F.SubmoduleRemap.insert(
+ F.SubmoduleRemap.insertOrReplace(
std::make_pair(LocalBaseSubmoduleID,
F.BaseSubmoduleID - LocalBaseSubmoduleID));
@@ -3221,10 +3279,21 @@
CurrentModule->UnresolvedExports.clear();
break;
}
+ case SUBMODULE_REQUIRES: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return Failure;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ CurrentModule->addRequirement(StringRef(BlobStart, BlobLen),
+ Context.getLangOptions());
+ break;
+ }
}
}
-
- return Success;
}
/// \brief Parse the record that corresponds to a LangOptions data
@@ -3361,9 +3430,8 @@
return ID;
}
}
-
- Error("invalid offset in preprocessor detail block");
- return 0;
+
+ llvm_unreachable("Invalid PreprocessorDetailRecordTypes");
}
/// \brief \arg SLocMapI points at a chunk of a module that contains no
@@ -3859,8 +3927,9 @@
}
unsigned Idx = 0;
bool IsDependent = Record[Idx++];
- QualType T
- = Context.getRecordType(ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx));
+ RecordDecl *RD = ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx);
+ RD = cast_or_null<RecordDecl>(RD->getCanonicalDecl());
+ QualType T = Context.getRecordType(RD);
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
return T;
}
@@ -3924,7 +3993,7 @@
unsigned Idx = 0;
ObjCInterfaceDecl *ItfD
= ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx);
- return Context.getObjCInterfaceType(ItfD);
+ return Context.getObjCInterfaceType(ItfD->getCanonicalDecl());
}
case TYPE_OBJC_OBJECT: {
@@ -4049,8 +4118,7 @@
return Context.getAtomicType(ValueType);
}
}
- // Suppress a GCC warning
- return QualType();
+ llvm_unreachable("Invalid TypeCode!");
}
class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
@@ -4431,7 +4499,6 @@
return TemplateArgumentLocInfo();
}
llvm_unreachable("unexpected template argument loc");
- return TemplateArgumentLocInfo();
}
TemplateArgumentLoc
@@ -4539,6 +4606,9 @@
case PREDEF_DECL_OBJC_CLASS_ID:
return Context.getObjCClassDecl();
+ case PREDEF_DECL_OBJC_PROTOCOL_ID:
+ return Context.getObjCProtocolDecl();
+
case PREDEF_DECL_INT_128_ID:
return Context.getInt128Decl();
@@ -4548,15 +4618,12 @@
case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
return Context.getObjCInstanceTypeDecl();
}
-
- return 0;
}
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
- if (Index > DeclsLoaded.size()) {
+ if (Index >= DeclsLoaded.size()) {
Error("declaration ID out-of-range for AST file");
- return 0;
}
if (!DeclsLoaded[Index]) {
@@ -4568,6 +4635,23 @@
return DeclsLoaded[Index];
}
+DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
+ DeclID GlobalID) {
+ if (GlobalID < NUM_PREDEF_DECL_IDS)
+ return GlobalID;
+
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID);
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ ModuleFile *Owner = I->second;
+
+ llvm::DenseMap<ModuleFile *, serialization::DeclID>::iterator Pos
+ = M.GlobalToLocalDeclIDs.find(Owner);
+ if (Pos == M.GlobalToLocalDeclIDs.end())
+ return 0;
+
+ return GlobalID - Owner->BaseDeclID + Pos->second;
+}
+
serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F,
const RecordData &Record,
unsigned &Idx) {
@@ -4744,15 +4828,17 @@
/// declaration context.
class DeclContextNameLookupVisitor {
ASTReader &Reader;
+ llvm::SmallVectorImpl<const DeclContext *> &Contexts;
const DeclContext *DC;
DeclarationName Name;
SmallVectorImpl<NamedDecl *> &Decls;
public:
DeclContextNameLookupVisitor(ASTReader &Reader,
- const DeclContext *DC, DeclarationName Name,
+ SmallVectorImpl<const DeclContext *> &Contexts,
+ DeclarationName Name,
SmallVectorImpl<NamedDecl *> &Decls)
- : Reader(Reader), DC(DC), Name(Name), Decls(Decls) { }
+ : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { }
static bool visit(ModuleFile &M, void *UserData) {
DeclContextNameLookupVisitor *This
@@ -4760,11 +4846,20 @@
// Check whether we have any visible declaration information for
// this context in this module.
- ModuleFile::DeclContextInfosMap::iterator Info
- = M.DeclContextInfos.find(This->DC);
- if (Info == M.DeclContextInfos.end() || !Info->second.NameLookupTableData)
- return false;
+ ModuleFile::DeclContextInfosMap::iterator Info;
+ bool FoundInfo = false;
+ for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
+ Info = M.DeclContextInfos.find(This->Contexts[I]);
+ if (Info != M.DeclContextInfos.end() &&
+ Info->second.NameLookupTableData) {
+ FoundInfo = true;
+ break;
+ }
+ }
+ if (!FoundInfo)
+ return false;
+
// Look for this name within this module.
ASTDeclContextNameLookupTable *LookupTable =
(ASTDeclContextNameLookupTable*)Info->second.NameLookupTableData;
@@ -4806,7 +4901,24 @@
DeclContext::lookup_iterator(0));
SmallVector<NamedDecl *, 64> Decls;
- DeclContextNameLookupVisitor Visitor(*this, DC, Name, Decls);
+
+ // Compute the declaration contexts we need to look into. Multiple such
+ // declaration contexts occur when two declaration contexts from disjoint
+ // modules get merged, e.g., when two namespaces with the same name are
+ // independently defined in separate modules.
+ SmallVector<const DeclContext *, 2> Contexts;
+ Contexts.push_back(DC);
+
+ if (DC->isNamespace()) {
+ MergedDeclsMap::iterator Merged
+ = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+ if (Merged != MergedDecls.end()) {
+ for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
+ Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
+ }
+ }
+
+ DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
++NumVisibleDeclContextsRead;
SetExternalVisibleDeclsForName(DC, Name, Decls);
@@ -5023,11 +5135,11 @@
}
IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
- IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart));
+ IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart),
+ /*PriorGeneration=*/0);
ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
IdentifierInfo *II = Visitor.getIdentifierInfo();
- if (II)
- II->setOutOfDate(false);
+ markIdentifierUpToDate(II);
return II;
}
@@ -5539,8 +5651,7 @@
return DeclarationName::getUsingDirectiveName();
}
- // Required to silence GCC warning
- return DeclarationName();
+ llvm_unreachable("Invalid NameKind!");
}
void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
@@ -6024,59 +6135,120 @@
SwitchCaseStmts.clear();
}
+void ASTReader::finishPendingActions() {
+ while (!PendingIdentifierInfos.empty() ||
+ !PendingDeclChains.empty() ||
+ !PendingChainedObjCCategories.empty()) {
+
+ // If any identifiers with corresponding top-level declarations have
+ // been loaded, load those declarations now.
+ while (!PendingIdentifierInfos.empty()) {
+ SetGloballyVisibleDecls(PendingIdentifierInfos.front().II,
+ PendingIdentifierInfos.front().DeclIDs, true);
+ PendingIdentifierInfos.pop_front();
+ }
+
+ // Load pending declaration chains.
+ for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
+ loadPendingDeclChain(PendingDeclChains[I]);
+ PendingDeclChainsKnown.erase(PendingDeclChains[I]);
+ }
+ PendingDeclChains.clear();
+
+ for (std::vector<std::pair<ObjCInterfaceDecl *,
+ serialization::DeclID> >::iterator
+ I = PendingChainedObjCCategories.begin(),
+ E = PendingChainedObjCCategories.end(); I != E; ++I) {
+ loadObjCChainedCategories(I->second, I->first);
+ }
+ PendingChainedObjCCategories.clear();
+ }
+
+ // If we deserialized any C++ or Objective-C class definitions, any
+ // Objective-C protocol definitions, or any redeclarable templates, make sure
+ // that all redeclarations point to the definitions. Note that this can only
+ // happen now, after the redeclaration chains have been fully wired.
+ for (llvm::SmallPtrSet<Decl *, 4>::iterator D = PendingDefinitions.begin(),
+ DEnd = PendingDefinitions.end();
+ D != DEnd; ++D) {
+ if (TagDecl *TD = dyn_cast<TagDecl>(*D)) {
+ if (const TagType *TagT = dyn_cast<TagType>(TD->TypeForDecl)) {
+ // Make sure that the TagType points at the definition.
+ const_cast<TagType*>(TagT)->decl = TD;
+ }
+
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(*D)) {
+ for (CXXRecordDecl::redecl_iterator R = RD->redecls_begin(),
+ REnd = RD->redecls_end();
+ R != REnd; ++R)
+ cast<CXXRecordDecl>(*R)->DefinitionData = RD->DefinitionData;
+
+ }
+
+ continue;
+ }
+
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(*D)) {
+ // Make sure that the ObjCInterfaceType points at the definition.
+ const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl))
+ ->Decl = ID;
+
+ for (ObjCInterfaceDecl::redecl_iterator R = ID->redecls_begin(),
+ REnd = ID->redecls_end();
+ R != REnd; ++R)
+ R->Data = ID->Data;
+
+ continue;
+ }
+
+ if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(*D)) {
+ for (ObjCProtocolDecl::redecl_iterator R = PD->redecls_begin(),
+ REnd = PD->redecls_end();
+ R != REnd; ++R)
+ R->Data = PD->Data;
+
+ continue;
+ }
+
+ RedeclarableTemplateDecl *RTD
+ = cast<RedeclarableTemplateDecl>(*D)->getCanonicalDecl();
+ for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(),
+ REnd = RTD->redecls_end();
+ R != REnd; ++R)
+ R->Common = RTD->Common;
+ }
+ PendingDefinitions.clear();
+}
+
void ASTReader::FinishedDeserializing() {
assert(NumCurrentElementsDeserializing &&
"FinishedDeserializing not paired with StartedDeserializing");
if (NumCurrentElementsDeserializing == 1) {
- // Fully load the interesting decls, including deserializing their bodies,
- // so that any other declarations that get referenced in the body will be
- // fully deserialized by the time we pass them to the consumer.
- for (std::deque<Decl *>::iterator
- I = InterestingDecls.begin(),
- E = InterestingDecls.end(); I != E; ++I)
- (*I)->getBody();
-
- do {
- // If any identifiers with corresponding top-level declarations have
- // been loaded, load those declarations now.
- while (!PendingIdentifierInfos.empty()) {
- SetGloballyVisibleDecls(PendingIdentifierInfos.front().II,
- PendingIdentifierInfos.front().DeclIDs, true);
- PendingIdentifierInfos.pop_front();
- }
-
- // Ready to load previous declarations of Decls that were delayed.
- while (!PendingPreviousDecls.empty()) {
- loadAndAttachPreviousDecl(PendingPreviousDecls.front().first,
- PendingPreviousDecls.front().second);
- PendingPreviousDecls.pop_front();
- }
-
- for (std::vector<std::pair<ObjCInterfaceDecl *,
- serialization::DeclID> >::iterator
- I = PendingChainedObjCCategories.begin(),
- E = PendingChainedObjCCategories.end(); I != E; ++I) {
- loadObjCChainedCategories(I->second, I->first);
- }
- PendingChainedObjCCategories.clear();
-
+ while (Consumer && !InterestingDecls.empty()) {
+ finishPendingActions();
+
// We are not in recursive loading, so it's safe to pass the "interesting"
// decls to the consumer.
- if (Consumer && !InterestingDecls.empty()) {
- Decl *D = InterestingDecls.front();
- InterestingDecls.pop_front();
+ Decl *D = InterestingDecls.front();
+ InterestingDecls.pop_front();
- PassInterestingDeclToConsumer(D);
+ // Fully load the interesting decls, including deserializing their
+ // bodies, so that any other declarations that get referenced in the
+ // body will be fully deserialized by the time we pass them to the
+ // consumer.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->doesThisDeclarationHaveABody()) {
+ FD->getBody();
+ finishPendingActions();
+ }
}
- } while ((Consumer && !InterestingDecls.empty()) ||
- !PendingIdentifierInfos.empty() ||
- !PendingPreviousDecls.empty() ||
- !PendingChainedObjCCategories.empty());
+ PassInterestingDeclToConsumer(D);
+ }
- assert(PendingForwardRefs.size() == 0 &&
- "Some forward refs did not get linked to the definition!");
+ finishPendingActions();
+ PendingDeclChainsKnown.clear();
}
--NumCurrentElementsDeserializing;
}
@@ -6090,7 +6262,8 @@
Consumer(0), ModuleMgr(FileMgr.getFileSystemOptions()),
RelocatablePCH(false), isysroot(isysroot),
DisableValidation(DisableValidation),
- DisableStatCache(DisableStatCache), NumStatHits(0), NumStatMisses(0),
+ DisableStatCache(DisableStatCache),
+ CurrentGeneration(0), NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), TotalNumSLocEntries(0),
NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
Modified: cfe/branches/tooling/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/ASTReaderDecl.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/branches/tooling/lib/Serialization/ASTReaderDecl.cpp Fri Jan 20 10:14:22 2012
@@ -14,6 +14,8 @@
#include "ASTCommon.h"
#include "clang/Serialization/ASTReader.h"
+#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -101,9 +103,93 @@
void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
const RecordData &R, unsigned &I);
- void InitializeCXXDefinitionData(CXXRecordDecl *D,
- CXXRecordDecl *DefinitionDecl,
- const RecordData &Record, unsigned &Idx);
+ /// \brief RAII class used to capture the first ID within a redeclaration
+ /// chain and to introduce it into the list of pending redeclaration chains
+ /// on destruction.
+ ///
+ /// The caller can choose not to introduce this ID into the redeclaration
+ /// chain by calling \c suppress().
+ class RedeclarableResult {
+ ASTReader &Reader;
+ GlobalDeclID FirstID;
+ mutable bool Owning;
+
+ RedeclarableResult &operator=(RedeclarableResult&); // DO NOT IMPLEMENT
+
+ public:
+ RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID)
+ : Reader(Reader), FirstID(FirstID), Owning(true) { }
+
+ RedeclarableResult(const RedeclarableResult &Other)
+ : Reader(Other.Reader), FirstID(Other.FirstID), Owning(Other.Owning)
+ {
+ Other.Owning = false;
+ }
+
+ ~RedeclarableResult() {
+ // FIXME: We want to suppress this when the declaration is local to
+ // a function, since there's no reason to search other AST files
+ // for redeclarations (they can't exist). However, this is hard to
+ // do locally because the declaration hasn't necessarily loaded its
+ // declaration context yet. Also, local externs still have the function
+ // as their (semantic) declaration context, which is wrong and would
+ // break this optimize.
+
+ if (FirstID && Owning && Reader.PendingDeclChainsKnown.insert(FirstID))
+ Reader.PendingDeclChains.push_back(FirstID);
+ }
+
+ /// \brief Retrieve the first ID.
+ GlobalDeclID getFirstID() const { return FirstID; }
+
+ /// \brief Do not introduce this declaration ID into the set of pending
+ /// declaration chains.
+ void suppress() {
+ Owning = false;
+ }
+ };
+
+ /// \brief Class used to capture the result of searching for an existing
+ /// declaration of a specific kind and name, along with the ability
+ /// to update the place where this result was found (the declaration
+ /// chain hanging off an identifier or the DeclContext we searched in)
+ /// if requested.
+ class FindExistingResult {
+ ASTReader &Reader;
+ NamedDecl *New;
+ NamedDecl *Existing;
+ mutable bool AddResult;
+
+ FindExistingResult &operator=(FindExistingResult&); // DO NOT IMPLEMENT
+
+ public:
+ FindExistingResult(ASTReader &Reader)
+ : Reader(Reader), New(0), Existing(0), AddResult(false) { }
+
+ FindExistingResult(ASTReader &Reader, NamedDecl *New, NamedDecl *Existing)
+ : Reader(Reader), New(New), Existing(Existing), AddResult(true) { }
+
+ FindExistingResult(const FindExistingResult &Other)
+ : Reader(Other.Reader), New(Other.New), Existing(Other.Existing),
+ AddResult(Other.AddResult)
+ {
+ Other.AddResult = false;
+ }
+
+ ~FindExistingResult();
+
+ /// \brief Suppress the addition of this result into the known set of
+ /// names.
+ void suppress() { AddResult = false; }
+
+ operator NamedDecl*() const { return Existing; }
+
+ template<typename T>
+ operator T*() const { return dyn_cast_or_null<T>(Existing); }
+ };
+
+ FindExistingResult findExisting(NamedDecl *D);
+
public:
ASTDeclReader(ASTReader &Reader, ModuleFile &F,
llvm::BitstreamCursor &Cursor, DeclID thisDeclID,
@@ -114,6 +200,7 @@
TypeIDForTypeDecl(0) { }
static void attachPreviousDecl(Decl *D, Decl *previous);
+ static void attachLatestDecl(Decl *D, Decl *latest);
void Visit(Decl *D);
@@ -133,6 +220,7 @@
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *TD);
+ void VisitTypedefNameDecl(TypedefNameDecl *TD);
void VisitTypedefDecl(TypedefDecl *TD);
void VisitTypeAliasDecl(TypeAliasDecl *TD);
void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
@@ -163,7 +251,7 @@
void VisitParmVarDecl(ParmVarDecl *PD);
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
void VisitTemplateDecl(TemplateDecl *D);
- void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
+ RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
@@ -180,8 +268,13 @@
void VisitBlockDecl(BlockDecl *BD);
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
- template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
+
+ template<typename T>
+ RedeclarableResult VisitRedeclarable(Redeclarable<T> *D);
+ template<typename T>
+ void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl);
+
// FIXME: Reorder according to DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
@@ -189,8 +282,6 @@
void VisitObjCIvarDecl(ObjCIvarDecl *D);
void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
- void VisitObjCClassDecl(ObjCClassDecl *D);
- void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
void VisitObjCImplDecl(ObjCImplDecl *D);
void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
@@ -265,21 +356,24 @@
D->setImplicit(Record[Idx++]);
D->setUsed(Record[Idx++]);
D->setReferenced(Record[Idx++]);
- D->TopLevelDeclInObjCContainer = Record[Idx++];
+ D->setTopLevelDeclInObjCContainer(Record[Idx++]);
D->setAccess((AccessSpecifier)Record[Idx++]);
D->FromASTFile = true;
- D->ModulePrivate = Record[Idx++];
-
+ D->setModulePrivate(Record[Idx++]);
+ D->Hidden = D->isModulePrivate();
+
// Determine whether this declaration is part of a (sub)module. If so, it
// may not yet be visible.
if (unsigned SubmoduleID = readSubmoduleID(Record, Idx)) {
+ // Store the owning submodule ID in the declaration.
+ D->setOwningModuleID(SubmoduleID);
+
// Module-private declarations are never visible, so there is no work to do.
- if (!D->ModulePrivate) {
+ if (!D->isModulePrivate()) {
if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
if (Owner->NameVisibility != Module::AllVisible) {
- // The owning module is not visible. Mark this declaration as
- // module-private,
- D->ModulePrivate = true;
+ // The owning module is not visible. Mark this declaration as hidden.
+ D->Hidden = true;
// Note that this declaration was hidden because its owning module is
// not yet visible.
@@ -306,31 +400,41 @@
TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
}
-void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
+void ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) {
+ RedeclarableResult Redecl = VisitRedeclarable(TD);
VisitTypeDecl(TD);
+
TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+ mergeRedeclarable(TD, Redecl);
+}
+
+void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
+ VisitTypedefNameDecl(TD);
}
void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) {
- VisitTypeDecl(TD);
- TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+ VisitTypedefNameDecl(TD);
}
void ASTDeclReader::VisitTagDecl(TagDecl *TD) {
- VisitRedeclarable(TD);
+ RedeclarableResult Redecl = VisitRedeclarable(TD);
VisitTypeDecl(TD);
+
TD->IdentifierNamespace = Record[Idx++];
TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
TD->setCompleteDefinition(Record[Idx++]);
TD->setEmbeddedInDeclarator(Record[Idx++]);
TD->setFreeStanding(Record[Idx++]);
TD->setRBraceLoc(ReadSourceLocation(Record, Idx));
+
if (Record[Idx++]) { // hasExtInfo
TagDecl::ExtInfo *Info = new (Reader.getContext()) TagDecl::ExtInfo();
ReadQualifierInfo(*Info, Record, Idx);
TD->TypedefNameDeclOrQualifier = Info;
} else
TD->setTypedefNameForAnonDecl(ReadDeclAs<TypedefNameDecl>(Record, Idx));
+
+ mergeRedeclarable(TD, Redecl);
}
void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
@@ -379,14 +483,34 @@
}
void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
- VisitRedeclarable(FD);
+ RedeclarableResult Redecl = VisitRedeclarable(FD);
VisitDeclaratorDecl(FD);
ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName(), Record, Idx);
FD->IdentifierNamespace = Record[Idx++];
+
+ // FunctionDecl's body is handled last at ASTDeclReader::Visit,
+ // after everything else is read.
+
+ FD->SClass = (StorageClass)Record[Idx++];
+ FD->SClassAsWritten = (StorageClass)Record[Idx++];
+ FD->IsInline = Record[Idx++];
+ FD->IsInlineSpecified = Record[Idx++];
+ FD->IsVirtualAsWritten = Record[Idx++];
+ FD->IsPure = Record[Idx++];
+ FD->HasInheritedPrototype = Record[Idx++];
+ FD->HasWrittenPrototype = Record[Idx++];
+ FD->IsDeleted = Record[Idx++];
+ FD->IsTrivial = Record[Idx++];
+ FD->IsDefaulted = Record[Idx++];
+ FD->IsExplicitlyDefaulted = Record[Idx++];
+ FD->HasImplicitReturnZero = Record[Idx++];
+ FD->IsConstexpr = Record[Idx++];
+ FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
+
switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
- default: llvm_unreachable("Unhandled TemplatedKind!");
case FunctionDecl::TK_NonTemplate:
+ mergeRedeclarable(FD, Redecl);
break;
case FunctionDecl::TK_FunctionTemplate:
FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>(Record,
@@ -480,25 +604,6 @@
}
}
- // FunctionDecl's body is handled last at ASTDeclReader::Visit,
- // after everything else is read.
-
- FD->SClass = (StorageClass)Record[Idx++];
- FD->SClassAsWritten = (StorageClass)Record[Idx++];
- FD->IsInline = Record[Idx++];
- FD->IsInlineSpecified = Record[Idx++];
- FD->IsVirtualAsWritten = Record[Idx++];
- FD->IsPure = Record[Idx++];
- FD->HasInheritedPrototype = Record[Idx++];
- FD->HasWrittenPrototype = Record[Idx++];
- FD->IsDeleted = Record[Idx++];
- FD->IsTrivial = Record[Idx++];
- FD->IsDefaulted = Record[Idx++];
- FD->IsExplicitlyDefaulted = Record[Idx++];
- FD->HasImplicitReturnZero = Record[Idx++];
- FD->IsConstexpr = Record[Idx++];
- FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
-
// Read in the parameters.
unsigned NumParams = Record[Idx++];
SmallVector<ParmVarDecl *, 16> Params;
@@ -557,15 +662,19 @@
}
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
- VisitRedeclarable(ID);
+ RedeclarableResult Redecl = VisitRedeclarable(ID);
VisitObjCContainerDecl(ID);
TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
+ mergeRedeclarable(ID, Redecl);
- ObjCInterfaceDecl *Def = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
- if (ID == Def) {
+ if (Record[Idx++]) {
// Read the definition.
ID->allocateDefinitionData();
+ // Set the definition data of the canonical declaration, so other
+ // redeclarations will see it.
+ ID->getCanonicalDecl()->Data = ID->Data;
+
ObjCInterfaceDecl::DefinitionData &Data = ID->data();
// Read the superclass.
@@ -609,29 +718,10 @@
// We will rebuild this list lazily.
ID->setIvarList(0);
- // If there are any pending forward references, make their definition data
- // pointers point at the newly-allocated data.
- ASTReader::PendingForwardRefsMap::iterator
- FindI = Reader.PendingForwardRefs.find(ID);
- if (FindI != Reader.PendingForwardRefs.end()) {
- ASTReader::ForwardRefs &Refs = FindI->second;
- for (ASTReader::ForwardRefs::iterator I = Refs.begin(),
- E = Refs.end();
- I != E; ++I)
- cast<ObjCInterfaceDecl>(*I)->Data = ID->Data;
-#ifndef NDEBUG
- // We later check whether PendingForwardRefs is empty to make sure all
- // pending references were linked.
- Reader.PendingForwardRefs.erase(ID);
-#endif
- }
- } else if (Def) {
- if (Def->Data) {
- ID->Data = Def->Data;
- } else {
- // The definition is still initializing.
- Reader.PendingForwardRefs[Def].push_back(ID);
- }
+ // Note that we have deserialized a definition.
+ Reader.PendingDefinitions.insert(ID);
+ } else {
+ ID->Data = ID->getCanonicalDecl()->Data;
}
}
@@ -645,48 +735,41 @@
}
void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
+ RedeclarableResult Redecl = VisitRedeclarable(PD);
VisitObjCContainerDecl(PD);
- PD->InitiallyForwardDecl = Record[Idx++];
- PD->isForwardProtoDecl = Record[Idx++];
- PD->setLocEnd(ReadSourceLocation(Record, Idx));
- unsigned NumProtoRefs = Record[Idx++];
- SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
- ProtoRefs.reserve(NumProtoRefs);
- for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
- SmallVector<SourceLocation, 16> ProtoLocs;
- ProtoLocs.reserve(NumProtoRefs);
- for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
- PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
- Reader.getContext());
+ mergeRedeclarable(PD, Redecl);
+
+ if (Record[Idx++]) {
+ // Read the definition.
+ PD->allocateDefinitionData();
+
+ // Set the definition data of the canonical declaration, so other
+ // redeclarations will see it.
+ PD->getCanonicalDecl()->Data = PD->Data;
+
+ unsigned NumProtoRefs = Record[Idx++];
+ SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ ProtoRefs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
+ PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
+ Reader.getContext());
+
+ // Note that we have deserialized a definition.
+ Reader.PendingDefinitions.insert(PD);
+ } else {
+ PD->Data = PD->getCanonicalDecl()->Data;
+ }
}
void ASTDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) {
VisitFieldDecl(FD);
}
-void ASTDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) {
- VisitDecl(CD);
- CD->Interface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
- CD->InterfaceLoc = ReadSourceLocation(Record, Idx);
-}
-
-void ASTDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) {
- VisitDecl(FPD);
- unsigned NumProtoRefs = Record[Idx++];
- SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
- ProtoRefs.reserve(NumProtoRefs);
- for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
- SmallVector<SourceLocation, 16> ProtoLocs;
- ProtoLocs.reserve(NumProtoRefs);
- for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
- FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
- Reader.getContext());
-}
-
void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
VisitObjCContainerDecl(CD);
CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
@@ -786,8 +869,9 @@
}
void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
- VisitRedeclarable(VD);
+ RedeclarableResult Redecl = VisitRedeclarable(VD);
VisitDeclaratorDecl(VD);
+
VD->VarDeclBits.SClass = (StorageClass)Record[Idx++];
VD->VarDeclBits.SClassAsWritten = (StorageClass)Record[Idx++];
VD->VarDeclBits.ThreadSpecified = Record[Idx++];
@@ -796,8 +880,19 @@
VD->VarDeclBits.NRVOVariable = Record[Idx++];
VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
- if (Record[Idx++])
+
+ // Only true variables (not parameters or implicit parameters) can be merged.
+ if (VD->getKind() == Decl::Var)
+ mergeRedeclarable(VD, Redecl);
+
+ if (uint64_t Val = Record[Idx++]) {
VD->setInit(Reader.ReadExpr(F));
+ if (Val > 1) {
+ EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
+ Eval->CheckedICE = true;
+ Eval->IsICE = Val == 3;
+ }
+ }
if (Record[Idx++]) { // HasMemberSpecializationInfo.
VarDecl *Tmpl = ReadDeclAs<VarDecl>(Record, Idx);
@@ -878,17 +973,25 @@
void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
- D->IsInline = Record[Idx++];
+ D->setInline(Record[Idx++]);
D->LocStart = ReadSourceLocation(Record, Idx);
D->RBraceLoc = ReadSourceLocation(Record, Idx);
- D->NextNamespace = Record[Idx++];
+ mergeRedeclarable(D, Redecl);
- bool IsOriginal = Record[Idx++];
- // FIXME: Modules will likely have trouble with pointing directly at
- // the original namespace.
- D->OrigOrAnonNamespace.setInt(IsOriginal);
- D->OrigOrAnonNamespace.setPointer(ReadDeclAs<NamespaceDecl>(Record, Idx));
+ if (Redecl.getFirstID() == ThisDeclID) {
+ // Each module has its own anonymous namespace, which is disjoint from
+ // any other module's anonymous namespaces, so don't attach the anonymous
+ // namespace at all.
+ NamespaceDecl *Anon = ReadDeclAs<NamespaceDecl>(Record, Idx);
+ if (F.Kind != MK_Module)
+ D->setAnonymousNamespace(Anon);
+ } else {
+ // Link this namespace back to the first declaration, which has already
+ // been deserialized.
+ D->AnonOrFirstNamespaceAndInline.setPointer(D->getFirstDeclaration());
+ }
}
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
@@ -904,7 +1007,7 @@
D->setUsingLocation(ReadSourceLocation(Record, Idx));
D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx);
- D->FirstUsingShadow = ReadDeclAs<UsingShadowDecl>(Record, Idx);
+ D->FirstUsingShadow.setPointer(ReadDeclAs<UsingShadowDecl>(Record, Idx));
D->setTypeName(Record[Idx++]);
if (NamedDecl *Pattern = ReadDeclAs<NamedDecl>(Record, Idx))
Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern);
@@ -994,54 +1097,33 @@
Data.FirstFriend = ReadDeclAs<FriendDecl>(Record, Idx);
}
-void ASTDeclReader::InitializeCXXDefinitionData(CXXRecordDecl *D,
- CXXRecordDecl *DefinitionDecl,
- const RecordData &Record,
- unsigned &Idx) {
- ASTContext &C = Reader.getContext();
-
- if (D == DefinitionDecl) {
- D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
- ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
- // We read the definition info. Check if there are pending forward
- // references that need to point to this DefinitionData pointer.
- ASTReader::PendingForwardRefsMap::iterator
- FindI = Reader.PendingForwardRefs.find(D);
- if (FindI != Reader.PendingForwardRefs.end()) {
- ASTReader::ForwardRefs &Refs = FindI->second;
- for (ASTReader::ForwardRefs::iterator
- I = Refs.begin(), E = Refs.end(); I != E; ++I)
- cast<CXXRecordDecl>(*I)->DefinitionData = D->DefinitionData;
-#ifndef NDEBUG
- // We later check whether PendingForwardRefs is empty to make sure all
- // pending references were linked.
- Reader.PendingForwardRefs.erase(D);
-#endif
- }
- } else if (DefinitionDecl) {
- if (DefinitionDecl->DefinitionData) {
- D->DefinitionData = DefinitionDecl->DefinitionData;
- } else {
- // The definition is still initializing.
- Reader.PendingForwardRefs[DefinitionDecl].push_back(D);
- }
- }
-}
-
void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
VisitRecordDecl(D);
- CXXRecordDecl *DefinitionDecl = ReadDeclAs<CXXRecordDecl>(Record, Idx);
- InitializeCXXDefinitionData(D, DefinitionDecl, Record, Idx);
-
ASTContext &C = Reader.getContext();
+ if (Record[Idx++]) {
+ D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
+
+ // Propagate the DefinitionData pointer to the canonical declaration, so
+ // that all other deserialized declarations will see it.
+ // FIXME: Complain if there already is a DefinitionData!
+ D->getCanonicalDecl()->DefinitionData = D->DefinitionData;
+
+ ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
+
+ // Note that we have deserialized a definition. Any declarations
+ // deserialized before this one will be be given the DefinitionData pointer
+ // at the end.
+ Reader.PendingDefinitions.insert(D);
+ } else {
+ // Propagate DefinitionData pointer from the canonical declaration.
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+ }
enum CXXRecKind {
CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
};
switch ((CXXRecKind)Record[Idx++]) {
- default:
- llvm_unreachable("Out of sync with ASTDeclWriter::VisitCXXRecordDecl?");
case CXXRecNotTemplate:
break;
case CXXRecTemplate:
@@ -1147,64 +1229,42 @@
D->init(TemplatedDecl, TemplateParams);
}
-void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
- // Initialize CommonOrPrev before VisitTemplateDecl so that getCommonPtr()
- // can be used while this is still initializing.
-
- assert(D->CommonOrPrev.isNull() && "getCommonPtr was called earlier on this");
- DeclID PreviousDeclID = ReadDeclID(Record, Idx);
- DeclID FirstDeclID = PreviousDeclID ? ReadDeclID(Record, Idx) : 0;
- // We delay loading of the redeclaration chain to avoid deeply nested calls.
- // We temporarily set the first (canonical) declaration as the previous one
- // which is the one that matters and mark the real previous DeclID to be
- // loaded & attached later on.
- RedeclarableTemplateDecl *FirstDecl =
- cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(FirstDeclID));
- assert((FirstDecl == 0 || FirstDecl->getKind() == D->getKind()) &&
- "FirstDecl kind mismatch");
- if (FirstDecl) {
- D->CommonOrPrev = FirstDecl;
- // Mark the real previous DeclID to be loaded & attached later on.
- if (PreviousDeclID != FirstDeclID)
- Reader.PendingPreviousDecls.push_back(std::make_pair(D, PreviousDeclID));
- } else {
- D->CommonOrPrev = D->newCommon(Reader.getContext());
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarable(D);
+
+ // Make sure we've allocated the Common pointer first. We do this before
+ // VisitTemplateDecl so that getCommonPtr() can be used during initialization.
+ RedeclarableTemplateDecl *CanonD = D->getCanonicalDecl();
+ if (!CanonD->Common) {
+ CanonD->Common = CanonD->newCommon(Reader.getContext());
+ Reader.PendingDefinitions.insert(CanonD);
+ }
+ D->Common = CanonD->Common;
+
+ // If this is the first declaration of the template, fill in the information
+ // for the 'common' pointer.
+ if (ThisDeclID == Redecl.getFirstID()) {
if (RedeclarableTemplateDecl *RTD
= ReadDeclAs<RedeclarableTemplateDecl>(Record, Idx)) {
assert(RTD->getKind() == D->getKind() &&
"InstantiatedFromMemberTemplate kind mismatch");
- D->setInstantiatedFromMemberTemplateImpl(RTD);
+ D->setInstantiatedFromMemberTemplate(RTD);
if (Record[Idx++])
D->setMemberSpecialization();
}
-
- RedeclarableTemplateDecl *LatestDecl
- = ReadDeclAs<RedeclarableTemplateDecl>(Record, Idx);
-
- // This decl is a first one and the latest declaration that it points to is
- // in the same AST file. However, if this actually needs to point to a
- // redeclaration in another AST file, we need to update it by checking
- // the FirstLatestDeclIDs map which tracks this kind of decls.
- assert(Reader.GetDecl(ThisDeclID) == D && "Invalid ThisDeclID ?");
- ASTReader::FirstLatestDeclIDMap::iterator I
- = Reader.FirstLatestDeclIDs.find(ThisDeclID);
- if (I != Reader.FirstLatestDeclIDs.end()) {
- if (Decl *NewLatest = Reader.GetDecl(I->second))
- LatestDecl = cast<RedeclarableTemplateDecl>(NewLatest);
- }
-
- assert(LatestDecl->getKind() == D->getKind() && "Latest kind mismatch");
- D->getCommonPtr()->Latest = LatestDecl;
}
-
+
VisitTemplateDecl(D);
D->IdentifierNamespace = Record[Idx++];
+
+ return Redecl;
}
void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
- VisitRedeclarableTemplateDecl(D);
+ RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
- if (D->getPreviousDeclaration() == 0) {
+ if (ThisDeclID == Redecl.getFirstID()) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
SmallVector<serialization::DeclID, 2> SpecIDs;
@@ -1226,6 +1286,7 @@
typedef serialization::DeclID DeclID;
ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr();
+ // FIXME: Append specializations!
CommonPtr->LazySpecializations
= new (Reader.getContext()) DeclID [SpecIDs.size()];
memcpy(CommonPtr->LazySpecializations, SpecIDs.data(),
@@ -1306,7 +1367,7 @@
D->SequenceNumber = Record[Idx++];
// These are read/set from/to the first declaration.
- if (D->getPreviousDeclaration() == 0) {
+ if (D->getPreviousDecl() == 0) {
D->InstantiatedFromMember.setPointer(
ReadDeclAs<ClassTemplatePartialSpecializationDecl>(Record, Idx));
D->InstantiatedFromMember.setInt(Record[Idx++]);
@@ -1320,9 +1381,9 @@
}
void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
- VisitRedeclarableTemplateDecl(D);
+ RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
- if (D->getPreviousDeclaration() == 0) {
+ if (ThisDeclID == Redecl.getFirstID()) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
// Read the function specialization declarations.
@@ -1397,73 +1458,90 @@
}
template <typename T>
-void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
- enum RedeclKind { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
- RedeclKind Kind = (RedeclKind)Record[Idx++];
- switch (Kind) {
- default:
- llvm_unreachable("Out of sync with ASTDeclWriter::VisitRedeclarable or"
- " messed up reading");
- case NoRedeclaration:
- break;
- case PointsToPrevious: {
- DeclID PreviousDeclID = ReadDeclID(Record, Idx);
- DeclID FirstDeclID = ReadDeclID(Record, Idx);
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
+ DeclID FirstDeclID = ReadDeclID(Record, Idx);
+
+ // 0 indicates that this declaration was the only declaration of its entity,
+ // and is used for space optimization.
+ if (FirstDeclID == 0)
+ FirstDeclID = ThisDeclID;
+
+ T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
+ if (FirstDecl != D) {
// We delay loading of the redeclaration chain to avoid deeply nested calls.
// We temporarily set the first (canonical) declaration as the previous one
// which is the one that matters and mark the real previous DeclID to be
// loaded & attached later on.
- T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(FirstDecl);
- if (PreviousDeclID != FirstDeclID)
- Reader.PendingPreviousDecls.push_back(std::make_pair(static_cast<T*>(D),
- PreviousDeclID));
-
- // If the first declaration in the chain is in an inconsistent
- // state where it thinks that it is the only declaration, fix its
- // redeclaration link now to point at this declaration, so that we have a
- // proper redeclaration chain.
- if (FirstDecl->RedeclLink.getPointer() == FirstDecl) {
- FirstDecl->RedeclLink
- = typename Redeclarable<T>::LatestDeclLink(static_cast<T*>(D));
- }
- break;
- }
- case PointsToLatest: {
- T *LatestDecl = ReadDeclAs<T>(Record, Idx);
- D->RedeclLink = typename Redeclarable<T>::LatestDeclLink(LatestDecl);
-
- // If the latest declaration in the chain is in an inconsistent
- // state where it thinks that it is the only declaration, fix its
- // redeclaration link now to point at this declaration, so that we have a
- // proper redeclaration chain.
- if (LatestDecl->RedeclLink.getPointer() == LatestDecl) {
- LatestDecl->RedeclLink
- = typename Redeclarable<T>::PreviousDeclLink(static_cast<T*>(D));
- }
- break;
- }
- }
+ }
+
+ // Note that this declaration has been deserialized.
+ Reader.RedeclsDeserialized.insert(static_cast<T *>(D));
+
+ // The result structure takes care to note that we need to load the
+ // other declaration chains for this ID.
+ return RedeclarableResult(Reader, FirstDeclID);
+}
- assert(!(Kind == PointsToPrevious &&
- Reader.FirstLatestDeclIDs.find(ThisDeclID) !=
- Reader.FirstLatestDeclIDs.end()) &&
- "This decl is not first, it should not be in the map");
- if (Kind == PointsToPrevious)
+/// \brief Attempts to merge the given declaration (D) with another declaration
+/// of the same entity.
+template<typename T>
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
+ RedeclarableResult &Redecl) {
+ // If modules are not available, there is no reason to perform this merge.
+ if (!Reader.getContext().getLangOptions().Modules)
return;
-
- // This decl is a first one and the latest declaration that it points to is in
- // the same AST file. However, if this actually needs to point to a
- // redeclaration in another AST file, we need to update it by checking the
- // FirstLatestDeclIDs map which tracks this kind of decls.
- assert(Reader.GetDecl(ThisDeclID) == static_cast<T*>(D) &&
- "Invalid ThisDeclID ?");
- ASTReader::FirstLatestDeclIDMap::iterator I
- = Reader.FirstLatestDeclIDs.find(ThisDeclID);
- if (I != Reader.FirstLatestDeclIDs.end()) {
- Decl *NewLatest = Reader.GetDecl(I->second);
- D->RedeclLink
- = typename Redeclarable<T>::LatestDeclLink(cast_or_null<T>(NewLatest));
+
+ if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D))) {
+ if (T *Existing = ExistingRes) {
+ T *ExistingCanon = Existing->getCanonicalDecl();
+ T *DCanon = static_cast<T*>(D)->getCanonicalDecl();
+ if (ExistingCanon != DCanon) {
+ // Have our redeclaration link point back at the canonical declaration
+ // of the existing declaration, so that this declaration has the
+ // appropriate canonical declaration.
+ D->RedeclLink
+ = typename Redeclarable<T>::PreviousDeclLink(ExistingCanon);
+
+ // When we merge a namespace, update its pointer to the first namespace.
+ if (NamespaceDecl *Namespace
+ = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
+ Namespace->AnonOrFirstNamespaceAndInline.setPointer(
+ static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
+ }
+
+ // Don't introduce DCanon into the set of pending declaration chains.
+ Redecl.suppress();
+
+ // Introduce ExistingCanon into the set of pending declaration chains,
+ // if in fact it came from a module file.
+ if (ExistingCanon->isFromASTFile()) {
+ GlobalDeclID ExistingCanonID = ExistingCanon->getGlobalID();
+ assert(ExistingCanonID && "Unrecorded canonical declaration ID?");
+ if (Reader.PendingDeclChainsKnown.insert(ExistingCanonID))
+ Reader.PendingDeclChains.push_back(ExistingCanonID);
+ }
+
+ // If this declaration was the canonical declaration, make a note of
+ // that. We accept the linear algorithm here because the number of
+ // unique canonical declarations of an entity should always be tiny.
+ if (DCanon == static_cast<T*>(D)) {
+ SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
+ if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
+ == Merged.end())
+ Merged.push_back(Redecl.getFirstID());
+
+ // If ExistingCanon did not come from a module file, introduce the
+ // first declaration that *does* come from a module file to the
+ // set of pending declaration chains, so that we merge this
+ // declaration.
+ if (!ExistingCanon->isFromASTFile() &&
+ Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID()))
+ Reader.PendingDeclChains.push_back(Merged[0]);
+ }
+ }
+ }
}
}
@@ -1556,6 +1634,113 @@
return LocalOffset + M.GlobalBitOffset;
}
+/// \brief Determine whether the two declarations refer to the same entity.
+static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
+ assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!");
+
+ if (X == Y)
+ return true;
+
+ // Must be in the same context.
+ if (!X->getDeclContext()->getRedeclContext()->Equals(
+ Y->getDeclContext()->getRedeclContext()))
+ return false;
+
+ // Two typedefs refer to the same entity if they have the same underlying
+ // type.
+ if (TypedefNameDecl *TypedefX = dyn_cast<TypedefNameDecl>(X))
+ if (TypedefNameDecl *TypedefY = dyn_cast<TypedefNameDecl>(Y))
+ return X->getASTContext().hasSameType(TypedefX->getUnderlyingType(),
+ TypedefY->getUnderlyingType());
+
+ // Must have the same kind.
+ if (X->getKind() != Y->getKind())
+ return false;
+
+ // Objective-C classes and protocols with the same name always match.
+ if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
+ return true;
+
+ // Compatible tags match.
+ if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
+ TagDecl *TagY = cast<TagDecl>(Y);
+ return (TagX->getTagKind() == TagY->getTagKind()) ||
+ ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class) &&
+ (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class));
+ }
+
+ // Functions with the same type and linkage match.
+ // FIXME: This needs to cope with function templates, merging of
+ //prototyped/non-prototyped functions, etc.
+ if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) {
+ FunctionDecl *FuncY = cast<FunctionDecl>(Y);
+ return (FuncX->getLinkage() == FuncY->getLinkage()) &&
+ FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType());
+ }
+
+ // Variables with the same type and linkage match.
+ if (VarDecl *VarX = dyn_cast<VarDecl>(X)) {
+ VarDecl *VarY = cast<VarDecl>(Y);
+ return (VarX->getLinkage() == VarY->getLinkage()) &&
+ VarX->getASTContext().hasSameType(VarX->getType(), VarY->getType());
+ }
+
+ // Namespaces with the same name and inlinedness match.
+ if (NamespaceDecl *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
+ NamespaceDecl *NamespaceY = cast<NamespaceDecl>(Y);
+ return NamespaceX->isInline() == NamespaceY->isInline();
+ }
+
+ // FIXME: Many other cases to implement.
+ return false;
+}
+
+ASTDeclReader::FindExistingResult::~FindExistingResult() {
+ if (!AddResult || Existing)
+ return;
+
+ DeclContext *DC = New->getDeclContext()->getRedeclContext();
+ if (DC->isTranslationUnit() && Reader.SemaObj) {
+ Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, New->getDeclName());
+ } else if (DC->isNamespace()) {
+ DC->addDecl(New);
+ }
+}
+
+ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
+ DeclarationName Name = D->getDeclName();
+ if (!Name) {
+ // Don't bother trying to find unnamed declarations.
+ FindExistingResult Result(Reader, D, /*Existing=*/0);
+ Result.suppress();
+ return Result;
+ }
+
+ DeclContext *DC = D->getDeclContext()->getRedeclContext();
+ if (!DC->isFileContext())
+ return FindExistingResult(Reader);
+
+ if (DC->isTranslationUnit() && Reader.SemaObj) {
+ IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
+ for (IdentifierResolver::iterator I = IdResolver.begin(Name),
+ IEnd = IdResolver.end();
+ I != IEnd; ++I) {
+ if (isSameEntity(*I, D))
+ return FindExistingResult(Reader, D, *I);
+ }
+ }
+
+ if (DC->isNamespace()) {
+ for (DeclContext::lookup_result R = DC->lookup(Name);
+ R.first != R.second; ++R.first) {
+ if (isSameEntity(*R.first, D))
+ return FindExistingResult(Reader, D, *R.first);
+ }
+ }
+
+ return FindExistingResult(Reader, D, /*Existing=*/0);
+}
+
void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
assert(D && previous);
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
@@ -1564,14 +1749,78 @@
FD->RedeclLink.setPointer(cast<FunctionDecl>(previous));
} else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
VD->RedeclLink.setPointer(cast<VarDecl>(previous));
- } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(previous)) {
+ } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ TD->RedeclLink.setPointer(cast<TypedefNameDecl>(previous));
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
ID->RedeclLink.setPointer(cast<ObjCInterfaceDecl>(previous));
+ } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
+ PD->RedeclLink.setPointer(cast<ObjCProtocolDecl>(previous));
+ } else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D)) {
+ ND->RedeclLink.setPointer(cast<NamespaceDecl>(previous));
} else {
RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
- TD->CommonOrPrev = cast<RedeclarableTemplateDecl>(previous);
+ TD->RedeclLink.setPointer(cast<RedeclarableTemplateDecl>(previous));
}
}
+void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) {
+ assert(D && Latest);
+ if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ TD->RedeclLink
+ = Redeclarable<TagDecl>::LatestDeclLink(cast<TagDecl>(Latest));
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ FD->RedeclLink
+ = Redeclarable<FunctionDecl>::LatestDeclLink(cast<FunctionDecl>(Latest));
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ VD->RedeclLink
+ = Redeclarable<VarDecl>::LatestDeclLink(cast<VarDecl>(Latest));
+ } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ TD->RedeclLink
+ = Redeclarable<TypedefNameDecl>::LatestDeclLink(
+ cast<TypedefNameDecl>(Latest));
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ ID->RedeclLink
+ = Redeclarable<ObjCInterfaceDecl>::LatestDeclLink(
+ cast<ObjCInterfaceDecl>(Latest));
+ } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
+ PD->RedeclLink
+ = Redeclarable<ObjCProtocolDecl>::LatestDeclLink(
+ cast<ObjCProtocolDecl>(Latest));
+ } else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D)) {
+ ND->RedeclLink
+ = Redeclarable<NamespaceDecl>::LatestDeclLink(
+ cast<NamespaceDecl>(Latest));
+ } else {
+ RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
+ TD->RedeclLink
+ = Redeclarable<RedeclarableTemplateDecl>::LatestDeclLink(
+ cast<RedeclarableTemplateDecl>(Latest));
+ }
+}
+
+ASTReader::MergedDeclsMap::iterator
+ASTReader::combineStoredMergedDecls(Decl *Canon, GlobalDeclID CanonID) {
+ // If we don't have any stored merged declarations, just look in the
+ // merged declarations set.
+ StoredMergedDeclsMap::iterator StoredPos = StoredMergedDecls.find(CanonID);
+ if (StoredPos == StoredMergedDecls.end())
+ return MergedDecls.find(Canon);
+
+ // Append the stored merged declarations to the merged declarations set.
+ MergedDeclsMap::iterator Pos = MergedDecls.find(Canon);
+ if (Pos == MergedDecls.end())
+ Pos = MergedDecls.insert(std::make_pair(Canon,
+ SmallVector<DeclID, 2>())).first;
+ Pos->second.append(StoredPos->second.begin(), StoredPos->second.end());
+ StoredMergedDecls.erase(StoredPos);
+
+ // Sort and uniquify the set of merged declarations.
+ llvm::array_pod_sort(Pos->second.begin(), Pos->second.end());
+ Pos->second.erase(std::unique(Pos->second.begin(), Pos->second.end()),
+ Pos->second.end());
+ return Pos;
+}
+
void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) {
Decl *previous = GetDecl(ID);
ASTDeclReader::attachPreviousDecl(D, previous);
@@ -1604,214 +1853,160 @@
case DECL_CONTEXT_VISIBLE:
llvm_unreachable("Record cannot be de-serialized with ReadDeclRecord");
case DECL_TYPEDEF:
- D = TypedefDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
- 0, 0);
+ D = TypedefDecl::CreateDeserialized(Context, ID);
break;
case DECL_TYPEALIAS:
- D = TypeAliasDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
- 0, 0);
+ D = TypeAliasDecl::CreateDeserialized(Context, ID);
break;
case DECL_ENUM:
- D = EnumDecl::Create(Context, Decl::EmptyShell());
+ D = EnumDecl::CreateDeserialized(Context, ID);
break;
case DECL_RECORD:
- D = RecordDecl::Create(Context, Decl::EmptyShell());
+ D = RecordDecl::CreateDeserialized(Context, ID);
break;
case DECL_ENUM_CONSTANT:
- D = EnumConstantDecl::Create(Context, 0, SourceLocation(), 0, QualType(),
- 0, llvm::APSInt());
+ D = EnumConstantDecl::CreateDeserialized(Context, ID);
break;
case DECL_FUNCTION:
- D = FunctionDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
- DeclarationName(), QualType(), 0);
+ D = FunctionDecl::CreateDeserialized(Context, ID);
break;
case DECL_LINKAGE_SPEC:
- D = LinkageSpecDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
- (LinkageSpecDecl::LanguageIDs)0,
- SourceLocation());
+ D = LinkageSpecDecl::CreateDeserialized(Context, ID);
break;
case DECL_LABEL:
- D = LabelDecl::Create(Context, 0, SourceLocation(), 0);
+ D = LabelDecl::CreateDeserialized(Context, ID);
break;
case DECL_NAMESPACE:
- D = NamespaceDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0);
+ D = NamespaceDecl::CreateDeserialized(Context, ID);
break;
case DECL_NAMESPACE_ALIAS:
- D = NamespaceAliasDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0,
- NestedNameSpecifierLoc(),
- SourceLocation(), 0);
+ D = NamespaceAliasDecl::CreateDeserialized(Context, ID);
break;
case DECL_USING:
- D = UsingDecl::Create(Context, 0, SourceLocation(),
- NestedNameSpecifierLoc(), DeclarationNameInfo(),
- false);
+ D = UsingDecl::CreateDeserialized(Context, ID);
break;
case DECL_USING_SHADOW:
- D = UsingShadowDecl::Create(Context, 0, SourceLocation(), 0, 0);
+ D = UsingShadowDecl::CreateDeserialized(Context, ID);
break;
case DECL_USING_DIRECTIVE:
- D = UsingDirectiveDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), NestedNameSpecifierLoc(),
- SourceLocation(), 0, 0);
+ D = UsingDirectiveDecl::CreateDeserialized(Context, ID);
break;
case DECL_UNRESOLVED_USING_VALUE:
- D = UnresolvedUsingValueDecl::Create(Context, 0, SourceLocation(),
- NestedNameSpecifierLoc(),
- DeclarationNameInfo());
+ D = UnresolvedUsingValueDecl::CreateDeserialized(Context, ID);
break;
case DECL_UNRESOLVED_USING_TYPENAME:
- D = UnresolvedUsingTypenameDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(),
- NestedNameSpecifierLoc(),
- SourceLocation(),
- DeclarationName());
+ D = UnresolvedUsingTypenameDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_RECORD:
- D = CXXRecordDecl::Create(Context, Decl::EmptyShell());
+ D = CXXRecordDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_METHOD:
- D = CXXMethodDecl::Create(Context, 0, SourceLocation(),
- DeclarationNameInfo(), QualType(), 0,
- false, SC_None, false, false, SourceLocation());
+ D = CXXMethodDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_CONSTRUCTOR:
- D = CXXConstructorDecl::Create(Context, Decl::EmptyShell());
+ D = CXXConstructorDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_DESTRUCTOR:
- D = CXXDestructorDecl::Create(Context, Decl::EmptyShell());
+ D = CXXDestructorDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_CONVERSION:
- D = CXXConversionDecl::Create(Context, Decl::EmptyShell());
+ D = CXXConversionDecl::CreateDeserialized(Context, ID);
break;
case DECL_ACCESS_SPEC:
- D = AccessSpecDecl::Create(Context, Decl::EmptyShell());
+ D = AccessSpecDecl::CreateDeserialized(Context, ID);
break;
case DECL_FRIEND:
- D = FriendDecl::Create(Context, Decl::EmptyShell());
+ D = FriendDecl::CreateDeserialized(Context, ID);
break;
case DECL_FRIEND_TEMPLATE:
- D = FriendTemplateDecl::Create(Context, Decl::EmptyShell());
+ D = FriendTemplateDecl::CreateDeserialized(Context, ID);
break;
case DECL_CLASS_TEMPLATE:
- D = ClassTemplateDecl::Create(Context, Decl::EmptyShell());
+ D = ClassTemplateDecl::CreateDeserialized(Context, ID);
break;
case DECL_CLASS_TEMPLATE_SPECIALIZATION:
- D = ClassTemplateSpecializationDecl::Create(Context, Decl::EmptyShell());
+ D = ClassTemplateSpecializationDecl::CreateDeserialized(Context, ID);
break;
case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION:
- D = ClassTemplatePartialSpecializationDecl::Create(Context,
- Decl::EmptyShell());
+ D = ClassTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID);
break;
case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION:
- D = ClassScopeFunctionSpecializationDecl::Create(Context,
- Decl::EmptyShell());
+ D = ClassScopeFunctionSpecializationDecl::CreateDeserialized(Context, ID);
break;
case DECL_FUNCTION_TEMPLATE:
- D = FunctionTemplateDecl::Create(Context, Decl::EmptyShell());
+ D = FunctionTemplateDecl::CreateDeserialized(Context, ID);
break;
case DECL_TEMPLATE_TYPE_PARM:
- D = TemplateTypeParmDecl::Create(Context, Decl::EmptyShell());
+ D = TemplateTypeParmDecl::CreateDeserialized(Context, ID);
break;
case DECL_NON_TYPE_TEMPLATE_PARM:
- D = NonTypeTemplateParmDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0, 0, 0, QualType(),
- false, 0);
+ D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID);
break;
case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK:
- D = NonTypeTemplateParmDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0, 0, 0, QualType(),
- 0, 0, Record[Idx++], 0);
+ D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID, Record[Idx++]);
break;
case DECL_TEMPLATE_TEMPLATE_PARM:
- D = TemplateTemplateParmDecl::Create(Context, 0, SourceLocation(), 0, 0,
- false, 0, 0);
+ D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
break;
case DECL_TYPE_ALIAS_TEMPLATE:
- D = TypeAliasTemplateDecl::Create(Context, Decl::EmptyShell());
+ D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
break;
case DECL_STATIC_ASSERT:
- D = StaticAssertDecl::Create(Context, 0, SourceLocation(), 0, 0,
- SourceLocation());
+ D = StaticAssertDecl::CreateDeserialized(Context, ID);
break;
-
case DECL_OBJC_METHOD:
- D = ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(),
- Selector(), QualType(), 0, 0);
+ D = ObjCMethodDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_INTERFACE:
- D = ObjCInterfaceDecl::CreateEmpty(Context);
+ D = ObjCInterfaceDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_IVAR:
- D = ObjCIvarDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
- 0, QualType(), 0, ObjCIvarDecl::None);
+ D = ObjCIvarDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_PROTOCOL:
- D = ObjCProtocolDecl::Create(Context, 0, 0, SourceLocation(),
- SourceLocation(), 0);
+ D = ObjCProtocolDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_AT_DEFS_FIELD:
- D = ObjCAtDefsFieldDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0, QualType(), 0);
- break;
- case DECL_OBJC_CLASS:
- D = ObjCClassDecl::Create(Context, 0, SourceLocation());
- break;
- case DECL_OBJC_FORWARD_PROTOCOL:
- D = ObjCForwardProtocolDecl::Create(Context, 0, SourceLocation());
+ D = ObjCAtDefsFieldDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_CATEGORY:
- D = ObjCCategoryDecl::Create(Context, Decl::EmptyShell());
+ D = ObjCCategoryDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_CATEGORY_IMPL:
- D = ObjCCategoryImplDecl::Create(Context, 0, 0, 0, SourceLocation(),
- SourceLocation(), SourceLocation());
+ D = ObjCCategoryImplDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_IMPLEMENTATION:
- D = ObjCImplementationDecl::Create(Context, 0, 0, 0, SourceLocation(),
- SourceLocation());
+ D = ObjCImplementationDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_COMPATIBLE_ALIAS:
- D = ObjCCompatibleAliasDecl::Create(Context, 0, SourceLocation(), 0, 0);
+ D = ObjCCompatibleAliasDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_PROPERTY:
- D = ObjCPropertyDecl::Create(Context, 0, SourceLocation(), 0, SourceLocation(),
- 0);
+ D = ObjCPropertyDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_PROPERTY_IMPL:
- D = ObjCPropertyImplDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0,
- ObjCPropertyImplDecl::Dynamic, 0,
- SourceLocation());
+ D = ObjCPropertyImplDecl::CreateDeserialized(Context, ID);
break;
case DECL_FIELD:
- D = FieldDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, 0, false, false);
+ D = FieldDecl::CreateDeserialized(Context, ID);
break;
case DECL_INDIRECTFIELD:
- D = IndirectFieldDecl::Create(Context, 0, SourceLocation(), 0, QualType(),
- 0, 0);
+ D = IndirectFieldDecl::CreateDeserialized(Context, ID);
break;
case DECL_VAR:
- D = VarDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, SC_None, SC_None);
+ D = VarDecl::CreateDeserialized(Context, ID);
break;
-
case DECL_IMPLICIT_PARAM:
- D = ImplicitParamDecl::Create(Context, 0, SourceLocation(), 0, QualType());
+ D = ImplicitParamDecl::CreateDeserialized(Context, ID);
break;
-
case DECL_PARM_VAR:
- D = ParmVarDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, SC_None, SC_None, 0);
+ D = ParmVarDecl::CreateDeserialized(Context, ID);
break;
case DECL_FILE_SCOPE_ASM:
- D = FileScopeAsmDecl::Create(Context, 0, 0, SourceLocation(),
- SourceLocation());
+ D = FileScopeAsmDecl::CreateDeserialized(Context, ID);
break;
case DECL_BLOCK:
- D = BlockDecl::Create(Context, 0, SourceLocation());
+ D = BlockDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_BASE_SPECIFIERS:
Error("attempt to read a C++ base-specifier record as a declaration");
@@ -1819,7 +2014,7 @@
case DECL_IMPORT:
// Note: last entry of the ImportDecl record is the number of stored source
// locations.
- D = ImportDecl::CreateEmpty(Context, Record.back());
+ D = ImportDecl::CreateDeserialized(Context, ID, Record.back());
break;
}
@@ -1904,6 +2099,147 @@
}
namespace {
+ struct CompareLocalRedeclarationsInfoToID {
+ bool operator()(const LocalRedeclarationsInfo &X, DeclID Y) {
+ return X.FirstID < Y;
+ }
+
+ bool operator()(DeclID X, const LocalRedeclarationsInfo &Y) {
+ return X < Y.FirstID;
+ }
+
+ bool operator()(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID < Y.FirstID;
+ }
+ bool operator()(DeclID X, DeclID Y) {
+ return X < Y;
+ }
+ };
+
+ /// \brief Module visitor class that finds all of the redeclarations of a
+ ///
+ class RedeclChainVisitor {
+ ASTReader &Reader;
+ SmallVectorImpl<DeclID> &SearchDecls;
+ llvm::SmallPtrSet<Decl *, 16> &Deserialized;
+ GlobalDeclID CanonID;
+ llvm::SmallVector<Decl *, 4> Chain;
+
+ public:
+ RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl<DeclID> &SearchDecls,
+ llvm::SmallPtrSet<Decl *, 16> &Deserialized,
+ GlobalDeclID CanonID)
+ : Reader(Reader), SearchDecls(SearchDecls), Deserialized(Deserialized),
+ CanonID(CanonID) {
+ for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I)
+ addToChain(Reader.GetDecl(SearchDecls[I]));
+ }
+
+ static bool visit(ModuleFile &M, bool Preorder, void *UserData) {
+ if (Preorder)
+ return false;
+
+ return static_cast<RedeclChainVisitor *>(UserData)->visit(M);
+ }
+
+ void addToChain(Decl *D) {
+ if (!D)
+ return;
+
+ if (Deserialized.count(D)) {
+ Deserialized.erase(D);
+ Chain.push_back(D);
+ }
+ }
+
+ void searchForID(ModuleFile &M, GlobalDeclID GlobalID) {
+ // Map global ID of the first declaration down to the local ID
+ // used in this module file.
+ DeclID ID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID);
+ if (!ID)
+ return;
+
+ // Perform a binary search to find the local redeclarations for this
+ // declaration (if any).
+ const LocalRedeclarationsInfo *Result
+ = std::lower_bound(M.RedeclarationsMap,
+ M.RedeclarationsMap + M.LocalNumRedeclarationsInMap,
+ ID, CompareLocalRedeclarationsInfoToID());
+ if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap ||
+ Result->FirstID != ID) {
+ // If we have a previously-canonical singleton declaration that was
+ // merged into another redeclaration chain, create a trivial chain
+ // for this single declaration so that it will get wired into the
+ // complete redeclaration chain.
+ if (GlobalID != CanonID &&
+ GlobalID - NUM_PREDEF_DECL_IDS >= M.BaseDeclID &&
+ GlobalID - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls) {
+ addToChain(Reader.GetDecl(GlobalID));
+ }
+
+ return;
+ }
+
+ // Dig out the starting/ending declarations.
+ unsigned Offset = Result->Offset;
+ unsigned N = M.RedeclarationChains[Offset];
+ M.RedeclarationChains[Offset++] = 0; // Don't try to deserialize again
+ for (unsigned I = 0; I != N; ++I)
+ addToChain(Reader.GetLocalDecl(M, M.RedeclarationChains[Offset++]));
+ }
+
+ bool visit(ModuleFile &M) {
+ // Visit each of the declarations.
+ for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I)
+ searchForID(M, SearchDecls[I]);
+ return false;
+ }
+
+ ArrayRef<Decl *> getChain() const {
+ return Chain;
+ }
+ };
+}
+
+void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
+ Decl *D = GetDecl(ID);
+ Decl *CanonDecl = D->getCanonicalDecl();
+
+ // Determine the set of declaration IDs we'll be searching for.
+ llvm::SmallVector<DeclID, 1> SearchDecls;
+ GlobalDeclID CanonID = 0;
+ if (D == CanonDecl) {
+ SearchDecls.push_back(ID); // Always first.
+ CanonID = ID;
+ }
+ MergedDeclsMap::iterator MergedPos = combineStoredMergedDecls(CanonDecl, ID);
+ if (MergedPos != MergedDecls.end())
+ SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end());
+
+ // Build up the list of redeclarations.
+ RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID);
+ ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visit, &Visitor);
+
+ // Retrieve the chains.
+ ArrayRef<Decl *> Chain = Visitor.getChain();
+ if (Chain.empty())
+ return;
+
+ // Hook up the chains.
+ Decl *MostRecent = CanonDecl->getMostRecentDecl();
+ for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
+ if (Chain[I] == CanonDecl)
+ continue;
+
+ ASTDeclReader::attachPreviousDecl(Chain[I], MostRecent);
+ MostRecent = Chain[I];
+ }
+
+ ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
+}
+
+namespace {
/// \brief Given an ObjC interface, goes through the modules and links to the
/// interface all the categories for it.
class ObjCChainedCategoriesVisitor {
@@ -2034,15 +2370,6 @@
unsigned Idx = 0;
while (Idx < Record.size()) {
switch ((DeclUpdateKind)Record[Idx++]) {
- case UPD_CXX_SET_DEFINITIONDATA: {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(D);
- CXXRecordDecl *DefinitionDecl
- = Reader.ReadDeclAs<CXXRecordDecl>(ModuleFile, Record, Idx);
- assert(!RD->DefinitionData && "DefinitionData is already set!");
- InitializeCXXDefinitionData(RD, DefinitionDecl, Record, Idx);
- break;
- }
-
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
cast<CXXRecordDecl>(D)->addedMember(Reader.ReadDecl(ModuleFile, Record, Idx));
break;
@@ -2055,14 +2382,15 @@
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
NamespaceDecl *Anon
= Reader.ReadDeclAs<NamespaceDecl>(ModuleFile, Record, Idx);
- // Guard against these being loaded out of original order. Don't use
- // getNextNamespace(), since it tries to access the context and can't in
- // the middle of deserialization.
- if (!Anon->NextNamespace) {
+
+ // Each module has its own anonymous namespace, which is disjoint from
+ // any other module's anonymous namespaces, so don't attach the anonymous
+ // namespace at all.
+ if (ModuleFile.Kind != MK_Module) {
if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D))
TU->setAnonymousNamespace(Anon);
else
- cast<NamespaceDecl>(D)->OrigOrAnonNamespace.setPointer(Anon);
+ cast<NamespaceDecl>(D)->setAnonymousNamespace(Anon);
}
break;
}
@@ -2071,19 +2399,6 @@
cast<VarDecl>(D)->getMemberSpecializationInfo()->setPointOfInstantiation(
Reader.ReadSourceLocation(ModuleFile, Record, Idx));
break;
-
- case UPD_OBJC_SET_CLASS_DEFINITIONDATA: {
- ObjCInterfaceDecl *ID = cast<ObjCInterfaceDecl>(D);
- ObjCInterfaceDecl *Def
- = Reader.ReadDeclAs<ObjCInterfaceDecl>(ModuleFile, Record, Idx);
- if (Def->Data) {
- ID->Data = Def->Data;
- } else {
- // The definition is still initializing.
- Reader.PendingForwardRefs[Def].push_back(ID);
- }
- break;
- }
}
}
}
Modified: cfe/branches/tooling/lib/Serialization/ASTReaderInternals.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/ASTReaderInternals.h?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/ASTReaderInternals.h (original)
+++ cfe/branches/tooling/lib/Serialization/ASTReaderInternals.h Fri Jan 20 10:14:22 2012
@@ -15,6 +15,7 @@
#include "clang/Basic/OnDiskHashTable.h"
#include "clang/AST/DeclarationName.h"
+#include "llvm/Support/Endian.h"
#include <utility>
#include <sys/stat.h>
@@ -41,7 +42,8 @@
///
/// Note that these declaration IDs are local to the module that contains this
/// particular lookup t
- typedef std::pair<DeclID *, DeclID *> data_type;
+ typedef llvm::support::ulittle32_t LE32DeclID;
+ typedef std::pair<LE32DeclID *, LE32DeclID *> data_type;
/// \brief Special internal key for declaration names.
/// The hash table creates keys for comparison; we do not create
Modified: cfe/branches/tooling/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/ASTReaderStmt.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/branches/tooling/lib/Serialization/ASTReaderStmt.cpp Fri Jan 20 10:14:22 2012
@@ -879,6 +879,7 @@
unsigned NumStoredSelLocs = Record[Idx++];
E->SelLocsKind = Record[Idx++];
E->setDelegateInitCall(Record[Idx++]);
+ E->IsImplicit = Record[Idx++];
ObjCMessageExpr::ReceiverKind Kind
= static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]);
switch (Kind) {
@@ -1446,7 +1447,6 @@
}
llvm_unreachable("ReadingKind not set ?");
- return 0;
}
Expr *ASTReader::ReadExpr(ModuleFile &F) {
@@ -1811,7 +1811,6 @@
break;
case EXPR_OBJC_KVC_REF_EXPR:
llvm_unreachable("mismatching AST file");
- break;
case EXPR_OBJC_MESSAGE_EXPR:
S = ObjCMessageExpr::CreateEmpty(Context,
Record[ASTStmtReader::NumExprFields],
Modified: cfe/branches/tooling/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/ASTWriter.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/branches/tooling/lib/Serialization/ASTWriter.cpp Fri Jan 20 10:14:22 2012
@@ -239,7 +239,7 @@
void ASTTypeWriter::VisitTagType(const TagType *T) {
Record.push_back(T->isDependentType());
- Writer.AddDeclRef(T->getDecl(), Record);
+ Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
assert(!T->isBeingDefined() &&
"Cannot serialize in the middle of a type definition");
}
@@ -369,7 +369,7 @@
}
void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
- Writer.AddDeclRef(T->getDecl(), Record);
+ Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
Code = TYPE_OBJC_INTERFACE;
}
@@ -778,7 +778,7 @@
RECORD(IMPORTS);
RECORD(REFERENCED_SELECTOR_POOL);
RECORD(TU_UPDATE_LEXICAL);
- RECORD(REDECLS_UPDATE_LATEST);
+ RECORD(LOCAL_REDECLARATIONS_MAP);
RECORD(SEMA_DECL_REFS);
RECORD(WEAK_UNDECLARED_IDENTIFIERS);
RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
@@ -798,7 +798,12 @@
RECORD(KNOWN_NAMESPACES);
RECORD(MODULE_OFFSET_MAP);
RECORD(SOURCE_MANAGER_LINE_TABLE);
-
+ RECORD(OBJC_CHAINED_CATEGORIES);
+ RECORD(FILE_SORTED_DECLS);
+ RECORD(IMPORTED_MODULES);
+ RECORD(MERGED_DECLARATIONS);
+ RECORD(LOCAL_REDECLARATIONS);
+
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
RECORD(SM_SLOC_FILE_ENTRY);
@@ -862,8 +867,6 @@
RECORD(DECL_OBJC_PROTOCOL);
RECORD(DECL_OBJC_IVAR);
RECORD(DECL_OBJC_AT_DEFS_FIELD);
- RECORD(DECL_OBJC_CLASS);
- RECORD(DECL_OBJC_FORWARD_PROTOCOL);
RECORD(DECL_OBJC_CATEGORY);
RECORD(DECL_OBJC_CATEGORY_IMPL);
RECORD(DECL_OBJC_IMPLEMENTATION);
@@ -1657,8 +1660,9 @@
for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
E = PP.macro_end(Chain == 0);
I != E; ++I) {
+ const IdentifierInfo *Name = I->first;
if (!IsModule || I->second->isPublic()) {
- MacroDefinitionsSeen.insert(I->first);
+ MacroDefinitionsSeen.insert(Name);
MacrosToEmit.push_back(std::make_pair(I->first, I->second));
}
}
@@ -1857,10 +1861,10 @@
/// given module).
static unsigned getNumberOfModules(Module *Mod) {
unsigned ChildModules = 0;
- for (llvm::StringMap<Module *>::iterator Sub = Mod->SubModules.begin(),
- SubEnd = Mod->SubModules.end();
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
Sub != SubEnd; ++Sub)
- ChildModules += getNumberOfModules(Sub->getValue());
+ ChildModules += getNumberOfModules(*Sub);
return ChildModules + 1;
}
@@ -1874,7 +1878,6 @@
for (ASTContext::import_iterator I = Context->local_import_begin(),
IEnd = Context->local_import_end();
I != IEnd; ++I) {
- assert(SubmoduleIDs.find(I->getImportedModule()) != SubmoduleIDs.end());
if (Module *ImportedFrom
= ModMap.inferModuleFromLocation(FullSourceLoc(I->getLocation(),
SrcMgr))) {
@@ -1914,6 +1917,11 @@
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev);
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_REQUIRES));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
+ unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev);
+
// Write the submodule metadata block.
RecordData Record;
Record.push_back(getNumberOfModules(WritingModule));
@@ -1945,6 +1953,15 @@
Record.push_back(Mod->InferExportWildcard);
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
+ // Emit the requirements.
+ for (unsigned I = 0, N = Mod->Requires.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_REQUIRES);
+ Stream.EmitRecordWithBlob(RequiresAbbrev, Record,
+ Mod->Requires[I].data(),
+ Mod->Requires[I].size());
+ }
+
// Emit the umbrella header, if there is one.
if (const FileEntry *UmbrellaHeader = Mod->getUmbrellaHeader()) {
Record.clear();
@@ -1995,19 +2012,10 @@
}
// Queue up the submodules of this module.
- llvm::SmallVector<StringRef, 2> SubModules;
-
- // Sort the submodules first, so we get a predictable ordering in the AST
- // file.
- for (llvm::StringMap<Module *>::iterator
- Sub = Mod->SubModules.begin(),
- SubEnd = Mod->SubModules.end();
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
Sub != SubEnd; ++Sub)
- SubModules.push_back(Sub->getKey());
- llvm::array_pod_sort(SubModules.begin(), SubModules.end());
-
- for (unsigned I = 0, N = SubModules.size(); I != N; ++I)
- Q.push(Mod->SubModules[SubModules[I]]);
+ Q.push(*Sub);
}
Stream.ExitBlock();
@@ -2518,6 +2526,7 @@
uint32_t Bits = 0;
bool HasMacroDefinition = hasMacroDefinition(II, Macro);
Bits = (uint32_t)II->getObjCOrBuiltinID();
+ assert((Bits & 0x7ff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
Bits = (Bits << 1) | unsigned(HasMacroDefinition);
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
Bits = (Bits << 1) | unsigned(II->isPoisoned());
@@ -2899,6 +2908,92 @@
Stream.EmitRecord(OPENCL_EXTENSIONS, Record);
}
+void ASTWriter::WriteRedeclarations() {
+ RecordData LocalRedeclChains;
+ SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclsMap;
+
+ for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) {
+ Decl *First = Redeclarations[I];
+ assert(First->getPreviousDecl() == 0 && "Not the first declaration?");
+
+ Decl *MostRecent = First->getMostRecentDecl();
+
+ // If we only have a single declaration, there is no point in storing
+ // a redeclaration chain.
+ if (First == MostRecent)
+ continue;
+
+ unsigned Offset = LocalRedeclChains.size();
+ unsigned Size = 0;
+ LocalRedeclChains.push_back(0); // Placeholder for the size.
+
+ // Collect the set of local redeclarations of this declaration.
+ for (Decl *Prev = MostRecent; Prev != First;
+ Prev = Prev->getPreviousDecl()) {
+ if (!Prev->isFromASTFile()) {
+ AddDeclRef(Prev, LocalRedeclChains);
+ ++Size;
+ }
+ }
+ LocalRedeclChains[Offset] = Size;
+
+ // Reverse the set of local redeclarations, so that we store them in
+ // order (since we found them in reverse order).
+ std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end());
+
+ // Add the mapping from the first ID to the set of local declarations.
+ LocalRedeclarationsInfo Info = { getDeclID(First), Offset };
+ LocalRedeclsMap.push_back(Info);
+
+ assert(N == Redeclarations.size() &&
+ "Deserialized a declaration we shouldn't have");
+ }
+
+ if (LocalRedeclChains.empty())
+ return;
+
+ // Sort the local redeclarations map by the first declaration ID,
+ // since the reader will be performing binary searches on this information.
+ llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end());
+
+ // Emit the local redeclarations map.
+ using namespace llvm;
+ llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS_MAP));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
+
+ RecordData Record;
+ Record.push_back(LOCAL_REDECLARATIONS_MAP);
+ Record.push_back(LocalRedeclsMap.size());
+ Stream.EmitRecordWithBlob(AbbrevID, Record,
+ reinterpret_cast<char*>(LocalRedeclsMap.data()),
+ LocalRedeclsMap.size() * sizeof(LocalRedeclarationsInfo));
+
+ // Emit the redeclaration chains.
+ Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedeclChains);
+}
+
+void ASTWriter::WriteMergedDecls() {
+ if (!Chain || Chain->MergedDecls.empty())
+ return;
+
+ RecordData Record;
+ for (ASTReader::MergedDeclsMap::iterator I = Chain->MergedDecls.begin(),
+ IEnd = Chain->MergedDecls.end();
+ I != IEnd; ++I) {
+ DeclID CanonID = I->first->isFromASTFile()? I->first->getGlobalID()
+ : getDeclID(I->first);
+ assert(CanonID && "Merged declaration not known?");
+
+ Record.push_back(CanonID);
+ Record.push_back(I->second.size());
+ Record.append(I->second.begin(), I->second.end());
+ }
+ Stream.EmitRecord(MERGED_DECLARATIONS, Record);
+}
+
//===----------------------------------------------------------------------===//
// General Serialization Routines
//===----------------------------------------------------------------------===//
@@ -3039,6 +3134,8 @@
DeclIDs[Context.ObjCSelDecl] = PREDEF_DECL_OBJC_SEL_ID;
if (Context.ObjCClassDecl)
DeclIDs[Context.ObjCClassDecl] = PREDEF_DECL_OBJC_CLASS_ID;
+ if (Context.ObjCProtocolClassDecl)
+ DeclIDs[Context.ObjCProtocolClassDecl] = PREDEF_DECL_OBJC_PROTOCOL_ID;
if (Context.Int128Decl)
DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID;
if (Context.UInt128Decl)
@@ -3218,7 +3315,6 @@
// Form the record of special types.
RecordData SpecialTypes;
AddTypeRef(Context.getBuiltinVaListType(), SpecialTypes);
- AddTypeRef(Context.ObjCProtoType, SpecialTypes);
AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes);
AddTypeRef(Context.getFILEType(), SpecialTypes);
AddTypeRef(Context.getjmp_bufType(), SpecialTypes);
@@ -3311,19 +3407,6 @@
Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);
- /// Build a record containing first declarations from a chained PCH and the
- /// most recent declarations in this AST that they point to.
- RecordData FirstLatestDeclIDs;
- for (FirstLatestDeclMap::iterator I = FirstLatestDecls.begin(),
- E = FirstLatestDecls.end();
- I != E; ++I) {
- AddDeclRef(I->first, FirstLatestDeclIDs);
- AddDeclRef(I->second, FirstLatestDeclIDs);
- }
-
- if (!FirstLatestDeclIDs.empty())
- Stream.EmitRecord(REDECLS_UPDATE_LATEST, FirstLatestDeclIDs);
-
// Write the record containing external, unnamed definitions.
if (!ExternalDefinitions.empty())
Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions);
@@ -3410,7 +3493,9 @@
WriteDeclUpdatesBlocks();
WriteDeclReplacementsBlock();
WriteChainedObjCCategories();
-
+ WriteMergedDecls();
+ WriteRedeclarations();
+
// Some simple statistics
Record.clear();
Record.push_back(NumStatements);
@@ -3435,11 +3520,9 @@
unsigned Idx = 0, N = URec.size();
while (Idx < N) {
switch ((DeclUpdateKind)URec[Idx++]) {
- case UPD_CXX_SET_DEFINITIONDATA:
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE:
- case UPD_OBJC_SET_CLASS_DEFINITIONDATA:
URec[Idx] = GetDeclRef(reinterpret_cast<Decl *>(URec[Idx]));
++Idx;
break;
@@ -3695,6 +3778,12 @@
if (D == 0) {
return 0;
}
+
+ // If D comes from an AST file, its declaration ID is already known and
+ // fixed.
+ if (D->isFromASTFile())
+ return D->getGlobalID();
+
assert(!(reinterpret_cast<uintptr_t>(D) & 0x01) && "Invalid decl pointer");
DeclID &ID = DeclIDs[D];
if (ID == 0) {
@@ -3711,6 +3800,11 @@
if (D == 0)
return 0;
+ // If D comes from an AST file, its declaration ID is already known and
+ // fixed.
+ if (D->isFromASTFile())
+ return D->getGlobalID();
+
assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!");
return DeclIDs[D];
}
@@ -4239,10 +4333,6 @@
StoredIdx = Idx;
}
-void ASTWriter::DeclRead(DeclID ID, const Decl *D) {
- DeclIDs[D] = ID;
-}
-
void ASTWriter::SelectorRead(SelectorID ID, Selector S) {
SelectorIDs[S] = ID;
}
@@ -4253,6 +4343,10 @@
MacroDefinitions[MD] = ID;
}
+void ASTWriter::MacroVisible(IdentifierInfo *II) {
+ DeserializedMacroNames.push_back(II);
+}
+
void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) {
assert(SubmoduleIDs.find(Mod) == SubmoduleIDs.end());
SubmoduleIDs[Mod] = ID;
@@ -4269,22 +4363,6 @@
// have created a new definition decl instead ?
RewriteDecl(RD);
}
-
- for (CXXRecordDecl::redecl_iterator
- I = RD->redecls_begin(), E = RD->redecls_end(); I != E; ++I) {
- CXXRecordDecl *Redecl = cast<CXXRecordDecl>(*I);
- if (Redecl == RD)
- continue;
-
- // We are interested when a PCH decl is modified.
- if (Redecl->isFromASTFile()) {
- UpdateRecord &Record = DeclUpdates[Redecl];
- Record.push_back(UPD_CXX_SET_DEFINITIONDATA);
- assert(Redecl->DefinitionData);
- assert(Redecl->DefinitionData->Definition == D);
- Record.push_back(reinterpret_cast<uint64_t>(D)); // the DefinitionDecl
- }
- }
}
}
void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
@@ -4378,29 +4456,6 @@
LocalChainedObjCCategories.push_back(Data);
}
-void ASTWriter::CompletedObjCForwardRef(const ObjCContainerDecl *D) {
- assert(!WritingAST && "Already writing the AST!");
- if (D->isFromASTFile())
- RewriteDecl(D);
-
- if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
- for (ObjCInterfaceDecl::redecl_iterator I = ID->redecls_begin(),
- E = ID->redecls_end();
- I != E; ++I) {
- if (*I == ID)
- continue;
-
- // We are interested when a PCH decl is modified.
- if (I->isFromASTFile()) {
- UpdateRecord &Record = DeclUpdates[*I];
- Record.push_back(UPD_OBJC_SET_CLASS_DEFINITIONDATA);
- assert((*I)->hasDefinition());
- assert((*I)->getDefinition() == D);
- Record.push_back(reinterpret_cast<uint64_t>(D)); // the DefinitionDecl
- }
- }
- }
-}
void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
const ObjCPropertyDecl *OrigProp,
@@ -4416,10 +4471,3 @@
RewriteDecl(D);
}
-void ASTWriter::UpdatedAttributeList(const Decl *D) {
- assert(!WritingAST && "Already writing the AST!");
- if (!D->isFromASTFile())
- return; // Declaration not imported from PCH.
-
- RewriteDecl(D);
-}
Modified: cfe/branches/tooling/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/ASTWriterDecl.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/branches/tooling/lib/Serialization/ASTWriterDecl.cpp Fri Jan 20 10:14:22 2012
@@ -55,6 +55,7 @@
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *D);
+ void VisitTypedefNameDecl(TypedefNameDecl *D);
void VisitTypedefDecl(TypedefDecl *D);
void VisitTypeAliasDecl(TypeAliasDecl *D);
void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
@@ -113,8 +114,6 @@
void VisitObjCIvarDecl(ObjCIvarDecl *D);
void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
- void VisitObjCClassDecl(ObjCClassDecl *D);
- void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
void VisitObjCImplDecl(ObjCImplDecl *D);
void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
@@ -155,9 +154,9 @@
Record.push_back(D->isImplicit());
Record.push_back(D->isUsed(false));
Record.push_back(D->isReferenced());
- Record.push_back(D->TopLevelDeclInObjCContainer);
+ Record.push_back(D->isTopLevelDeclInObjCContainer());
Record.push_back(D->getAccess());
- Record.push_back(D->ModulePrivate);
+ Record.push_back(D->isModulePrivate());
Record.push_back(Writer.inferSubmoduleIDFromLocation(D->getLocation()));
}
@@ -176,14 +175,18 @@
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
}
-void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
+void ASTDeclWriter::VisitTypedefNameDecl(TypedefNameDecl *D) {
+ VisitRedeclarable(D);
VisitTypeDecl(D);
- Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+}
+void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
+ VisitTypedefNameDecl(D);
if (!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
- D->RedeclLink.getNext() == D &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
@@ -196,8 +199,7 @@
}
void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) {
- VisitTypeDecl(D);
- Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ VisitTypedefNameDecl(D);
Code = serialization::DECL_TYPEALIAS;
}
@@ -234,7 +236,7 @@
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
@@ -258,7 +260,7 @@
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
@@ -300,9 +302,28 @@
Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
Record.push_back(D->getIdentifierNamespace());
+
+ // FunctionDecl's body is handled last at ASTWriterDecl::Visit,
+ // after everything else is written.
+
+ Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->getStorageClassAsWritten());
+ Record.push_back(D->IsInline);
+ Record.push_back(D->isInlineSpecified());
+ Record.push_back(D->isVirtualAsWritten());
+ Record.push_back(D->isPure());
+ Record.push_back(D->hasInheritedPrototype());
+ Record.push_back(D->hasWrittenPrototype());
+ Record.push_back(D->isDeletedAsWritten());
+ Record.push_back(D->isTrivial());
+ Record.push_back(D->isDefaulted());
+ Record.push_back(D->isExplicitlyDefaulted());
+ Record.push_back(D->hasImplicitReturnZero());
+ Record.push_back(D->isConstexpr());
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+
Record.push_back(D->getTemplatedKind());
switch (D->getTemplatedKind()) {
- default: llvm_unreachable("Unhandled TemplatedKind!");
case FunctionDecl::TK_NonTemplate:
break;
case FunctionDecl::TK_FunctionTemplate:
@@ -366,25 +387,6 @@
}
}
- // FunctionDecl's body is handled last at ASTWriterDecl::Visit,
- // after everything else is written.
-
- Record.push_back(D->getStorageClass()); // FIXME: stable encoding
- Record.push_back(D->getStorageClassAsWritten());
- Record.push_back(D->IsInline);
- Record.push_back(D->isInlineSpecified());
- Record.push_back(D->isVirtualAsWritten());
- Record.push_back(D->isPure());
- Record.push_back(D->hasInheritedPrototype());
- Record.push_back(D->hasWrittenPrototype());
- Record.push_back(D->isDeletedAsWritten());
- Record.push_back(D->isTrivial());
- Record.push_back(D->isDefaulted());
- Record.push_back(D->isExplicitlyDefaulted());
- Record.push_back(D->hasImplicitReturnZero());
- Record.push_back(D->isConstexpr());
- Writer.AddSourceLocation(D->getLocEnd(), Record);
-
Record.push_back(D->param_size());
for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
P != PEnd; ++P)
@@ -451,10 +453,8 @@
VisitObjCContainerDecl(D);
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
- ObjCInterfaceDecl *Def = D->getDefinition();
- Writer.AddDeclRef(Def, Record);
-
- if (D == Def) {
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition()) {
// Write the DefinitionData
ObjCInterfaceDecl::DefinitionData &Data = D->data();
@@ -514,18 +514,21 @@
}
void ASTDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+ VisitRedeclarable(D);
VisitObjCContainerDecl(D);
- Record.push_back(D->isInitiallyForwardDecl());
- Record.push_back(D->isForwardDecl());
- Writer.AddSourceLocation(D->getLocEnd(), Record);
- Record.push_back(D->protocol_size());
- for (ObjCProtocolDecl::protocol_iterator
- I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
- Writer.AddDeclRef(*I, Record);
- for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
- PLEnd = D->protocol_loc_end();
- PL != PLEnd; ++PL)
- Writer.AddSourceLocation(*PL, Record);
+
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition()) {
+ Record.push_back(D->protocol_size());
+ for (ObjCProtocolDecl::protocol_iterator
+ I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
+ PLEnd = D->protocol_loc_end();
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
+ }
+
Code = serialization::DECL_OBJC_PROTOCOL;
}
@@ -534,26 +537,6 @@
Code = serialization::DECL_OBJC_AT_DEFS_FIELD;
}
-void ASTDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) {
- VisitDecl(D);
- Writer.AddDeclRef(D->Interface, Record);
- Writer.AddSourceLocation(D->InterfaceLoc, Record);
- Code = serialization::DECL_OBJC_CLASS;
-}
-
-void ASTDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
- VisitDecl(D);
- Record.push_back(D->protocol_size());
- for (ObjCForwardProtocolDecl::protocol_iterator
- I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
- Writer.AddDeclRef(*I, Record);
- for (ObjCForwardProtocolDecl::protocol_loc_iterator
- PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end();
- PL != PLEnd; ++PL)
- Writer.AddSourceLocation(*PL, Record);
- Code = serialization::DECL_OBJC_FORWARD_PROTOCOL;
-}
-
void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
VisitObjCContainerDecl(D);
Writer.AddDeclRef(D->getClassInterface(), Record);
@@ -678,9 +661,12 @@
Record.push_back(D->isNRVOVariable());
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->isARCPseudoStrong());
- Record.push_back(D->getInit() ? 1 : 0);
- if (D->getInit())
+ if (D->getInit()) {
+ Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
Writer.AddStmt(D->getInit());
+ } else {
+ Record.push_back(0);
+ }
MemberSpecializationInfo *SpecInfo
= D->isStaticDataMember() ? D->getMemberSpecializationInfo() : 0;
@@ -701,7 +687,7 @@
!D->isModulePrivate() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->hasCXXDirectInitializer() &&
D->getInit() == 0 &&
!isa<ParmVarDecl>(D) &&
@@ -738,6 +724,7 @@
!D->hasExtInfo() &&
!D->isImplicit() &&
!D->isUsed(false) &&
+ !D->isReferenced() &&
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
D->getStorageClass() == 0 &&
@@ -756,7 +743,7 @@
assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread");
assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
- assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl");
+ assert(D->getPreviousDecl() == 0 && "PARM_VAR_DECL can't be redecl");
assert(!D->isStaticDataMember() &&
"PARM_VAR_DECL can't be static data member");
}
@@ -811,18 +798,14 @@
void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
+ VisitRedeclarable(D);
VisitNamedDecl(D);
Record.push_back(D->isInline());
Writer.AddSourceLocation(D->getLocStart(), Record);
Writer.AddSourceLocation(D->getRBraceLoc(), Record);
- Writer.AddDeclRef(D->getNextNamespace(), Record);
- // Only write one reference--original or anonymous
- Record.push_back(D->isOriginalNamespace());
if (D->isOriginalNamespace())
Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
- else
- Writer.AddDeclRef(D->getOriginalNamespace(), Record);
Code = serialization::DECL_NAMESPACE;
if (Writer.hasChain() && !D->isOriginalNamespace() &&
@@ -845,7 +828,8 @@
}
}
- if (Writer.hasChain() && D->isAnonymousNamespace() && !D->getNextNamespace()){
+ if (Writer.hasChain() && D->isAnonymousNamespace() &&
+ D == D->getMostRecentDecl()) {
// This is a most recent reopening of the anonymous namespace. If its parent
// is in a previous PCH (or is the TU), mark that parent for update, because
// the original namespace always points to the latest re-opening of its
@@ -874,7 +858,7 @@
Writer.AddSourceLocation(D->getUsingLocation(), Record);
Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
- Writer.AddDeclRef(D->FirstUsingShadow, Record);
+ Writer.AddDeclRef(D->FirstUsingShadow.getPointer(), Record);
Record.push_back(D->isTypeName());
Writer.AddDeclRef(Context.getInstantiatedFromUsingDecl(D), Record);
Code = serialization::DECL_USING;
@@ -916,12 +900,8 @@
void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
VisitRecordDecl(D);
-
- CXXRecordDecl *DefinitionDecl = 0;
- if (D->DefinitionData)
- DefinitionDecl = D->DefinitionData->Definition;
- Writer.AddDeclRef(DefinitionDecl, Record);
- if (D == DefinitionDecl)
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition())
Writer.AddCXXDefinitionData(D, Record);
enum {
@@ -1042,36 +1022,17 @@
}
void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
+ VisitRedeclarable(D);
+
// Emit data to initialize CommonOrPrev before VisitTemplateDecl so that
// getCommonPtr() can be used while this is still initializing.
-
- Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
- if (D->getPreviousDeclaration())
- Writer.AddDeclRef(D->getFirstDeclaration(), Record);
-
- if (D->getPreviousDeclaration() == 0) {
- // This TemplateDecl owns the CommonPtr; write it.
- assert(D->isCanonicalDecl());
-
+ if (D->isFirstDeclaration()) {
+ // This declaration owns the 'common' pointer, so serialize that data now.
Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record);
if (D->getInstantiatedFromMemberTemplate())
Record.push_back(D->isMemberSpecialization());
-
- Writer.AddDeclRef(D->getCommonPtr()->Latest, Record);
- } else {
- RedeclarableTemplateDecl *First = D->getFirstDeclaration();
- assert(First != D);
- // If this is a most recent redeclaration that is pointed to by a first decl
- // in a chained PCH, keep track of the association with the map so we can
- // update the first decl during AST reading.
- if (First->getMostRecentDeclaration() == D &&
- First->isFromASTFile() && !D->isFromASTFile()) {
- assert(Writer.FirstLatestDecls.find(First)==Writer.FirstLatestDecls.end()
- && "The latest is already set");
- Writer.FirstLatestDecls[First] = D;
- }
}
-
+
VisitTemplateDecl(D);
Record.push_back(D->getIdentifierNamespace());
}
@@ -1079,7 +1040,7 @@
void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
- if (D->getPreviousDeclaration() == 0) {
+ if (D->isFirstDeclaration()) {
typedef llvm::FoldingSet<ClassTemplateSpecializationDecl> CTSDSetTy;
CTSDSetTy &CTSDSet = D->getSpecializations();
Record.push_back(CTSDSet.size());
@@ -1148,7 +1109,7 @@
Record.push_back(D->getSequenceNumber());
// These are read/set from/to the first declaration.
- if (D->getPreviousDeclaration() == 0) {
+ if (D->getPreviousDecl() == 0) {
Writer.AddDeclRef(D->getInstantiatedFromMember(), Record);
Record.push_back(D->isMemberSpecialization());
}
@@ -1167,7 +1128,7 @@
void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
- if (D->getPreviousDeclaration() == 0) {
+ if (D->isFirstDeclaration()) {
// This FunctionTemplateDecl owns the CommonPtr; write it.
// Write the function specialization declarations.
@@ -1267,31 +1228,23 @@
template <typename T>
void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
- enum { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
- if (D->RedeclLink.getNext() == D) {
- Record.push_back(NoRedeclaration);
- } else {
- if (D->RedeclLink.NextIsPrevious()) {
- Record.push_back(PointsToPrevious);
- Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
- Writer.AddDeclRef(D->getFirstDeclaration(), Record);
- } else {
- Record.push_back(PointsToLatest);
- Writer.AddDeclRef(D->RedeclLink.getPointer(), Record);
- }
- }
-
T *First = D->getFirstDeclaration();
- T *ThisDecl = static_cast<T*>(D);
- // If this is a most recent redeclaration that is pointed to by a first decl
- // in a chained PCH, keep track of the association with the map so we can
- // update the first decl during AST reading.
- if (ThisDecl != First && First->getMostRecentDeclaration() == ThisDecl &&
- First->isFromASTFile() && !ThisDecl->isFromASTFile()) {
- assert(Writer.FirstLatestDecls.find(First) == Writer.FirstLatestDecls.end()
- && "The latest is already set");
- Writer.FirstLatestDecls[First] = ThisDecl;
+ if (First->getMostRecentDecl() != First) {
+ // There is more than one declaration of this entity, so we will need to
+ // write a redeclaration chain.
+ Writer.AddDeclRef(First, Record);
+ Writer.Redeclarations.insert(First);
+
+ // Make sure that we serialize both the previous and the most-recent
+ // declarations, which (transitively) ensures that all declarations in the
+ // chain get serialized.
+ (void)Writer.GetDeclRef(D->getPreviousDecl());
+ (void)Writer.GetDeclRef(First->getMostRecentDecl());
+ } else {
+ // We use the sentinel value 0 to indicate an only declaration.
+ Record.push_back(0);
}
+
}
//===----------------------------------------------------------------------===//
@@ -1374,7 +1327,7 @@
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM));
// Redeclarable
- Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1421,7 +1374,7 @@
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD));
// Redeclarable
- Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1511,6 +1464,8 @@
// Abbreviation for DECL_TYPEDEF
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1688,12 +1643,18 @@
VisibleOffset = WriteDeclContextVisibleBlock(Context, DC);
}
- // Determine the ID for this declaration
- serialization::DeclID &IDR = DeclIDs[D];
- if (IDR == 0)
- IDR = NextDeclID++;
- serialization::DeclID ID = IDR;
-
+ // Determine the ID for this declaration.
+ serialization::DeclID ID;
+ if (D->isFromASTFile())
+ ID = getDeclID(D);
+ else {
+ serialization::DeclID &IDR = DeclIDs[D];
+ if (IDR == 0)
+ IDR = NextDeclID++;
+
+ ID= IDR;
+ }
+
if (ID < FirstDeclID) {
// We're replacing a decl in a previous file.
ReplacedDecls.push_back(ReplacedDeclInfo(ID, Stream.GetCurrentBitNo(),
Modified: cfe/branches/tooling/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/ASTWriterStmt.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/branches/tooling/lib/Serialization/ASTWriterStmt.cpp Fri Jan 20 10:14:22 2012
@@ -848,6 +848,7 @@
Record.push_back(E->getNumStoredSelLocs());
Record.push_back(E->SelLocsKind);
Record.push_back(E->isDelegateInitCall());
+ Record.push_back(E->IsImplicit);
Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
Modified: cfe/branches/tooling/lib/Serialization/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/CMakeLists.txt?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/CMakeLists.txt (original)
+++ cfe/branches/tooling/lib/Serialization/CMakeLists.txt Fri Jan 20 10:14:22 2012
@@ -1,5 +1,4 @@
-# TODO: This must need some dependencies, but it builds fine without them.
-#set(LLVM_USED_LIBS ???)
+set(LLVM_USED_LIBS clangSema)
add_clang_library(clangSerialization
ASTCommon.h
Modified: cfe/branches/tooling/lib/Serialization/Module.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/Module.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/Module.cpp (original)
+++ cfe/branches/tooling/lib/Serialization/Module.cpp Fri Jan 20 10:14:22 2012
@@ -20,8 +20,8 @@
using namespace serialization;
using namespace reader;
-ModuleFile::ModuleFile(ModuleKind Kind)
- : Kind(Kind), DirectlyImported(false), SizeInBits(0),
+ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
+ : Kind(Kind), DirectlyImported(false), Generation(Generation), SizeInBits(0),
LocalNumSLocEntries(0), SLocEntryBaseID(0),
SLocEntryBaseOffset(0), SLocEntryOffsets(0),
SLocFileOffsets(0), LocalNumIdentifiers(0),
@@ -30,12 +30,12 @@
PreprocessedEntityOffsets(0), NumPreprocessedEntities(0),
LocalNumHeaderFileInfos(0),
HeaderFileInfoTableData(0), HeaderFileInfoTable(0),
- HeaderFileFrameworkStrings(0), LocalNumSubmodules(0),
+ HeaderFileFrameworkStrings(0), LocalNumSubmodules(0), BaseSubmoduleID(0),
LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0),
SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
DeclOffsets(0), BaseDeclID(0),
LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0),
- FileSortedDecls(0),
+ FileSortedDecls(0), RedeclarationsMap(0), LocalNumRedeclarationsInMap(0),
LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0)
{}
Modified: cfe/branches/tooling/lib/Serialization/ModuleManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/Serialization/ModuleManager.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/Serialization/ModuleManager.cpp (original)
+++ cfe/branches/tooling/lib/Serialization/ModuleManager.cpp Fri Jan 20 10:14:22 2012
@@ -35,7 +35,8 @@
std::pair<ModuleFile *, bool>
ModuleManager::addModule(StringRef FileName, ModuleKind Type,
- ModuleFile *ImportedBy, std::string &ErrorStr) {
+ ModuleFile *ImportedBy, unsigned Generation,
+ std::string &ErrorStr) {
const FileEntry *Entry = FileMgr.getFile(FileName);
if (!Entry && FileName != "-") {
ErrorStr = "file not found";
@@ -47,7 +48,7 @@
bool NewModule = false;
if (!ModuleEntry) {
// Allocate a new module.
- ModuleFile *New = new ModuleFile(Type);
+ ModuleFile *New = new ModuleFile(Type, Generation);
New->FileName = FileName.str();
Chain.push_back(New);
NewModule = true;
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp Fri Jan 20 10:14:22 2012
@@ -38,19 +38,20 @@
// Fetch the signature of the called function.
const ProgramState *state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
- SVal V = state->getSVal(CE);
+ SVal V = state->getSVal(CE, LCtx);
if (V.isUnknown())
return;
// Casting to void? Discard the value.
if (expectedResultTy->isVoidType()) {
- C.addTransition(state->BindExpr(CE, UnknownVal()));
+ C.addTransition(state->BindExpr(CE, LCtx, UnknownVal()));
return;
}
- const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion();
+ const MemRegion *callee = state->getSVal(CE->getCallee(), LCtx).getAsRegion();
if (!callee)
return;
@@ -82,7 +83,7 @@
// the cast avoids some assertion failures elsewhere.
SValBuilder &svalBuilder = C.getSValBuilder();
V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy);
- C.addTransition(state->BindExpr(CE, V));
+ C.addTransition(state->BindExpr(CE, LCtx, V));
}
}
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp Fri Jan 20 10:14:22 2012
@@ -34,9 +34,10 @@
void AttrNonNullChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
const ProgramState *state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
// Check if the callee has a 'nonnull' attribute.
- SVal X = state->getSVal(CE->getCallee());
+ SVal X = state->getSVal(CE->getCallee(), LCtx);
const FunctionDecl *FD = X.getAsFunctionDecl();
if (!FD)
@@ -55,7 +56,7 @@
if (!Att->isNonNull(idx))
continue;
- SVal V = state->getSVal(*I);
+ SVal V = state->getSVal(*I, LCtx);
DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
// If the value is unknown or undefined, we can't perform this check.
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp Fri Jan 20 10:14:22 2012
@@ -129,7 +129,7 @@
Name == "compare:options:range:locale:" ||
Name == "componentsSeparatedByCharactersInSet:" ||
Name == "initWithFormat:") {
- if (isNil(msg.getArgSVal(0, C.getState())))
+ if (isNil(msg.getArgSVal(0, C.getLocationContext(), C.getState())))
WarnNilArg(C, msg, 0);
}
}
@@ -262,7 +262,8 @@
return;
// Get the value of the "theType" argument.
- SVal TheTypeVal = state->getSVal(CE->getArg(1));
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
// FIXME: We really should allow ranges of valid theType values, and
// bifurcate the state appropriately.
@@ -280,7 +281,7 @@
// Look at the value of the integer being passed by reference. Essentially
// we want to catch cases where the value passed in is not equal to the
// size of the type being created.
- SVal TheValueExpr = state->getSVal(CE->getArg(2));
+ SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
// FIXME: Eventually we should handle arbitrary locations. We can do this
// by having an enhanced memory model that does low-level typing.
@@ -382,7 +383,7 @@
// Get the argument's value.
const Expr *Arg = CE->getArg(0);
- SVal ArgVal = state->getSVal(Arg);
+ SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
if (!DefArgVal)
return;
@@ -593,7 +594,8 @@
continue;
// Ignore pointer constants.
- if (isa<loc::ConcreteInt>(msg.getArgSVal(I, state)))
+ if (isa<loc::ConcreteInt>(msg.getArgSVal(I, C.getLocationContext(),
+ state)))
continue;
// Ignore pointer types annotated with 'NSObject' attribute.
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp Fri Jan 20 10:14:22 2012
@@ -33,6 +33,7 @@
CheckerContext &C) const {
const ProgramState *state = C.getState();
const FunctionDecl *FD = C.getCalleeDecl(CE);
+ const LocationContext *LCtx = C.getLocationContext();
if (!FD)
return false;
@@ -45,8 +46,8 @@
case Builtin::BI__builtin_expect: {
// For __builtin_expect, just return the value of the subexpression.
assert (CE->arg_begin() != CE->arg_end());
- SVal X = state->getSVal(*(CE->arg_begin()));
- C.addTransition(state->BindExpr(CE, X));
+ SVal X = state->getSVal(*(CE->arg_begin()), LCtx);
+ C.addTransition(state->BindExpr(CE, LCtx, X));
return true;
}
@@ -60,7 +61,7 @@
// SVal of the argument directly. If we save the extent in bits, we
// cannot represent values like symbol*8.
DefinedOrUnknownSVal Size =
- cast<DefinedOrUnknownSVal>(state->getSVal(*(CE->arg_begin())));
+ cast<DefinedOrUnknownSVal>(state->getSVal(*(CE->arg_begin()), LCtx));
SValBuilder& svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
@@ -68,7 +69,7 @@
svalBuilder.evalEQ(state, Extent, Size);
state = state->assume(extentMatchesSizeArg, true);
- C.addTransition(state->BindExpr(CE, loc::MemRegionVal(R)));
+ C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
return true;
}
}
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CMakeLists.txt?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CMakeLists.txt (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CMakeLists.txt Fri Jan 20 10:14:22 2012
@@ -3,7 +3,7 @@
SOURCE Checkers.td
TARGET ClangSACheckers)
-set(LLVM_USED_LIBS clangBasic clangAST)
+set(LLVM_USED_LIBS clangBasic clangAST clangStaticAnalyzerCore)
add_clang_library(clangStaticAnalyzerCheckers
AdjustedReturnValueChecker.cpp
@@ -62,6 +62,7 @@
UnixAPIChecker.cpp
UnreachableCodeChecker.cpp
VLASizeChecker.cpp
+ VirtualCallChecker.cpp
)
add_dependencies(clangStaticAnalyzerCheckers
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Fri Jan 20 10:14:22 2012
@@ -329,12 +329,13 @@
SValBuilder &svalBuilder = C.getSValBuilder();
ASTContext &Ctx = svalBuilder.getContext();
+ const LocationContext *LCtx = C.getLocationContext();
QualType sizeTy = Size->getType();
QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
// Check that the first buffer is non-null.
- SVal BufVal = state->getSVal(FirstBuf);
+ SVal BufVal = state->getSVal(FirstBuf, LCtx);
state = checkNonNull(C, state, FirstBuf, BufVal);
if (!state)
return NULL;
@@ -342,7 +343,7 @@
// Get the access length and make sure it is known.
// FIXME: This assumes the caller has already checked that the access length
// is positive. And that it's unsigned.
- SVal LengthVal = state->getSVal(Size);
+ SVal LengthVal = state->getSVal(Size, LCtx);
NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
if (!Length)
return state;
@@ -368,7 +369,7 @@
// If there's a second buffer, check it as well.
if (SecondBuf) {
- BufVal = state->getSVal(SecondBuf);
+ BufVal = state->getSVal(SecondBuf, LCtx);
state = checkNonNull(C, state, SecondBuf, BufVal);
if (!state)
return NULL;
@@ -403,8 +404,9 @@
const ProgramState *stateTrue, *stateFalse;
// Get the buffer values and make sure they're known locations.
- SVal firstVal = state->getSVal(First);
- SVal secondVal = state->getSVal(Second);
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal firstVal = state->getSVal(First, LCtx);
+ SVal secondVal = state->getSVal(Second, LCtx);
Loc *firstLoc = dyn_cast<Loc>(&firstVal);
if (!firstLoc)
@@ -456,7 +458,7 @@
}
// Get the length, and make sure it too is known.
- SVal LengthVal = state->getSVal(Size);
+ SVal LengthVal = state->getSVal(Size, LCtx);
NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
if (!Length)
return state;
@@ -846,7 +848,8 @@
CurrentFunctionDescription = "memory copy function";
// See if the size argument is zero.
- SVal sizeVal = state->getSVal(Size);
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal sizeVal = state->getSVal(Size, LCtx);
QualType sizeTy = Size->getType();
const ProgramState *stateZeroSize, *stateNonZeroSize;
@@ -854,12 +857,12 @@
assumeZero(C, state, sizeVal, sizeTy);
// Get the value of the Dest.
- SVal destVal = state->getSVal(Dest);
+ SVal destVal = state->getSVal(Dest, LCtx);
// If the size is zero, there won't be any actual memory access, so
// just bind the return value to the destination buffer and return.
if (stateZeroSize) {
- stateZeroSize = stateZeroSize->BindExpr(CE, destVal);
+ stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal);
C.addTransition(stateZeroSize);
}
@@ -874,7 +877,7 @@
return;
// Get the value of the Src.
- SVal srcVal = state->getSVal(Source);
+ SVal srcVal = state->getSVal(Source, LCtx);
// Ensure the source is not null. If it is NULL there will be a
// NULL pointer dereference.
@@ -910,20 +913,20 @@
Dest->getType());
// The byte after the last byte copied is the return value.
- state = state->BindExpr(CE, lastElement);
+ state = state->BindExpr(CE, LCtx, lastElement);
} else {
// If we don't know how much we copied, we can at least
// conjure a return value for later.
unsigned Count = C.getCurrentBlockCount();
SVal result =
C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
- state = state->BindExpr(CE, result);
+ state = state->BindExpr(CE, LCtx, result);
}
} else {
// All other copies return the destination buffer.
// (Well, bcopy() has a void return type, but this won't hurt.)
- state = state->BindExpr(CE, destVal);
+ state = state->BindExpr(CE, LCtx, destVal);
}
// Invalidate the destination.
@@ -931,7 +934,8 @@
// can use LazyCompoundVals to copy the source values into the destination.
// This would probably remove any existing bindings past the end of the
// copied region, but that's still an improvement over blank invalidation.
- state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest));
+ state = InvalidateBuffer(C, state, Dest,
+ state->getSVal(Dest, C.getLocationContext()));
C.addTransition(state);
}
}
@@ -982,7 +986,8 @@
SValBuilder &svalBuilder = C.getSValBuilder();
// See if the size argument is zero.
- SVal sizeVal = state->getSVal(Size);
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal sizeVal = state->getSVal(Size, LCtx);
QualType sizeTy = Size->getType();
const ProgramState *stateZeroSize, *stateNonZeroSize;
@@ -993,7 +998,8 @@
// have to check either of the buffers.
if (stateZeroSize) {
state = stateZeroSize;
- state = state->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
+ state = state->BindExpr(CE, LCtx,
+ svalBuilder.makeZeroVal(CE->getType()));
C.addTransition(state);
}
@@ -1003,8 +1009,10 @@
// If we know the two buffers are the same, we know the result is 0.
// First, get the two buffers' addresses. Another checker will have already
// made sure they're not undefined.
- DefinedOrUnknownSVal LV = cast<DefinedOrUnknownSVal>(state->getSVal(Left));
- DefinedOrUnknownSVal RV = cast<DefinedOrUnknownSVal>(state->getSVal(Right));
+ DefinedOrUnknownSVal LV =
+ cast<DefinedOrUnknownSVal>(state->getSVal(Left, LCtx));
+ DefinedOrUnknownSVal RV =
+ cast<DefinedOrUnknownSVal>(state->getSVal(Right, LCtx));
// See if they are the same.
DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
@@ -1017,7 +1025,8 @@
state = StSameBuf;
state = CheckBufferAccess(C, state, Size, Left);
if (state) {
- state = StSameBuf->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
+ state = StSameBuf->BindExpr(CE, LCtx,
+ svalBuilder.makeZeroVal(CE->getType()));
C.addTransition(state);
}
}
@@ -1031,7 +1040,7 @@
// The return value is the comparison result, which we don't know.
unsigned Count = C.getCurrentBlockCount();
SVal CmpV = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
- state = state->BindExpr(CE, CmpV);
+ state = state->BindExpr(CE, LCtx, CmpV);
C.addTransition(state);
}
}
@@ -1054,10 +1063,11 @@
bool IsStrnlen) const {
CurrentFunctionDescription = "string length function";
const ProgramState *state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
if (IsStrnlen) {
const Expr *maxlenExpr = CE->getArg(1);
- SVal maxlenVal = state->getSVal(maxlenExpr);
+ SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
const ProgramState *stateZeroSize, *stateNonZeroSize;
llvm::tie(stateZeroSize, stateNonZeroSize) =
@@ -1067,7 +1077,7 @@
// have to check the string itself.
if (stateZeroSize) {
SVal zero = C.getSValBuilder().makeZeroVal(CE->getType());
- stateZeroSize = stateZeroSize->BindExpr(CE, zero);
+ stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero);
C.addTransition(stateZeroSize);
}
@@ -1081,7 +1091,7 @@
// Check that the string argument is non-null.
const Expr *Arg = CE->getArg(0);
- SVal ArgVal = state->getSVal(Arg);
+ SVal ArgVal = state->getSVal(Arg, LCtx);
state = checkNonNull(C, state, Arg, ArgVal);
@@ -1105,7 +1115,7 @@
// It's a little unfortunate to be getting this again,
// but it's not that expensive...
const Expr *maxlenExpr = CE->getArg(1);
- SVal maxlenVal = state->getSVal(maxlenExpr);
+ SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal);
@@ -1170,7 +1180,7 @@
// Bind the return value.
assert(!result.isUnknown() && "Should have conjured a value by now");
- state = state->BindExpr(CE, result);
+ state = state->BindExpr(CE, LCtx, result);
C.addTransition(state);
}
@@ -1219,10 +1229,11 @@
bool isAppending) const {
CurrentFunctionDescription = "string copy function";
const ProgramState *state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
// Check that the destination is non-null.
const Expr *Dst = CE->getArg(0);
- SVal DstVal = state->getSVal(Dst);
+ SVal DstVal = state->getSVal(Dst, LCtx);
state = checkNonNull(C, state, Dst, DstVal);
if (!state)
@@ -1230,7 +1241,7 @@
// Check that the source is non-null.
const Expr *srcExpr = CE->getArg(1);
- SVal srcVal = state->getSVal(srcExpr);
+ SVal srcVal = state->getSVal(srcExpr, LCtx);
state = checkNonNull(C, state, srcExpr, srcVal);
if (!state)
return;
@@ -1257,7 +1268,7 @@
if (isBounded) {
// Get the max number of characters to copy.
const Expr *lenExpr = CE->getArg(2);
- SVal lenVal = state->getSVal(lenExpr);
+ SVal lenVal = state->getSVal(lenExpr, LCtx);
// Protect against misdeclared strncpy().
lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->getType());
@@ -1512,7 +1523,7 @@
}
// Set the return value.
- state = state->BindExpr(CE, Result);
+ state = state->BindExpr(CE, LCtx, Result);
C.addTransition(state);
}
@@ -1542,17 +1553,18 @@
bool isBounded, bool ignoreCase) const {
CurrentFunctionDescription = "string comparison function";
const ProgramState *state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
// Check that the first string is non-null
const Expr *s1 = CE->getArg(0);
- SVal s1Val = state->getSVal(s1);
+ SVal s1Val = state->getSVal(s1, LCtx);
state = checkNonNull(C, state, s1, s1Val);
if (!state)
return;
// Check that the second string is non-null.
const Expr *s2 = CE->getArg(1);
- SVal s2Val = state->getSVal(s2);
+ SVal s2Val = state->getSVal(s2, LCtx);
state = checkNonNull(C, state, s2, s2Val);
if (!state)
return;
@@ -1582,7 +1594,8 @@
// If the two arguments might be the same buffer, we know the result is 0,
// and we only need to check one size.
if (StSameBuf) {
- StSameBuf = StSameBuf->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
+ StSameBuf = StSameBuf->BindExpr(CE, LCtx,
+ svalBuilder.makeZeroVal(CE->getType()));
C.addTransition(StSameBuf);
// If the two arguments are GUARANTEED to be the same, we're done!
@@ -1608,7 +1621,7 @@
if (isBounded) {
// Get the max number of characters to compare.
const Expr *lenExpr = CE->getArg(2);
- SVal lenVal = state->getSVal(lenExpr);
+ SVal lenVal = state->getSVal(lenExpr, LCtx);
// If the length is known, we can get the right substrings.
if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
@@ -1645,7 +1658,7 @@
// Build the SVal of the comparison and bind the return value.
SVal resultVal = svalBuilder.makeIntVal(result, CE->getType());
- state = state->BindExpr(CE, resultVal);
+ state = state->BindExpr(CE, LCtx, resultVal);
}
}
@@ -1653,7 +1666,7 @@
// Conjure a symbolic value. It's the best we can do.
unsigned Count = C.getCurrentBlockCount();
SVal resultVal = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
- state = state->BindExpr(CE, resultVal);
+ state = state->BindExpr(CE, LCtx, resultVal);
}
// Record this as a possible path.
@@ -1728,7 +1741,7 @@
if (!MR)
continue;
- SVal StrVal = state->getSVal(Init);
+ SVal StrVal = state->getSVal(Init, C.getLocationContext());
assert(StrVal.isValid() && "Initializer string is unknown or undefined");
DefinedOrUnknownSVal strLength
= cast<DefinedOrUnknownSVal>(getCStringLength(C, state, Init, StrVal));
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp Fri Jan 20 10:14:22 2012
@@ -133,7 +133,7 @@
return true;
}
else {
- const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR));
+ const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
if (V.isUndef())
return true;
}
@@ -193,7 +193,8 @@
CheckerContext &C) const{
const Expr *Callee = CE->getCallee()->IgnoreParens();
- SVal L = C.getState()->getSVal(Callee);
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal L = C.getState()->getSVal(Callee, LCtx);
if (L.isUndef()) {
if (!BT_call_undef)
@@ -210,7 +211,7 @@
EmitBadCall(BT_call_null.get(), C, CE);
}
- PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()),
+ PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState(), LCtx),
"Function call argument is an uninitialized value",
BT_call_arg);
}
@@ -219,10 +220,11 @@
CheckerContext &C) const {
const ProgramState *state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
// FIXME: Handle 'super'?
if (const Expr *receiver = msg.getInstanceReceiver()) {
- SVal recVal = state->getSVal(receiver);
+ SVal recVal = state->getSVal(receiver, LCtx);
if (recVal.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_msg_undef)
@@ -255,7 +257,8 @@
"Argument for property setter is an uninitialized value"
: "Argument in message expression is an uninitialized value";
// Check for any arguments that are uninitialized/undefined.
- PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), bugDesc, BT_msg_arg);
+ PreVisitProcessArgs(C, CallOrObjCMessage(msg, state, LCtx),
+ bugDesc, BT_msg_arg);
}
void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
@@ -298,11 +301,12 @@
// return different values depending on the return type and the architecture.
QualType RetTy = msg.getType(Ctx);
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
+ const LocationContext *LCtx = C.getLocationContext();
if (CanRetTy->isStructureOrClassType()) {
// Structure returns are safe since the compiler zeroes them out.
SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
- C.addTransition(state->BindExpr(msg.getOriginExpr(), V));
+ C.addTransition(state->BindExpr(msg.getOriginExpr(), LCtx, V));
return;
}
@@ -339,7 +343,7 @@
// of this case unless we have *a lot* more knowledge.
//
SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
- C.addTransition(state->BindExpr(msg.getOriginExpr(), V));
+ C.addTransition(state->BindExpr(msg.getOriginExpr(), LCtx, V));
return;
}
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp Fri Jan 20 10:14:22 2012
@@ -45,7 +45,7 @@
return;
const ProgramState *state = C.getState();
- const MemRegion *R = state->getSVal(E).getAsRegion();
+ const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion();
if (R == 0)
return;
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp Fri Jan 20 10:14:22 2012
@@ -34,6 +34,25 @@
}
namespace {
+struct DefaultBool {
+ bool val;
+ DefaultBool() : val(false) {}
+ operator bool() const { return val; }
+ DefaultBool &operator=(bool b) { val = b; return *this; }
+};
+
+struct ChecksFilter {
+ DefaultBool check_gets;
+ DefaultBool check_getpw;
+ DefaultBool check_mktemp;
+ DefaultBool check_mkstemp;
+ DefaultBool check_strcpy;
+ DefaultBool check_rand;
+ DefaultBool check_vfork;
+ DefaultBool check_FloatLoopCounter;
+ DefaultBool check_UncheckedReturn;
+};
+
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
AnalysisDeclContext* AC;
@@ -41,11 +60,14 @@
IdentifierInfo *II_setid[num_setids];
const bool CheckRand;
+ const ChecksFilter &filter;
public:
- WalkAST(BugReporter &br, AnalysisDeclContext* ac)
+ WalkAST(BugReporter &br, AnalysisDeclContext* ac,
+ const ChecksFilter &f)
: BR(br), AC(ac), II_setid(),
- CheckRand(isArc4RandomAvailable(BR.getContext())) {}
+ CheckRand(isArc4RandomAvailable(BR.getContext())),
+ filter(f) {}
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
@@ -66,6 +88,7 @@
void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
+ void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
@@ -105,6 +128,9 @@
.Case("gets", &WalkAST::checkCall_gets)
.Case("getpw", &WalkAST::checkCall_getpw)
.Case("mktemp", &WalkAST::checkCall_mktemp)
+ .Case("mkstemp", &WalkAST::checkCall_mkstemp)
+ .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
+ .Case("mkstemps", &WalkAST::checkCall_mkstemp)
.Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
.Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
.Case("drand48", &WalkAST::checkCall_rand)
@@ -186,6 +212,9 @@
/// CERT: FLP30-C, FLP30-CPP.
///
void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
+ if (!filter.check_FloatLoopCounter)
+ return;
+
// Does the loop have a condition?
const Expr *condition = FS->getCond();
@@ -268,6 +297,9 @@
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_gets)
+ return;
+
const FunctionProtoType *FPT
= dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
if (!FPT)
@@ -302,6 +334,9 @@
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_getpw)
+ return;
+
const FunctionProtoType *FPT
= dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
if (!FPT)
@@ -335,11 +370,18 @@
}
//===----------------------------------------------------------------------===//
-// Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp().
+// Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp().
// CWE-377: Insecure Temporary File
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_mktemp) {
+ // Fall back to the security check of looking for enough 'X's in the
+ // format string, since that is a less severe warning.
+ checkCall_mkstemp(CE, FD);
+ return;
+ }
+
const FunctionProtoType *FPT
= dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
if(!FPT)
@@ -369,6 +411,88 @@
CELoc, &R, 1);
}
+
+//===----------------------------------------------------------------------===//
+// Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
+//===----------------------------------------------------------------------===//
+
+void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_mkstemp)
+ return;
+
+ StringRef Name = FD->getIdentifier()->getName();
+ std::pair<signed, signed> ArgSuffix =
+ llvm::StringSwitch<std::pair<signed, signed> >(Name)
+ .Case("mktemp", std::make_pair(0,-1))
+ .Case("mkstemp", std::make_pair(0,-1))
+ .Case("mkdtemp", std::make_pair(0,-1))
+ .Case("mkstemps", std::make_pair(0,1))
+ .Default(std::make_pair(-1, -1));
+
+ assert(ArgSuffix.first >= 0 && "Unsupported function");
+
+ // Check if the number of arguments is consistent with out expectations.
+ unsigned numArgs = CE->getNumArgs();
+ if ((signed) numArgs <= ArgSuffix.first)
+ return;
+
+ const StringLiteral *strArg =
+ dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
+ ->IgnoreParenImpCasts());
+
+ // Currently we only handle string literals. It is possible to do better,
+ // either by looking at references to const variables, or by doing real
+ // flow analysis.
+ if (!strArg || strArg->getCharByteWidth() != 1)
+ return;
+
+ // Count the number of X's, taking into account a possible cutoff suffix.
+ StringRef str = strArg->getString();
+ unsigned numX = 0;
+ unsigned n = str.size();
+
+ // Take into account the suffix.
+ unsigned suffix = 0;
+ if (ArgSuffix.second >= 0) {
+ const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
+ llvm::APSInt Result;
+ if (!suffixEx->EvaluateAsInt(Result, BR.getContext()))
+ return;
+ // FIXME: Issue a warning.
+ if (Result.isNegative())
+ return;
+ suffix = (unsigned) Result.getZExtValue();
+ n = (n > suffix) ? n - suffix : 0;
+ }
+
+ for (unsigned i = 0; i < n; ++i)
+ if (str[i] == 'X') ++numX;
+
+ if (numX >= 6)
+ return;
+
+ // Issue a warning.
+ SourceRange R = strArg->getSourceRange();
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
+ llvm::SmallString<512> buf;
+ llvm::raw_svector_ostream out(buf);
+ out << "Call to '" << Name << "' should have at least 6 'X's in the"
+ " format string to be secure (" << numX << " 'X'";
+ if (numX != 1)
+ out << 's';
+ out << " seen";
+ if (suffix) {
+ out << ", " << suffix << " character";
+ if (suffix > 1)
+ out << 's';
+ out << " used as a suffix";
+ }
+ out << ')';
+ BR.EmitBasicReport("Insecure temporary file creation", "Security",
+ out.str(), CELoc, &R, 1);
+}
+
//===----------------------------------------------------------------------===//
// Check: Any use of 'strcpy' is insecure.
//
@@ -376,6 +500,9 @@
// the Bounds of a Memory Buffer
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_strcpy)
+ return;
+
if (!checkCall_strCommon(CE, FD))
return;
@@ -400,6 +527,9 @@
// the Bounds of a Memory Buffer
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_strcpy)
+ return;
+
if (!checkCall_strCommon(CE, FD))
return;
@@ -453,7 +583,7 @@
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
- if (!CheckRand)
+ if (!filter.check_rand || !CheckRand)
return;
const FunctionProtoType *FTP
@@ -497,7 +627,7 @@
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
- if (!CheckRand)
+ if (!CheckRand || !filter.check_rand)
return;
const FunctionProtoType *FTP
@@ -526,6 +656,9 @@
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_vfork)
+ return;
+
// All calls to vfork() are insecure, issue a warning.
SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
@@ -546,6 +679,9 @@
//===----------------------------------------------------------------------===//
void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
+ if (!filter.check_UncheckedReturn)
+ return;
+
const FunctionDecl *FD = CE->getDirectCallee();
if (!FD)
return;
@@ -609,14 +745,29 @@
namespace {
class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
public:
+ ChecksFilter filter;
+
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- WalkAST walker(BR, mgr.getAnalysisDeclContext(D));
+ WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
walker.Visit(D->getBody());
}
};
}
-void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
- mgr.registerChecker<SecuritySyntaxChecker>();
+#define REGISTER_CHECKER(name) \
+void ento::register##name(CheckerManager &mgr) {\
+ mgr.registerChecker<SecuritySyntaxChecker>()->filter.check_##name = true;\
}
+
+REGISTER_CHECKER(gets)
+REGISTER_CHECKER(getpw)
+REGISTER_CHECKER(mkstemp)
+REGISTER_CHECKER(mktemp)
+REGISTER_CHECKER(strcpy)
+REGISTER_CHECKER(rand)
+REGISTER_CHECKER(vfork)
+REGISTER_CHECKER(FloatLoopCounter)
+REGISTER_CHECKER(UncheckedReturn)
+
+
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/Checkers.td
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/Checkers.td?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/Checkers.td (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/Checkers.td Fri Jan 20 10:14:22 2012
@@ -27,6 +27,7 @@
def DeadCodeExperimental : Package<"deadcode">, InPackage<Experimental>, Hidden;
def Security : Package <"security">;
+def InsecureAPI : Package<"insecureAPI">, InPackage<Security>;
def SecurityExperimental : Package<"security">, InPackage<Experimental>, Hidden;
def Taint : Package<"taint">, InPackage<SecurityExperimental>, Hidden;
@@ -164,6 +165,10 @@
HelpText<"Check improper uses of STL vector iterators">,
DescFile<"IteratorsChecker.cpp">;
+def VirtualCallChecker : Checker<"VirtualCall">,
+ HelpText<"Check virtual function calls during construction or destruction">,
+ DescFile<"VirtualCallChecker.cpp">;
+
} // end: "cplusplus.experimental"
//===----------------------------------------------------------------------===//
@@ -175,15 +180,14 @@
def DeadStoresChecker : Checker<"DeadStores">,
HelpText<"Check for values stored to variables that are never read afterwards">,
DescFile<"DeadStoresChecker.cpp">;
+} // end DeadCode
+
+let ParentPackage = DeadCodeExperimental in {
def IdempotentOperationChecker : Checker<"IdempotentOperations">,
HelpText<"Warn about idempotent operations">,
DescFile<"IdempotentOperationChecker.cpp">;
-} // end DeadCode
-
-let ParentPackage = DeadCodeExperimental in {
-
def UnreachableCodeChecker : Checker<"UnreachableCode">,
HelpText<"Check unreachable code">,
DescFile<"UnreachableCodeChecker.cpp">;
@@ -194,11 +198,39 @@
// Security checkers.
//===----------------------------------------------------------------------===//
-let ParentPackage = SecurityExperimental in {
+let ParentPackage = InsecureAPI in {
+ def gets : Checker<"gets">,
+ HelpText<"Warn on uses of the 'gets' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def getpw : Checker<"getpw">,
+ HelpText<"Warn on uses of the 'getpw' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def mktemp : Checker<"mktemp">,
+ HelpText<"Warn on uses of the 'mktemp' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def mkstemp : Checker<"mkstemp">,
+ HelpText<"Warn when 'mkstemp' is passed fewer than 6 X's in the format string">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def rand : Checker<"rand">,
+ HelpText<"Warn on uses of the 'rand', 'random', and related functions">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def strcpy : Checker<"strcpy">,
+ HelpText<"Warn on uses of the 'strcpy' and 'strcat' functions">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def vfork : Checker<"vfork">,
+ HelpText<"Warn on uses of the 'vfork' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def UncheckedReturn : Checker<"UncheckedReturn">,
+ HelpText<"Warn on uses of functions whose return values must be always checked">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+}
+let ParentPackage = Security in {
+ def FloatLoopCounter : Checker<"FloatLoopCounter">,
+ HelpText<"Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP)">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+}
-def SecuritySyntaxChecker : Checker<"SecuritySyntactic">,
- HelpText<"Perform quick security API checks that require no data flow">,
- DescFile<"CheckSecuritySyntaxOnly.cpp">;
+let ParentPackage = SecurityExperimental in {
def ArrayBoundChecker : Checker<"ArrayBound">,
HelpText<"Warn about buffer overflows (older checker)">,
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp Fri Jan 20 10:14:22 2012
@@ -105,7 +105,7 @@
// After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
const Expr *ArgExpr = CE->getArg(0);
- SVal ArgVal = state->getSVal(ArgExpr);
+ SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext());
if (const MemRegion *R = ArgVal.getAsRegion()) {
R = R->StripCasts();
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp Fri Jan 20 10:14:22 2012
@@ -109,9 +109,6 @@
const char *BugType = 0;
switch (dsk) {
- default:
- llvm_unreachable("Impossible dead store type.");
-
case DeadInit:
BugType = "Dead initialization";
os << "Value stored to '" << *V
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp Fri Jan 20 10:14:22 2012
@@ -16,6 +16,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Analyses/Dominators.h"
+#include "llvm/Support/Process.h"
using namespace clang;
using namespace ento;
@@ -92,7 +93,8 @@
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
if (CFG *cfg = mgr.getCFG(D)) {
- cfg->dump(mgr.getLangOptions());
+ cfg->dump(mgr.getLangOptions(),
+ llvm::sys::Process::StandardErrHasColors());
}
}
};
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp Fri Jan 20 10:14:22 2012
@@ -42,7 +42,7 @@
!B->getRHS()->getType()->isScalarType())
return;
- SVal Denom = C.getState()->getSVal(B->getRHS());
+ SVal Denom = C.getState()->getSVal(B->getRHS(), C.getLocationContext());
const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);
// Divide-by-undefined handled in the generic checking for uses of
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp Fri Jan 20 10:14:22 2012
@@ -45,8 +45,7 @@
return;
const ProgramState *state = C.getState();
-
- SVal RV = state->getSVal(B->getRHS());
+ SVal RV = state->getSVal(B->getRHS(), C.getLocationContext());
if (!RV.isConstant() || RV.isZeroConstant())
return;
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp Fri Jan 20 10:14:22 2012
@@ -20,6 +20,8 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/Basic/Builtins.h"
+#include <climits>
using namespace clang;
using namespace ento;
@@ -28,199 +30,503 @@
class GenericTaintChecker : public Checker< check::PostStmt<CallExpr>,
check::PreStmt<CallExpr> > {
public:
- enum TaintOnPreVisitKind {
- /// No taint propagates from pre-visit to post-visit.
- PrevisitNone = 0,
- /// Based on the pre-visit, the return argument of the call
- /// should be tainted.
- PrevisitTaintRet = 1,
- /// Based on the pre-visit, the call can taint values through it's
- /// pointer/reference arguments.
- PrevisitTaintArgs = 2
- };
+ static void *getTag() { static int Tag; return &Tag; }
+
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const DeclRefExpr *DRE, CheckerContext &C) const;
+
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
private:
+ static const unsigned ReturnValueIndex = UINT_MAX;
+ static const unsigned InvalidArgIndex = UINT_MAX - 1;
+
mutable llvm::OwningPtr<BugType> BT;
- void initBugType() const;
+ inline void initBugType() const {
+ if (!BT)
+ BT.reset(new BugType("Taint Analysis", "General"));
+ }
+
+ /// \brief Catch taint related bugs. Check if tainted data is passed to a
+ /// system call etc.
+ bool checkPre(const CallExpr *CE, CheckerContext &C) const;
+
+ /// \brief Add taint sources on a pre-visit.
+ void addSourcesPre(const CallExpr *CE, CheckerContext &C) const;
- /// Given a pointer argument, get the symbol of the value it contains
+ /// \brief Propagate taint generated at pre-visit.
+ bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const;
+
+ /// \brief Add taint sources on a post visit.
+ void addSourcesPost(const CallExpr *CE, CheckerContext &C) const;
+
+ /// \brief Given a pointer argument, get the symbol of the value it contains
/// (points to).
- SymbolRef getPointedToSymbol(CheckerContext &C,
- const Expr *Arg,
- bool IssueWarning = true) const;
+ static SymbolRef getPointedToSymbol(CheckerContext &C, const Expr *Arg);
+
+ static inline bool isTaintedOrPointsToTainted(const Expr *E,
+ const ProgramState *State,
+ CheckerContext &C) {
+ return (State->isTainted(E, C.getLocationContext()) ||
+ (E->getType().getTypePtr()->isPointerType() &&
+ State->isTainted(getPointedToSymbol(C, E))));
+ }
/// Functions defining the attack surface.
typedef const ProgramState *(GenericTaintChecker::*FnCheck)(const CallExpr *,
CheckerContext &C) const;
const ProgramState *postScanf(const CallExpr *CE, CheckerContext &C) const;
- const ProgramState *postFscanf(const CallExpr *CE, CheckerContext &C) const;
+ const ProgramState *postSocket(const CallExpr *CE, CheckerContext &C) const;
const ProgramState *postRetTaint(const CallExpr *CE, CheckerContext &C) const;
- const ProgramState *postDefault(const CallExpr *CE, CheckerContext &C) const;
/// Taint the scanned input if the file is tainted.
const ProgramState *preFscanf(const CallExpr *CE, CheckerContext &C) const;
- /// Taint if any of the arguments are tainted.
- const ProgramState *preAnyArgs(const CallExpr *CE, CheckerContext &C) const;
/// Check if the region the expression evaluates to is the standard input,
/// and thus, is tainted.
bool isStdin(const Expr *E, CheckerContext &C) const;
-public:
- static void *getTag() { static int Tag; return &Tag; }
+ /// Check for CWE-134: Uncontrolled Format String.
+ static const char MsgUncontrolledFormatString[];
+ bool checkUncontrolledFormatString(const CallExpr *CE,
+ CheckerContext &C) const;
+
+ /// Check for:
+ /// CERT/STR02-C. "Sanitize data passed to complex subsystems"
+ /// CWE-78, "Failure to Sanitize Data into an OS Command"
+ static const char MsgSanitizeSystemArgs[];
+ bool checkSystemCall(const CallExpr *CE, StringRef Name,
+ CheckerContext &C) const;
+
+ /// Check if tainted data is used as a buffer size ins strn.. functions,
+ /// and allocators.
+ static const char MsgTaintedBufferSize[];
+ bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl,
+ CheckerContext &C) const;
+
+ /// Generate a report if the expression is tainted or points to tainted data.
+ bool generateReportIfTainted(const Expr *E, const char Msg[],
+ CheckerContext &C) const;
+
+
+ typedef llvm::SmallVector<unsigned, 2> ArgVector;
- void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
- void checkPostStmt(const DeclRefExpr *DRE, CheckerContext &C) const;
+ /// \brief A struct used to specify taint propagation rules for a function.
+ ///
+ /// If any of the possible taint source arguments is tainted, all of the
+ /// destination arguments should also be tainted. Use InvalidArgIndex in the
+ /// src list to specify that all of the arguments can introduce taint. Use
+ /// InvalidArgIndex in the dst arguments to signify that all the non-const
+ /// pointer and reference arguments might be tainted on return. If
+ /// ReturnValueIndex is added to the dst list, the return value will be
+ /// tainted.
+ struct TaintPropagationRule {
+ /// List of arguments which can be taint sources and should be checked.
+ ArgVector SrcArgs;
+ /// List of arguments which should be tainted on function return.
+ ArgVector DstArgs;
+ // TODO: Check if using other data structures would be more optimal.
+
+ TaintPropagationRule() {}
+
+ TaintPropagationRule(unsigned SArg,
+ unsigned DArg, bool TaintRet = false) {
+ SrcArgs.push_back(SArg);
+ DstArgs.push_back(DArg);
+ if (TaintRet)
+ DstArgs.push_back(ReturnValueIndex);
+ }
- void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+ TaintPropagationRule(unsigned SArg1, unsigned SArg2,
+ unsigned DArg, bool TaintRet = false) {
+ SrcArgs.push_back(SArg1);
+ SrcArgs.push_back(SArg2);
+ DstArgs.push_back(DArg);
+ if (TaintRet)
+ DstArgs.push_back(ReturnValueIndex);
+ }
-};
-}
+ /// Get the propagation rule for a given function.
+ static TaintPropagationRule
+ getTaintPropagationRule(const FunctionDecl *FDecl,
+ StringRef Name,
+ CheckerContext &C);
+
+ inline void addSrcArg(unsigned A) { SrcArgs.push_back(A); }
+ inline void addDstArg(unsigned A) { DstArgs.push_back(A); }
+
+ inline bool isNull() const { return SrcArgs.empty(); }
+
+ inline bool isDestinationArgument(unsigned ArgNum) const {
+ return (std::find(DstArgs.begin(),
+ DstArgs.end(), ArgNum) != DstArgs.end());
+ }
+
+ /// \brief Pre-process a function which propagates taint according to the
+ /// taint rule.
+ const ProgramState *process(const CallExpr *CE, CheckerContext &C) const;
-/// Definitions for the checker specific state.
-namespace { struct TaintOnPreVisit {};}
-namespace clang {
-namespace ento {
- /// A flag which is used to pass information from call pre-visit instruction
- /// to the call post-visit. The value is an unsigned, which takes on values
- /// of the TaintOnPreVisitKind enumeration.
- template<>
- struct ProgramStateTrait<TaintOnPreVisit> :
- public ProgramStatePartialTrait<unsigned> {
- static void *GDMIndex() { return GenericTaintChecker::getTag(); }
};
-}
-}
+};
+
+const unsigned GenericTaintChecker::ReturnValueIndex;
+const unsigned GenericTaintChecker::InvalidArgIndex;
+
+const char GenericTaintChecker::MsgUncontrolledFormatString[] =
+ "Tainted format string (CWE-134: Uncontrolled Format String)";
-inline void GenericTaintChecker::initBugType() const {
- if (!BT)
- BT.reset(new BugType("Tainted data checking", "General"));
+const char GenericTaintChecker::MsgSanitizeSystemArgs[] =
+ "Tainted data passed to a system call "
+ "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
+
+const char GenericTaintChecker::MsgTaintedBufferSize[] =
+ "Tainted data is used to specify the buffer size "
+ "(CERT/STR31-C. Guarantee that storage for strings has sufficient space for "
+ "character data and the null terminator)";
+
+} // end of anonymous namespace
+
+/// A set which is used to pass information from call pre-visit instruction
+/// to the call post-visit. The values are unsigned integers, which are either
+/// ReturnValueIndex, or indexes of the pointer/reference argument, which
+/// points to data, which should be tainted on return.
+namespace { struct TaintArgsOnPostVisit{}; }
+namespace clang { namespace ento {
+template<> struct ProgramStateTrait<TaintArgsOnPostVisit>
+ : public ProgramStatePartialTrait<llvm::ImmutableSet<unsigned> > {
+ static void *GDMIndex() { return GenericTaintChecker::getTag(); }
+};
+}}
+
+GenericTaintChecker::TaintPropagationRule
+GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
+ const FunctionDecl *FDecl,
+ StringRef Name,
+ CheckerContext &C) {
+ // Check for exact name match for functions without builtin substitutes.
+ TaintPropagationRule Rule = llvm::StringSwitch<TaintPropagationRule>(Name)
+ .Case("atoi", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("atol", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("atoll", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("read", TaintPropagationRule(0, 2, 1, true))
+ .Case("pread", TaintPropagationRule(InvalidArgIndex, 1, true))
+ .Default(TaintPropagationRule());
+
+ if (!Rule.isNull())
+ return Rule;
+
+ // Check if it's one of the memory setting/copying functions.
+ // This check is specialized but faster then calling isCLibraryFunction.
+ unsigned BId = 0;
+ if ( (BId = FDecl->getMemoryFunctionKind()) )
+ switch(BId) {
+ case Builtin::BImemcpy:
+ case Builtin::BImemmove:
+ case Builtin::BIstrncpy:
+ case Builtin::BIstrncat:
+ return TaintPropagationRule(1, 2, 0, true);
+ break;
+ case Builtin::BIstrlcpy:
+ case Builtin::BIstrlcat:
+ return TaintPropagationRule(1, 2, 0, false);
+ break;
+ case Builtin::BIstrndup:
+ return TaintPropagationRule(0, 1, ReturnValueIndex);
+ break;
+
+ default:
+ break;
+ };
+
+ // Process all other functions which could be defined as builtins.
+ if (Rule.isNull()) {
+ if (C.isCLibraryFunction(FDecl, "snprintf") ||
+ C.isCLibraryFunction(FDecl, "sprintf"))
+ return TaintPropagationRule(InvalidArgIndex, 0, true);
+ else if (C.isCLibraryFunction(FDecl, "strcpy") ||
+ C.isCLibraryFunction(FDecl, "stpcpy") ||
+ C.isCLibraryFunction(FDecl, "strcat"))
+ return TaintPropagationRule(1, 0, true);
+ else if (C.isCLibraryFunction(FDecl, "bcopy"))
+ return TaintPropagationRule(0, 2, 1, false);
+ else if (C.isCLibraryFunction(FDecl, "strdup") ||
+ C.isCLibraryFunction(FDecl, "strdupa"))
+ return TaintPropagationRule(0, ReturnValueIndex);
+ else if (C.isCLibraryFunction(FDecl, "wcsdup"))
+ return TaintPropagationRule(0, ReturnValueIndex);
+ }
+
+ // Skipping the following functions, since they might be used for cleansing
+ // or smart memory copy:
+ // - memccpy - copying untill hitting a special character.
+
+ return TaintPropagationRule();
}
void GenericTaintChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
- const ProgramState *State = C.getState();
+ // Check for errors first.
+ if (checkPre(CE, C))
+ return;
- // Set the evaluation function by switching on the callee name.
- StringRef Name = C.getCalleeName(CE);
+ // Add taint second.
+ addSourcesPre(CE, C);
+}
+
+void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ if (propagateFromPre(CE, C))
+ return;
+ addSourcesPost(CE, C);
+}
+
+void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
+ CheckerContext &C) const {
+ const ProgramState *State = 0;
+ const FunctionDecl *FDecl = C.getCalleeDecl(CE);
+ StringRef Name = C.getCalleeName(FDecl);
+ if (Name.empty())
+ return;
+
+ // First, try generating a propagation rule for this function.
+ TaintPropagationRule Rule =
+ TaintPropagationRule::getTaintPropagationRule(FDecl, Name, C);
+ if (!Rule.isNull()) {
+ State = Rule.process(CE, C);
+ if (!State)
+ return;
+ C.addTransition(State);
+ return;
+ }
+
+ // Otherwise, check if we have custom pre-processing implemented.
FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
.Case("fscanf", &GenericTaintChecker::preFscanf)
- .Case("atoi", &GenericTaintChecker::preAnyArgs)
- .Case("atol", &GenericTaintChecker::preAnyArgs)
- .Case("atoll", &GenericTaintChecker::preAnyArgs)
.Default(0);
-
// Check and evaluate the call.
if (evalFunction)
State = (this->*evalFunction)(CE, C);
if (!State)
return;
-
C.addTransition(State);
+
}
-void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
- CheckerContext &C) const {
+bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
+ CheckerContext &C) const {
const ProgramState *State = C.getState();
-
+
+ // Depending on what was tainted at pre-visit, we determined a set of
+ // arguments which should be tainted after the function returns. These are
+ // stored in the state as TaintArgsOnPostVisit set.
+ llvm::ImmutableSet<unsigned> TaintArgs = State->get<TaintArgsOnPostVisit>();
+ for (llvm::ImmutableSet<unsigned>::iterator
+ I = TaintArgs.begin(), E = TaintArgs.end(); I != E; ++I) {
+ unsigned ArgNum = *I;
+
+ // Special handling for the tainted return value.
+ if (ArgNum == ReturnValueIndex) {
+ State = State->addTaint(CE, C.getLocationContext());
+ continue;
+ }
+
+ // The arguments are pointer arguments. The data they are pointing at is
+ // tainted after the call.
+ const Expr* Arg = CE->getArg(ArgNum);
+ SymbolRef Sym = getPointedToSymbol(C, Arg);
+ if (Sym)
+ State = State->addTaint(Sym);
+ }
+
+ // Clear up the taint info from the state.
+ State = State->remove<TaintArgsOnPostVisit>();
+
+ if (State != C.getState()) {
+ C.addTransition(State);
+ return true;
+ }
+ return false;
+}
+
+void GenericTaintChecker::addSourcesPost(const CallExpr *CE,
+ CheckerContext &C) const {
// Define the attack surface.
// Set the evaluation function by switching on the callee name.
StringRef Name = C.getCalleeName(CE);
+ if (Name.empty())
+ return;
FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
.Case("scanf", &GenericTaintChecker::postScanf)
- .Case("fscanf", &GenericTaintChecker::postFscanf)
- .Case("sscanf", &GenericTaintChecker::postFscanf)
// TODO: Add support for vfscanf & family.
.Case("getchar", &GenericTaintChecker::postRetTaint)
.Case("getenv", &GenericTaintChecker::postRetTaint)
.Case("fopen", &GenericTaintChecker::postRetTaint)
.Case("fdopen", &GenericTaintChecker::postRetTaint)
.Case("freopen", &GenericTaintChecker::postRetTaint)
- .Default(&GenericTaintChecker::postDefault);
+ .Case("socket", &GenericTaintChecker::postSocket)
+ .Default(0);
// If the callee isn't defined, it is not of security concern.
// Check and evaluate the call.
+ const ProgramState *State = 0;
if (evalFunction)
State = (this->*evalFunction)(CE, C);
if (!State)
return;
- assert(State->get<TaintOnPreVisit>() == PrevisitNone &&
- "State has to be cleared.");
C.addTransition(State);
}
+bool GenericTaintChecker::checkPre(const CallExpr *CE, CheckerContext &C) const{
+
+ if (checkUncontrolledFormatString(CE, C))
+ return true;
+
+ const FunctionDecl *FDecl = C.getCalleeDecl(CE);
+ StringRef Name = C.getCalleeName(FDecl);
+ if (Name.empty())
+ return false;
+
+ if (checkSystemCall(CE, Name, C))
+ return true;
+
+ if (checkTaintedBufferSize(CE, FDecl, C))
+ return true;
+
+ return false;
+}
+
SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
- const Expr* Arg,
- bool IssueWarning) const {
+ const Expr* Arg) {
const ProgramState *State = C.getState();
- SVal AddrVal = State->getSVal(Arg->IgnoreParens());
+ SVal AddrVal = State->getSVal(Arg->IgnoreParens(), C.getLocationContext());
if (AddrVal.isUnknownOrUndef())
return 0;
Loc *AddrLoc = dyn_cast<Loc>(&AddrVal);
-
- if (!AddrLoc && !IssueWarning)
+ if (!AddrLoc)
return 0;
- // If the Expr is not a location, issue a warning.
- if (!AddrLoc) {
- assert(IssueWarning);
- if (ExplodedNode *N = C.generateSink(State)) {
- initBugType();
- BugReport *report = new BugReport(*BT, "Pointer argument is expected.",N);
- report->addRange(Arg->getSourceRange());
- C.EmitReport(report);
+ const PointerType *ArgTy =
+ dyn_cast<PointerType>(Arg->getType().getCanonicalType().getTypePtr());
+ assert(ArgTy);
+ SVal Val = State->getSVal(*AddrLoc, ArgTy->getPointeeType());
+ return Val.getAsSymbol();
+}
+
+const ProgramState *
+GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
+ CheckerContext &C) const {
+ const ProgramState *State = C.getState();
+
+ // Check for taint in arguments.
+ bool IsTainted = false;
+ for (ArgVector::const_iterator I = SrcArgs.begin(),
+ E = SrcArgs.end(); I != E; ++I) {
+ unsigned ArgNum = *I;
+
+ if (ArgNum == InvalidArgIndex) {
+ // Check if any of the arguments is tainted, but skip the
+ // destination arguments.
+ for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
+ if (isDestinationArgument(i))
+ continue;
+ if ((IsTainted =
+ GenericTaintChecker::isTaintedOrPointsToTainted(CE->getArg(i),
+ State, C)))
+ break;
+ }
+ break;
}
- return 0;
+
+ assert(ArgNum < CE->getNumArgs());
+ if ((IsTainted =
+ GenericTaintChecker::isTaintedOrPointsToTainted(CE->getArg(ArgNum),
+ State, C)))
+ break;
}
+ if (!IsTainted)
+ return State;
- SVal Val = State->getSVal(*AddrLoc);
- return Val.getAsSymbol();
+ // Mark the arguments which should be tainted after the function returns.
+ for (ArgVector::const_iterator I = DstArgs.begin(),
+ E = DstArgs.end(); I != E; ++I) {
+ unsigned ArgNum = *I;
+
+ // Should we mark all arguments as tainted?
+ if (ArgNum == InvalidArgIndex) {
+ // For all pointer and references that were passed in:
+ // If they are not pointing to const data, mark data as tainted.
+ // TODO: So far we are just going one level down; ideally we'd need to
+ // recurse here.
+ for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
+ const Expr *Arg = CE->getArg(i);
+ // Process pointer argument.
+ const Type *ArgTy = Arg->getType().getTypePtr();
+ QualType PType = ArgTy->getPointeeType();
+ if ((!PType.isNull() && !PType.isConstQualified())
+ || (ArgTy->isReferenceType() && !Arg->getType().isConstQualified()))
+ State = State->add<TaintArgsOnPostVisit>(i);
+ }
+ continue;
+ }
+
+ // Should mark the return value?
+ if (ArgNum == ReturnValueIndex) {
+ State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex);
+ continue;
+ }
+
+ // Mark the given argument.
+ assert(ArgNum < CE->getNumArgs());
+ State = State->add<TaintArgsOnPostVisit>(ArgNum);
+ }
+
+ return State;
}
+
+// If argument 0 (file descriptor) is tainted, all arguments except for arg 0
+// and arg 1 should get taint.
const ProgramState *GenericTaintChecker::preFscanf(const CallExpr *CE,
CheckerContext &C) const {
assert(CE->getNumArgs() >= 2);
const ProgramState *State = C.getState();
// Check is the file descriptor is tainted.
- if (State->isTainted(CE->getArg(0)) || isStdin(CE->getArg(0), C))
- return State->set<TaintOnPreVisit>(PrevisitTaintArgs);
- return 0;
-}
-
-// If any other arguments are tainted, mark state as tainted on pre-visit.
-const ProgramState * GenericTaintChecker::preAnyArgs(const CallExpr *CE,
- CheckerContext &C) const {
- for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
- const ProgramState *State = C.getState();
- const Expr *Arg = CE->getArg(i);
- if (State->isTainted(Arg) || State->isTainted(getPointedToSymbol(C, Arg)))
- return State = State->set<TaintOnPreVisit>(PrevisitTaintRet);
+ if (State->isTainted(CE->getArg(0), C.getLocationContext()) ||
+ isStdin(CE->getArg(0), C)) {
+ // All arguments except for the first two should get taint.
+ for (unsigned int i = 2; i < CE->getNumArgs(); ++i)
+ State = State->add<TaintArgsOnPostVisit>(i);
+ return State;
}
+
return 0;
}
-const ProgramState *GenericTaintChecker::postDefault(const CallExpr *CE,
- CheckerContext &C) const {
- const ProgramState *State = C.getState();
- // Check if we know that the result needs to be tainted based on the
- // pre-visit analysis.
- if (State->get<TaintOnPreVisit>() == PrevisitTaintRet) {
- State = State->addTaint(CE);
- return State->set<TaintOnPreVisit>(PrevisitNone);
- }
+// If argument 0(protocol domain) is network, the return value should get taint.
+const ProgramState *GenericTaintChecker::postSocket(const CallExpr *CE,
+ CheckerContext &C) const {
+ assert(CE->getNumArgs() >= 3);
+ const ProgramState *State = C.getState();
- return 0;
+ SourceLocation DomLoc = CE->getArg(0)->getExprLoc();
+ StringRef DomName = C.getMacroNameOrSpelling(DomLoc);
+ // White list the internal communication protocols.
+ if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") ||
+ DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36"))
+ return State;
+ State = State->addTaint(CE, C.getLocationContext());
+ return State;
}
const ProgramState *GenericTaintChecker::postScanf(const CallExpr *CE,
CheckerContext &C) const {
const ProgramState *State = C.getState();
assert(CE->getNumArgs() >= 2);
- SVal x = State->getSVal(CE->getArg(1));
+ SVal x = State->getSVal(CE->getArg(1), C.getLocationContext());
// All arguments except for the very first one should get taint.
for (unsigned int i = 1; i < CE->getNumArgs(); ++i) {
// The arguments are pointer arguments. The data they are pointing at is
@@ -233,42 +539,15 @@
return State;
}
-/// If argument 0 (file descriptor) is tainted, all arguments except for arg 0
-/// and arg 1 should get taint.
-const ProgramState *GenericTaintChecker::postFscanf(const CallExpr *CE,
- CheckerContext &C) const {
- const ProgramState *State = C.getState();
- assert(CE->getNumArgs() >= 2);
-
- // Fscanf is only tainted if the input file is tainted at pre visit, so
- // check for that first.
- if (State->get<TaintOnPreVisit>() == PrevisitNone)
- return 0;
-
- // Reset the taint state.
- State = State->set<TaintOnPreVisit>(PrevisitNone);
-
- // All arguments except for the first two should get taint.
- for (unsigned int i = 2; i < CE->getNumArgs(); ++i) {
- // The arguments are pointer arguments. The data they are pointing at is
- // tainted after the call.
- const Expr* Arg = CE->getArg(i);
- SymbolRef Sym = getPointedToSymbol(C, Arg);
- if (Sym)
- State = State->addTaint(Sym);
- }
- return State;
-}
-
const ProgramState *GenericTaintChecker::postRetTaint(const CallExpr *CE,
CheckerContext &C) const {
- return C.getState()->addTaint(CE);
+ return C.getState()->addTaint(CE, C.getLocationContext());
}
bool GenericTaintChecker::isStdin(const Expr *E,
CheckerContext &C) const {
const ProgramState *State = C.getState();
- SVal Val = State->getSVal(E);
+ SVal Val = State->getSVal(E, C.getLocationContext());
// stdin is a pointer, so it would be a region.
const MemRegion *MemReg = Val.getAsRegion();
@@ -299,6 +578,136 @@
return false;
}
+static bool getPrintfFormatArgumentNum(const CallExpr *CE,
+ const CheckerContext &C,
+ unsigned int &ArgNum) {
+ // Find if the function contains a format string argument.
+ // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf,
+ // vsnprintf, syslog, custom annotated functions.
+ const FunctionDecl *FDecl = C.getCalleeDecl(CE);
+ if (!FDecl)
+ return false;
+ for (specific_attr_iterator<FormatAttr>
+ i = FDecl->specific_attr_begin<FormatAttr>(),
+ e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
+
+ const FormatAttr *Format = *i;
+ ArgNum = Format->getFormatIdx() - 1;
+ if ((Format->getType() == "printf") && CE->getNumArgs() > ArgNum)
+ return true;
+ }
+
+ // Or if a function is named setproctitle (this is a heuristic).
+ if (C.getCalleeName(CE).find("setproctitle") != StringRef::npos) {
+ ArgNum = 0;
+ return true;
+ }
+
+ return false;
+}
+
+bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
+ const char Msg[],
+ CheckerContext &C) const {
+ assert(E);
+
+ // Check for taint.
+ const ProgramState *State = C.getState();
+ if (!State->isTainted(getPointedToSymbol(C, E)) &&
+ !State->isTainted(E, C.getLocationContext()))
+ return false;
+
+ // Generate diagnostic.
+ if (ExplodedNode *N = C.addTransition()) {
+ initBugType();
+ BugReport *report = new BugReport(*BT, Msg, N);
+ report->addRange(E->getSourceRange());
+ C.EmitReport(report);
+ return true;
+ }
+ return false;
+}
+
+bool GenericTaintChecker::checkUncontrolledFormatString(const CallExpr *CE,
+ CheckerContext &C) const{
+ // Check if the function contains a format string argument.
+ unsigned int ArgNum = 0;
+ if (!getPrintfFormatArgumentNum(CE, C, ArgNum))
+ return false;
+
+ // If either the format string content or the pointer itself are tainted, warn.
+ if (generateReportIfTainted(CE->getArg(ArgNum),
+ MsgUncontrolledFormatString, C))
+ return true;
+ return false;
+}
+
+bool GenericTaintChecker::checkSystemCall(const CallExpr *CE,
+ StringRef Name,
+ CheckerContext &C) const {
+ unsigned ArgNum = llvm::StringSwitch<unsigned>(Name)
+ .Case("system", 0)
+ .Case("popen", 0)
+ .Case("execl", 0)
+ .Case("execle", 0)
+ .Case("execlp", 0)
+ .Case("execv", 0)
+ .Case("execvp", 0)
+ .Case("execvP", 0)
+ .Default(UINT_MAX);
+
+ if (ArgNum == UINT_MAX)
+ return false;
+
+ if (generateReportIfTainted(CE->getArg(ArgNum),
+ MsgSanitizeSystemArgs, C))
+ return true;
+
+ return false;
+}
+
+// TODO: Should this check be a part of the CString checker?
+// If yes, should taint be a global setting?
+bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
+ const FunctionDecl *FDecl,
+ CheckerContext &C) const {
+ // If the function has a buffer size argument, set ArgNum.
+ unsigned ArgNum = InvalidArgIndex;
+ unsigned BId = 0;
+ if ( (BId = FDecl->getMemoryFunctionKind()) )
+ switch(BId) {
+ case Builtin::BImemcpy:
+ case Builtin::BImemmove:
+ case Builtin::BIstrncpy:
+ ArgNum = 2;
+ break;
+ case Builtin::BIstrndup:
+ ArgNum = 1;
+ break;
+ default:
+ break;
+ };
+
+ if (ArgNum == InvalidArgIndex) {
+ if (C.isCLibraryFunction(FDecl, "malloc") ||
+ C.isCLibraryFunction(FDecl, "calloc") ||
+ C.isCLibraryFunction(FDecl, "alloca"))
+ ArgNum = 0;
+ else if (C.isCLibraryFunction(FDecl, "memccpy"))
+ ArgNum = 3;
+ else if (C.isCLibraryFunction(FDecl, "realloc"))
+ ArgNum = 1;
+ else if (C.isCLibraryFunction(FDecl, "bcopy"))
+ ArgNum = 2;
+ }
+
+ if (ArgNum != InvalidArgIndex &&
+ generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C))
+ return true;
+
+ return false;
+}
+
void ento::registerGenericTaintChecker(CheckerManager &mgr) {
mgr.registerChecker<GenericTaintChecker>();
}
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp Fri Jan 20 10:14:22 2012
@@ -142,9 +142,9 @@
}
const ProgramState *state = C.getState();
-
- SVal LHSVal = state->getSVal(LHS);
- SVal RHSVal = state->getSVal(RHS);
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal LHSVal = state->getSVal(LHS, LCtx);
+ SVal RHSVal = state->getSVal(RHS, LCtx);
// If either value is unknown, we can't be 100% sure of all paths.
if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) {
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp Fri Jan 20 10:14:22 2012
@@ -254,7 +254,7 @@
lexp = M->GetTemporaryExpr();
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(lexp))
lexp = ICE->getSubExpr();
- SVal sv = state->getSVal(lexp);
+ SVal sv = state->getSVal(lexp, LC);
const MemRegion *MR = sv.getAsRegion();
if (!MR)
return state;
@@ -574,7 +574,7 @@
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase());
if (!DRE || getTemplateKind(DRE->getType()) != VectorKind)
return;
- SVal tsv = C.getState()->getSVal(DRE);
+ SVal tsv = C.getState()->getSVal(DRE, C.getLocationContext());
// Get the MemRegion associated with the container instance.
const MemRegion *MR = tsv.getAsRegion();
if (!MR)
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp Fri Jan 20 10:14:22 2012
@@ -220,11 +220,11 @@
static SymbolRef getAsPointeeSymbol(const Expr *Expr,
CheckerContext &C) {
const ProgramState *State = C.getState();
- SVal ArgV = State->getSVal(Expr);
+ SVal ArgV = State->getSVal(Expr, C.getLocationContext());
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) {
StoreManager& SM = C.getStoreManager();
- const MemRegion *V = SM.Retrieve(State->getStore(), *X).getAsRegion();
+ const MemRegion *V = SM.getBinding(State->getStore(), *X).getAsRegion();
if (V)
return getSymbolForRegion(C, V);
}
@@ -325,7 +325,7 @@
// Check the argument to the deallocator.
const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
- SVal ArgSVal = State->getSVal(ArgExpr);
+ SVal ArgSVal = State->getSVal(ArgExpr, C.getLocationContext());
// Undef is reported by another checker.
if (ArgSVal.isUndef())
@@ -462,7 +462,8 @@
// allocated value symbol, since our diagnostics depend on the value
// returned by the call. Ex: Data should only be freed if noErr was
// returned during allocation.)
- SymbolRef RetStatusSymbol = State->getSVal(CE).getAsSymbol();
+ SymbolRef RetStatusSymbol =
+ State->getSVal(CE, C.getLocationContext()).getAsSymbol();
C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol);
// Track the allocated value in the checker state.
@@ -481,7 +482,8 @@
// Check if the value is escaping through the return.
const ProgramState *state = C.getState();
- const MemRegion *V = state->getSVal(retExpr).getAsRegion();
+ const MemRegion *V =
+ state->getSVal(retExpr, C.getLocationContext()).getAsRegion();
if (!V)
return;
state = state->remove<AllocatedData>(getSymbolForRegion(C, V));
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp Fri Jan 20 10:14:22 2012
@@ -57,7 +57,8 @@
// Check if the first argument is stack allocated. If so, issue a warning
// because that's likely to be bad news.
const ProgramState *state = C.getState();
- const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+ const MemRegion *R =
+ state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion();
if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
return;
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Fri Jan 20 10:14:22 2012
@@ -64,8 +64,14 @@
class RegionState {};
-class MallocChecker : public Checker<eval::Call, check::DeadSymbols, check::EndPath, check::PreStmt<ReturnStmt>, check::Location,
- check::Bind, eval::Assume> {
+class MallocChecker : public Checker<eval::Call,
+ check::DeadSymbols,
+ check::EndPath,
+ check::PreStmt<ReturnStmt>,
+ check::Location,
+ check::Bind,
+ eval::Assume>
+{
mutable llvm::OwningPtr<BuiltinBug> BT_DoubleFree;
mutable llvm::OwningPtr<BuiltinBug> BT_Leak;
mutable llvm::OwningPtr<BuiltinBug> BT_UseFree;
@@ -94,7 +100,9 @@
static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
const Expr *SizeEx, SVal Init,
const ProgramState *state) {
- return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state);
+ return MallocMemAux(C, CE,
+ state->getSVal(SizeEx, C.getLocationContext()),
+ Init, state);
}
static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
SVal SizeEx, SVal Init,
@@ -104,7 +112,8 @@
void FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att) const;
const ProgramState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const ProgramState *state, unsigned Num, bool Hold) const;
+ const ProgramState *state, unsigned Num,
+ bool Hold) const;
void ReallocMem(CheckerContext &C, const CallExpr *CE) const;
static void CallocMem(CheckerContext &C, const CallExpr *CE);
@@ -182,8 +191,6 @@
rv = true;
break;
}
- default:
- break;
}
}
}
@@ -221,8 +228,9 @@
SValBuilder &svalBuilder = C.getSValBuilder();
// Set the return value.
- SVal retVal = svalBuilder.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
- state = state->BindExpr(CE, retVal);
+ SVal retVal = svalBuilder.getConjuredSymbolVal(NULL, CE,
+ CE->getType(), Count);
+ state = state->BindExpr(CE, C.getLocationContext(), retVal);
// Fill the region with the initialization value.
state = state->bindDefault(retVal, Init);
@@ -258,18 +266,21 @@
for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
I != E; ++I) {
- const ProgramState *state = FreeMemAux(C, CE, C.getState(), *I,
- Att->getOwnKind() == OwnershipAttr::Holds);
+ const ProgramState *state =
+ FreeMemAux(C, CE, C.getState(), *I,
+ Att->getOwnKind() == OwnershipAttr::Holds);
if (state)
C.addTransition(state);
}
}
-const ProgramState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const ProgramState *state, unsigned Num,
- bool Hold) const {
+const ProgramState *MallocChecker::FreeMemAux(CheckerContext &C,
+ const CallExpr *CE,
+ const ProgramState *state,
+ unsigned Num,
+ bool Hold) const {
const Expr *ArgExpr = CE->getArg(Num);
- SVal ArgVal = state->getSVal(ArgExpr);
+ SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext());
DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(ArgVal);
@@ -396,8 +407,7 @@
default: {
const MemSpaceRegion *MS = MR->getMemorySpace();
- switch (MS->getKind()) {
- case MemRegion::StackLocalsSpaceRegionKind: {
+ if (isa<StackLocalsSpaceRegion>(MS)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -411,7 +421,8 @@
os << "the address of a local stack variable";
return true;
}
- case MemRegion::StackArgumentsSpaceRegionKind: {
+
+ if (isa<StackArgumentsSpaceRegion>(MS)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -425,8 +436,8 @@
os << "the address of a parameter";
return true;
}
- case MemRegion::NonStaticGlobalSpaceRegionKind:
- case MemRegion::StaticGlobalSpaceRegionKind: {
+
+ if (isa<GlobalsSpaceRegion>(MS)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -443,9 +454,8 @@
os << "the address of a global variable";
return true;
}
- default:
- return false;
- }
+
+ return false;
}
}
}
@@ -491,8 +501,9 @@
void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
const Expr *arg0Expr = CE->getArg(0);
+ const LocationContext *LCtx = C.getLocationContext();
DefinedOrUnknownSVal arg0Val
- = cast<DefinedOrUnknownSVal>(state->getSVal(arg0Expr));
+ = cast<DefinedOrUnknownSVal>(state->getSVal(arg0Expr, LCtx));
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -506,7 +517,7 @@
// Get the value of the size argument.
DefinedOrUnknownSVal Arg1Val =
- cast<DefinedOrUnknownSVal>(state->getSVal(Arg1));
+ cast<DefinedOrUnknownSVal>(state->getSVal(Arg1, LCtx));
// Compare the size argument to 0.
DefinedOrUnknownSVal SizeZero =
@@ -532,14 +543,17 @@
if (const ProgramState *stateNotEqual = state->assume(PtrEQ, false)) {
// If the size is 0, free the memory.
- if (const ProgramState *stateSizeZero = stateNotEqual->assume(SizeZero, true))
+ if (const ProgramState *stateSizeZero =
+ stateNotEqual->assume(SizeZero, true))
if (const ProgramState *stateFree =
FreeMemAux(C, CE, stateSizeZero, 0, false)) {
// Bind the return value to NULL because it is now free.
- C.addTransition(stateFree->BindExpr(CE, svalBuilder.makeNull(), true));
+ C.addTransition(stateFree->BindExpr(CE, LCtx,
+ svalBuilder.makeNull(), true));
}
- if (const ProgramState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false))
+ if (const ProgramState *stateSizeNotZero =
+ stateNotEqual->assume(SizeZero,false))
if (const ProgramState *stateFree = FreeMemAux(C, CE, stateSizeNotZero,
0, false)) {
// FIXME: We should copy the content of the original buffer.
@@ -553,9 +567,9 @@
void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
const ProgramState *state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder();
-
- SVal count = state->getSVal(CE->getArg(0));
- SVal elementSize = state->getSVal(CE->getArg(1));
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal count = state->getSVal(CE->getArg(0), LCtx);
+ SVal elementSize = state->getSVal(CE->getArg(1), LCtx);
SVal TotalSize = svalBuilder.evalBinOp(state, BO_Mul, count, elementSize,
svalBuilder.getContext().getSizeType());
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
@@ -626,7 +640,7 @@
const ProgramState *state = C.getState();
- SymbolRef Sym = state->getSVal(retExpr).getAsSymbol();
+ SymbolRef Sym = state->getSVal(retExpr, C.getLocationContext()).getAsSymbol();
if (!Sym)
return;
@@ -641,8 +655,9 @@
C.addTransition(state);
}
-const ProgramState *MallocChecker::evalAssume(const ProgramState *state, SVal Cond,
- bool Assumption) const {
+const ProgramState *MallocChecker::evalAssume(const ProgramState *state,
+ SVal Cond,
+ bool Assumption) const {
// If a symblic region is assumed to NULL, set its state to AllocateFailed.
// FIXME: should also check symbols assumed to non-null.
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp Fri Jan 20 10:14:22 2012
@@ -42,7 +42,7 @@
bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
if (!BuildSinks) {
- SVal L = state->getSVal(Callee);
+ SVal L = state->getSVal(Callee, C.getLocationContext());
const FunctionDecl *FD = L.getAsFunctionDecl();
if (!FD)
return;
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp Fri Jan 20 10:14:22 2012
@@ -36,9 +36,10 @@
}
static StringRef getCalleeName(const ProgramState *State,
- const CallExpr *CE) {
+ const CallExpr *CE,
+ const LocationContext *LCtx) {
const Expr *Callee = CE->getCallee();
- SVal L = State->getSVal(Callee);
+ SVal L = State->getSVal(Callee, LCtx);
const FunctionDecl *funDecl = L.getAsFunctionDecl();
if (!funDecl)
return StringRef();
@@ -52,7 +53,8 @@
ExprEngine &Eng,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) const {
- StringRef FName = getCalleeName(Pred->getState(), CE);
+ StringRef FName = getCalleeName(Pred->getState(),
+ CE, Pred->getLocationContext());
if (FName.empty())
return false;
@@ -103,8 +105,9 @@
// Load 'theValue'.
const ProgramState *state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
ExplodedNodeSet Tmp;
- SVal location = state->getSVal(theValueExpr);
+ SVal location = state->getSVal(theValueExpr, LCtx);
// Here we should use the value type of the region as the load type, because
// we are simulating the semantics of the function, not the semantics of
// passing argument. So the type of theValue expr is not we are loading.
@@ -135,9 +138,9 @@
// Use direct bindings from the environment since we are forcing a load
// from a location that the Environment would typically not be used
// to bind a value.
- SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, true);
+ SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, LCtx, true);
- SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
+ SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr, LCtx);
// FIXME: Issue an error.
if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
@@ -161,7 +164,7 @@
if (stateEqual) {
// Perform the store.
ExplodedNodeSet TmpStore;
- SVal val = stateEqual->getSVal(newValueExpr);
+ SVal val = stateEqual->getSVal(newValueExpr, LCtx);
// Handle implicit value casts.
if (const TypedValueRegion *R =
@@ -189,7 +192,8 @@
QualType T = CE->getType();
if (!T->isVoidType())
Res = Eng.getSValBuilder().makeTruthVal(true, T);
- B.generateNode(CE, predNew, stateNew->BindExpr(CE, Res), false, this);
+ B.generateNode(CE, predNew, stateNew->BindExpr(CE, LCtx, Res),
+ false, this);
}
}
@@ -201,7 +205,8 @@
if (!T->isVoidType())
Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType());
StmtNodeBuilder B(N, Dst, Eng.getBuilderContext());
- B.generateNode(CE, N, stateNotEqual->BindExpr(CE, Res), false, this);
+ B.generateNode(CE, N, stateNotEqual->BindExpr(CE, LCtx, Res),
+ false, this);
}
}
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp Fri Jan 20 10:14:22 2012
@@ -39,7 +39,7 @@
const Expr *Ex = S->getSynchExpr();
const ProgramState *state = C.getState();
- SVal V = state->getSVal(Ex);
+ SVal V = state->getSVal(Ex, C.getLocationContext());
// Uninitialized value used for the mutex?
if (isa<UndefinedVal>(V)) {
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp Fri Jan 20 10:14:22 2012
@@ -156,7 +156,7 @@
/// points to and is an object that did not come from the result of calling
/// an initializer.
static bool isInvalidSelf(const Expr *E, CheckerContext &C) {
- SVal exprVal = C.getState()->getSVal(E);
+ SVal exprVal = C.getState()->getSVal(E, C.getLocationContext());
if (!hasSelfFlag(exprVal, SelfFlag_Self, C))
return false; // value did not come from 'self'.
if (hasSelfFlag(exprVal, SelfFlag_InitRes, C))
@@ -206,7 +206,7 @@
// value out when we return from this method.
state = state->set<CalledInit>(true);
- SVal V = state->getSVal(msg.getOriginExpr());
+ SVal V = state->getSVal(msg.getOriginExpr(), C.getLocationContext());
addSelfFlag(state, V, SelfFlag_InitRes, C);
return;
}
@@ -262,7 +262,7 @@
const ProgramState *state = C.getState();
for (CallExpr::const_arg_iterator
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
- SVal argV = state->getSVal(*I);
+ SVal argV = state->getSVal(*I, C.getLocationContext());
if (isSelfVar(argV, C)) {
unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
@@ -278,9 +278,10 @@
void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
const ProgramState *state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
for (CallExpr::const_arg_iterator
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
- SVal argV = state->getSVal(*I);
+ SVal argV = state->getSVal(*I, LCtx);
if (isSelfVar(argV, C)) {
SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
state = state->remove<PreCallSelfFlags>();
@@ -289,7 +290,7 @@
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
state = state->remove<PreCallSelfFlags>();
- addSelfFlag(state, state->getSVal(CE), prevFlags, C);
+ addSelfFlag(state, state->getSVal(CE, LCtx), prevFlags, C);
return;
}
}
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp Fri Jan 20 10:14:22 2012
@@ -37,8 +37,9 @@
return;
const ProgramState *state = C.getState();
- SVal LV = state->getSVal(B->getLHS());
- SVal RV = state->getSVal(B->getRHS());
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal LV = state->getSVal(B->getLHS(), LCtx);
+ SVal RV = state->getSVal(B->getRHS(), LCtx);
const MemRegion *LR = LV.getAsRegion();
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp Fri Jan 20 10:14:22 2012
@@ -40,8 +40,9 @@
return;
const ProgramState *state = C.getState();
- SVal LV = state->getSVal(B->getLHS());
- SVal RV = state->getSVal(B->getRHS());
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal LV = state->getSVal(B->getLHS(), LCtx);
+ SVal RV = state->getSVal(B->getRHS(), LCtx);
const MemRegion *LR = LV.getAsRegion();
const MemRegion *RR = RV.getAsRegion();
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp Fri Jan 20 10:14:22 2012
@@ -57,6 +57,7 @@
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
const ProgramState *state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
StringRef FName = C.getCalleeName(CE);
if (FName.empty())
return;
@@ -67,24 +68,28 @@
if (FName == "pthread_mutex_lock" ||
FName == "pthread_rwlock_rdlock" ||
FName == "pthread_rwlock_wrlock")
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false, PthreadSemantics);
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
+ false, PthreadSemantics);
else if (FName == "lck_mtx_lock" ||
FName == "lck_rw_lock_exclusive" ||
FName == "lck_rw_lock_shared")
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false, XNUSemantics);
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
+ false, XNUSemantics);
else if (FName == "pthread_mutex_trylock" ||
FName == "pthread_rwlock_tryrdlock" ||
FName == "pthread_rwlock_tryrwlock")
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true, PthreadSemantics);
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
+ true, PthreadSemantics);
else if (FName == "lck_mtx_try_lock" ||
FName == "lck_rw_try_lock_exclusive" ||
FName == "lck_rw_try_lock_shared")
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true, XNUSemantics);
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
+ true, XNUSemantics);
else if (FName == "pthread_mutex_unlock" ||
FName == "pthread_rwlock_unlock" ||
FName == "lck_mtx_unlock" ||
FName == "lck_rw_done")
- ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
+ ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
}
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
@@ -97,7 +102,7 @@
const ProgramState *state = C.getState();
- SVal X = state->getSVal(CE);
+ SVal X = state->getSVal(CE, C.getLocationContext());
if (X.isUnknownOrUndef())
return;
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Fri Jan 20 10:14:22 2012
@@ -358,15 +358,15 @@
/// DefaultArgEffect - The default ArgEffect to apply to arguments that
/// do not have an entry in Args.
- ArgEffect DefaultArgEffect;
+ ArgEffect DefaultArgEffect;
/// Receiver - If this summary applies to an Objective-C message expression,
/// this is the effect applied to the state of the receiver.
- ArgEffect Receiver;
+ ArgEffect Receiver;
/// Ret - The effect on the return value. Used to indicate if the
/// function/method call returns a new tracked symbol.
- RetEffect Ret;
+ RetEffect Ret;
public:
RetainSummary(ArgEffects A, RetEffect R, ArgEffect defaultEff,
@@ -436,7 +436,7 @@
ObjCSummaryKey(Selector s)
: II(0), S(s) {}
- IdentifierInfo* getIdentifier() const { return II; }
+ IdentifierInfo *getIdentifier() const { return II; }
Selector getSelector() const { return S; }
};
}
@@ -516,7 +516,7 @@
return Summ;
}
- const RetainSummary * find(IdentifierInfo* II, Selector S) {
+ const RetainSummary *find(IdentifierInfo* II, Selector S) {
// FIXME: Class method lookup. Right now we dont' have a good way
// of going between IdentifierInfo* and the class hierarchy.
MapTy::iterator I = M.find(ObjCSummaryKey(II, S));
@@ -584,7 +584,7 @@
ArgEffects::Factory AF;
/// ScratchArgs - A holding buffer for construct ArgEffects.
- ArgEffects ScratchArgs;
+ ArgEffects ScratchArgs;
/// ObjCAllocRetE - Default return effect for methods returning Objective-C
/// objects.
@@ -614,18 +614,18 @@
return &DefaultSummary;
}
- const RetainSummary * getUnarySummary(const FunctionType* FT,
+ const RetainSummary *getUnarySummary(const FunctionType* FT,
UnaryFuncKind func);
- const RetainSummary * getCFSummaryCreateRule(const FunctionDecl *FD);
- const RetainSummary * getCFSummaryGetRule(const FunctionDecl *FD);
- const RetainSummary * getCFCreateGetRuleSummary(const FunctionDecl *FD);
+ const RetainSummary *getCFSummaryCreateRule(const FunctionDecl *FD);
+ const RetainSummary *getCFSummaryGetRule(const FunctionDecl *FD);
+ const RetainSummary *getCFCreateGetRuleSummary(const FunctionDecl *FD);
- const RetainSummary * getPersistentSummary(ArgEffects AE, RetEffect RetEff,
+ const RetainSummary *getPersistentSummary(ArgEffects AE, RetEffect RetEff,
ArgEffect ReceiverEff = DoNothing,
ArgEffect DefaultEff = MayEscape);
- const RetainSummary * getPersistentSummary(RetEffect RE,
+ const RetainSummary *getPersistentSummary(RetEffect RE,
ArgEffect ReceiverEff = DoNothing,
ArgEffect DefaultEff = MayEscape) {
return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff);
@@ -729,19 +729,19 @@
InitializeMethodSummaries();
}
- const RetainSummary * getSummary(const FunctionDecl *FD);
+ const RetainSummary *getSummary(const FunctionDecl *FD);
const RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
const ProgramState *state,
const LocationContext *LC);
- const RetainSummary * getInstanceMethodSummary(const ObjCMessage &msg,
+ const RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
const ObjCInterfaceDecl *ID) {
return getInstanceMethodSummary(msg.getSelector(), 0,
ID, msg.getMethodDecl(), msg.getType(Ctx));
}
- const RetainSummary * getInstanceMethodSummary(Selector S,
+ const RetainSummary *getInstanceMethodSummary(Selector S,
IdentifierInfo *ClsName,
const ObjCInterfaceDecl *ID,
const ObjCMethodDecl *MD,
@@ -779,7 +779,7 @@
return getClassMethodSummary(S, ClsName, ID, MD, ResultTy);
}
- const RetainSummary * getCommonMethodSummary(const ObjCMethodDecl *MD,
+ const RetainSummary *getCommonMethodSummary(const ObjCMethodDecl *MD,
Selector S, QualType RetTy);
void updateSummaryFromAnnotations(const RetainSummary *&Summ,
@@ -1099,7 +1099,6 @@
case cfretain: Effect = IncRef; break;
case cfrelease: Effect = DecRef; break;
case cfmakecollectable: Effect = MakeCollectable; break;
- default: llvm_unreachable("Not a supported unary function.");
}
ScratchArgs = AF.add(ScratchArgs, 0, Effect);
@@ -1312,7 +1311,7 @@
SVal receiverV;
if (Receiver) {
- receiverV = state->getSValAsScalarOrLoc(Receiver);
+ receiverV = state->getSValAsScalarOrLoc(Receiver, LC);
// FIXME: Eventually replace the use of state->get<RefBindings> with
// a generic API for reasoning about the Objective-C types of symbolic
@@ -1841,6 +1840,7 @@
// Check if the type state has changed.
const ProgramState *PrevSt = PrevN->getState();
const ProgramState *CurrSt = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
const RefVal* CurrT = CurrSt->get<RefBindings>(Sym);
if (!CurrT) return NULL;
@@ -1860,7 +1860,7 @@
if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
// Get the name of the callee (if it is available).
- SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee());
+ SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
if (const FunctionDecl *FD = X.getAsFunctionDecl())
os << "Call to function '" << *FD << '\'';
else
@@ -1920,7 +1920,7 @@
// Retrieve the value of the argument. Is it the symbol
// we are interested in?
- if (CurrSt->getSValAsScalarOrLoc(*AI).getAsLocSymbol() != Sym)
+ if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
continue;
// We have an argument. Get the effect!
@@ -1929,7 +1929,8 @@
}
else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
if (const Expr *receiver = ME->getInstanceReceiver())
- if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) {
+ if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
+ .getAsLocSymbol() == Sym) {
// The symbol we are tracking is the receiver.
AEffects.push_back(Summ->getReceiverEffect());
}
@@ -1957,7 +1958,8 @@
if (contains(AEffects, MakeCollectable)) {
// Get the name of the function.
const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
- SVal X = CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee());
+ SVal X =
+ CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee(), LCtx);
const FunctionDecl *FD = X.getAsFunctionDecl();
if (GCEnabled) {
@@ -2069,7 +2071,7 @@
for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
I!=E; ++I)
if (const Expr *Exp = dyn_cast_or_null<Expr>(*I))
- if (CurrSt->getSValAsScalarOrLoc(Exp).getAsLocSymbol() == Sym) {
+ if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
P->addRange(Exp->getSourceRange());
break;
}
@@ -2105,7 +2107,7 @@
}
operator bool() { return First && Binding; }
- const MemRegion* getRegion() { return Binding; }
+ const MemRegion *getRegion() { return Binding; }
};
}
@@ -2201,10 +2203,10 @@
}
else {
const FunctionDecl *FD = cast<FunctionDecl>(D);
- os << " is return from a function whose name ('"
+ os << " is returned from a function whose name ('"
<< FD->getNameAsString()
<< "') does not contain 'Copy' or 'Create'. This violates the naming"
- " convention rules given the Memory Management Guide for Core"
+ " convention rules given in the Memory Management Guide for Core"
" Foundation";
}
}
@@ -2505,7 +2507,8 @@
const ProgramState *state = C.getState();
const BlockDataRegion *R =
- cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+ cast<BlockDataRegion>(state->getSVal(BE,
+ C.getLocationContext()).getAsRegion());
BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
E = R->referenced_vars_end();
@@ -2555,7 +2558,7 @@
}
const ProgramState *state = C.getState();
- SymbolRef Sym = state->getSVal(CE).getAsLocSymbol();
+ SymbolRef Sym = state->getSVal(CE, C.getLocationContext()).getAsLocSymbol();
if (!Sym)
return;
const RefVal* T = state->get<RefBindings>(Sym);
@@ -2579,7 +2582,7 @@
// Get the callee.
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
+ SVal L = state->getSVal(Callee, C.getLocationContext());
RetainSummaryManager &Summaries = getSummaryManager(C);
const RetainSummary *Summ = 0;
@@ -2599,7 +2602,7 @@
if (!Summ)
Summ = Summaries.getDefaultSummary();
- checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
+ checkSummary(*Summ, CallOrObjCMessage(CE, state, C.getLocationContext()), C);
}
void RetainCountChecker::checkPostStmt(const CXXConstructExpr *CE,
@@ -2616,7 +2619,7 @@
return;
const ProgramState *state = C.getState();
- checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
+ checkSummary(*Summ, CallOrObjCMessage(CE, state, C.getLocationContext()), C);
}
void RetainCountChecker::checkPostObjCMessage(const ObjCMessage &Msg,
@@ -2637,7 +2640,7 @@
if (!Summ)
return;
- checkSummary(*Summ, CallOrObjCMessage(Msg, state), C);
+ checkSummary(*Summ, CallOrObjCMessage(Msg, state, C.getLocationContext()), C);
}
/// GetReturnType - Used to get the return type of a message expression or
@@ -2729,7 +2732,7 @@
switch (RE.getKind()) {
default:
- llvm_unreachable("Unhandled RetEffect."); break;
+ llvm_unreachable("Unhandled RetEffect.");
case RetEffect::NoRet:
// No work necessary.
@@ -2737,7 +2740,8 @@
case RetEffect::OwnedAllocatedSymbol:
case RetEffect::OwnedSymbol: {
- SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr()).getAsSymbol();
+ SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr(),
+ C.getLocationContext()).getAsSymbol();
if (!Sym)
break;
@@ -2764,7 +2768,7 @@
case RetEffect::ARCNotOwnedSymbol:
case RetEffect::NotOwnedSymbol: {
const Expr *Ex = CallOrMsg.getOriginExpr();
- SymbolRef Sym = state->getSVal(Ex).getAsSymbol();
+ SymbolRef Sym = state->getSVal(Ex, C.getLocationContext()).getAsSymbol();
if (!Sym)
break;
@@ -2829,7 +2833,6 @@
case IncRefMsg:
case MakeCollectable:
llvm_unreachable("DecRefMsg/IncRefMsg/MakeCollectable already converted");
- return state;
case Dealloc:
// Any use of -dealloc in GC is *bad*.
@@ -2842,7 +2845,6 @@
switch (V.getKind()) {
default:
llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
- break;
case RefVal::Owned:
// The object immediately transitions to the released state.
V = V ^ RefVal::Released;
@@ -2886,7 +2888,6 @@
switch (V.getKind()) {
default:
llvm_unreachable("Invalid RefVal state for a retain.");
- break;
case RefVal::Owned:
case RefVal::NotOwned:
V = V + 1;
@@ -2908,7 +2909,6 @@
default:
// case 'RefVal::Released' handled above.
llvm_unreachable("Invalid RefVal state for a release.");
- break;
case RefVal::Owned:
assert(V.getCount() > 0);
@@ -2952,7 +2952,6 @@
switch (ErrorKind) {
default:
llvm_unreachable("Unhandled error.");
- return;
case RefVal::ErrorUseAfterRelease:
if (!useAfterRelease)
useAfterRelease.reset(new UseAfterRelease());
@@ -3030,14 +3029,15 @@
return false;
// Bind the return value.
- SVal RetVal = state->getSVal(CE->getArg(0));
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal RetVal = state->getSVal(CE->getArg(0), LCtx);
if (RetVal.isUnknown()) {
// If the receiver is unknown, conjure a return value.
SValBuilder &SVB = C.getSValBuilder();
unsigned Count = C.getCurrentBlockCount();
SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count);
}
- state = state->BindExpr(CE, RetVal, false);
+ state = state->BindExpr(CE, LCtx, RetVal, false);
// FIXME: This should not be necessary, but otherwise the argument seems to be
// considered alive during the next statement.
@@ -3072,7 +3072,8 @@
return;
const ProgramState *state = C.getState();
- SymbolRef Sym = state->getSValAsScalarOrLoc(RetE).getAsLocSymbol();
+ SymbolRef Sym =
+ state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol();
if (!Sym)
return;
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp Fri Jan 20 10:14:22 2012
@@ -39,7 +39,7 @@
if (!RetE)
return;
- SVal V = state->getSVal(RetE);
+ SVal V = state->getSVal(RetE, C.getLocationContext());
const MemRegion *R = V.getAsRegion();
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R);
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp Fri Jan 20 10:14:22 2012
@@ -38,7 +38,7 @@
if (!RetE)
return;
- if (!C.getState()->getSVal(RetE).isUndef())
+ if (!C.getState()->getSVal(RetE, C.getLocationContext()).isUndef())
return;
ExplodedNode *N = C.generateSink();
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp Fri Jan 20 10:14:22 2012
@@ -119,7 +119,7 @@
if (!RetE)
return;
- SVal V = C.getState()->getSVal(RetE);
+ SVal V = C.getState()->getSVal(RetE, C.getLocationContext());
const MemRegion *R = V.getAsRegion();
if (!R || !R->hasStackStorage())
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/StreamChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/StreamChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/StreamChecker.cpp Fri Jan 20 10:14:22 2012
@@ -223,7 +223,7 @@
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedSVal RetVal =
cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, Count));
- state = state->BindExpr(CE, RetVal);
+ state = state->BindExpr(CE, C.getLocationContext(), RetVal);
ConstraintManager &CM = C.getConstraintManager();
// Bifurcate the state into two: one with a valid FILE* pointer, the other
@@ -251,22 +251,25 @@
void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
+ if (!CheckNullStream(state->getSVal(CE->getArg(3), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
+ if (!CheckNullStream(state->getSVal(CE->getArg(3), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C)))
+ if (!(state = CheckNullStream(state->getSVal(CE->getArg(0),
+ C.getLocationContext()), state, C)))
return;
// Check the legality of the 'whence' argument of 'fseek'.
- SVal Whence = state->getSVal(CE->getArg(2));
+ SVal Whence = state->getSVal(CE->getArg(2), C.getLocationContext());
const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Whence);
if (!CI)
@@ -289,49 +292,57 @@
void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const {
const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
@@ -361,7 +372,8 @@
const ProgramState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
const ProgramState *state,
CheckerContext &C) const {
- SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol();
+ SymbolRef Sym =
+ state->getSVal(CE->getArg(0), C.getLocationContext()).getAsSymbol();
if (!Sym)
return state;
@@ -442,7 +454,7 @@
return;
const ProgramState *state = C.getState();
- SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
+ SymbolRef Sym = state->getSVal(RetE, C.getLocationContext()).getAsSymbol();
if (!Sym)
return;
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp Fri Jan 20 10:14:22 2012
@@ -47,7 +47,7 @@
if (!State)
return;
- if (State->isTainted(E)) {
+ if (State->isTainted(E, C.getLocationContext())) {
if (ExplodedNode *N = C.addTransition()) {
initBugType();
BugReport *report = new BugReport(*BT, "tainted",N);
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp Fri Jan 20 10:14:22 2012
@@ -28,8 +28,10 @@
struct FindUndefExpr {
const ProgramState *St;
+ const LocationContext *LCtx;
- FindUndefExpr(const ProgramState *S) : St(S) {}
+ FindUndefExpr(const ProgramState *S, const LocationContext *L)
+ : St(S), LCtx(L) {}
const Expr *FindExpr(const Expr *Ex) {
if (!MatchesCriteria(Ex))
@@ -45,7 +47,9 @@
return Ex;
}
- bool MatchesCriteria(const Expr *Ex) { return St->getSVal(Ex).isUndef(); }
+ bool MatchesCriteria(const Expr *Ex) {
+ return St->getSVal(Ex, LCtx).isUndef();
+ }
};
public:
@@ -56,7 +60,7 @@
void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
CheckerContext &Ctx) const {
- SVal X = Ctx.getState()->getSVal(Condition);
+ SVal X = Ctx.getState()->getSVal(Condition, Ctx.getLocationContext());
if (X.isUndef()) {
// Generate a sink node, which implicitly marks both outgoing branches as
// infeasible.
@@ -90,7 +94,7 @@
if (PS->getStmt() == Ex)
St = PrevN->getState();
- FindUndefExpr FindIt(St);
+ FindUndefExpr FindIt(St, Ctx.getLocationContext());
Ex = FindIt.FindExpr(Ex);
// Emit the bug report.
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp Fri Jan 20 10:14:22 2012
@@ -57,7 +57,8 @@
const ProgramState *state = C.getState();
const BlockDataRegion *R =
- cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+ cast<BlockDataRegion>(state->getSVal(BE,
+ C.getLocationContext()).getAsRegion());
BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
E = R->referenced_vars_end();
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp Fri Jan 20 10:14:22 2012
@@ -36,7 +36,8 @@
void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
CheckerContext &C) const {
const ProgramState *state = C.getState();
- if (state->getSVal(B).isUndef()) {
+ const LocationContext *LCtx = C.getLocationContext();
+ if (state->getSVal(B, LCtx).isUndef()) {
// Generate an error node.
ExplodedNode *N = C.generateSink();
if (!N)
@@ -50,11 +51,11 @@
const Expr *Ex = NULL;
bool isLeft = true;
- if (state->getSVal(B->getLHS()).isUndef()) {
+ if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
Ex = B->getLHS()->IgnoreParenCasts();
isLeft = true;
}
- else if (state->getSVal(B->getRHS()).isUndef()) {
+ else if (state->getSVal(B->getRHS(), LCtx).isUndef()) {
Ex = B->getRHS()->IgnoreParenCasts();
isLeft = false;
}
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp Fri Jan 20 10:14:22 2012
@@ -34,7 +34,7 @@
void
UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
CheckerContext &C) const {
- if (C.getState()->getSVal(A->getIdx()).isUndef()) {
+ if (C.getState()->getSVal(A->getIdx(), C.getLocationContext()).isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT)
BT.reset(new BuiltinBug("Array subscript is undefined"));
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp Fri Jan 20 10:14:22 2012
@@ -55,7 +55,7 @@
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
if (B->isCompoundAssignmentOp()) {
const ProgramState *state = C.getState();
- if (state->getSVal(B->getLHS()).isUndef()) {
+ if (state->getSVal(B->getLHS(), C.getLocationContext()).isUndef()) {
str = "The left expression of the compound assignment is an "
"uninitialized value. The computed value will also be garbage";
ex = B->getLHS();
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp Fri Jan 20 10:14:22 2012
@@ -36,10 +36,24 @@
void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
+ void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
+ void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
+ void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
+ void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &,
const CallExpr *) const;
+private:
+ bool ReportZeroByteAllocation(CheckerContext &C,
+ const ProgramState *falseState,
+ const Expr *arg,
+ const char *fn_name) const;
+ void BasicAllocationCheck(CheckerContext &C,
+ const CallExpr *CE,
+ const unsigned numArgs,
+ const unsigned sizeArg,
+ const char *fn) const;
};
} //end anonymous namespace
@@ -84,7 +98,7 @@
// Now check if oflags has O_CREAT set.
const Expr *oflagsEx = CE->getArg(1);
- const SVal V = state->getSVal(oflagsEx);
+ const SVal V = state->getSVal(oflagsEx, C.getLocationContext());
if (!isa<NonLoc>(V)) {
// The case where 'V' can be a location can only be due to a bad header,
// so in this case bail out.
@@ -142,7 +156,8 @@
// Check if the first argument is stack allocated. If so, issue a warning
// because that's likely to be bad news.
const ProgramState *state = C.getState();
- const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+ const MemRegion *R =
+ state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion();
if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
return;
@@ -170,60 +185,143 @@
}
//===----------------------------------------------------------------------===//
-// "malloc" with allocation size 0
+// "calloc", "malloc", "realloc", "alloca" and "valloc" with allocation size 0
//===----------------------------------------------------------------------===//
+// FIXME: Eventually these should be rolled into the MallocChecker, but right now
+// they're more basic and valuable for widespread use.
-// FIXME: Eventually this should be rolled into the MallocChecker, but this
-// check is more basic and is valuable for widespread use.
-void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
- const CallExpr *CE) const {
+// Returns true if we try to do a zero byte allocation, false otherwise.
+// Fills in trueState and falseState.
+static bool IsZeroByteAllocation(const ProgramState *state,
+ const SVal argVal,
+ const ProgramState **trueState,
+ const ProgramState **falseState) {
+ llvm::tie(*trueState, *falseState) =
+ state->assume(cast<DefinedSVal>(argVal));
+
+ return (*falseState && !*trueState);
+}
+
+// Generates an error report, indicating that the function whose name is given
+// will perform a zero byte allocation.
+// Returns false if an error occured, true otherwise.
+bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
+ const ProgramState *falseState,
+ const Expr *arg,
+ const char *fn_name) const {
+ ExplodedNode *N = C.generateSink(falseState);
+ if (!N)
+ return false;
+
+ LazyInitialize(BT_mallocZero,
+ "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
+
+ llvm::SmallString<256> S;
+ llvm::raw_svector_ostream os(S);
+ os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
+ BugReport *report = new BugReport(*BT_mallocZero, os.str(), N);
+
+ report->addRange(arg->getSourceRange());
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, arg));
+ C.EmitReport(report);
+
+ return true;
+}
- // Sanity check that malloc takes one argument.
- if (CE->getNumArgs() != 1)
+// Does a basic check for 0-sized allocations suitable for most of the below
+// functions (modulo "calloc")
+void UnixAPIChecker::BasicAllocationCheck(CheckerContext &C,
+ const CallExpr *CE,
+ const unsigned numArgs,
+ const unsigned sizeArg,
+ const char *fn) const {
+ // Sanity check for the correct number of arguments
+ if (CE->getNumArgs() != numArgs)
return;
// Check if the allocation size is 0.
const ProgramState *state = C.getState();
- SVal argVal = state->getSVal(CE->getArg(0));
+ const ProgramState *trueState = NULL, *falseState = NULL;
+ const Expr *arg = CE->getArg(sizeArg);
+ SVal argVal = state->getSVal(arg, C.getLocationContext());
if (argVal.isUnknownOrUndef())
return;
-
- const ProgramState *trueState, *falseState;
- llvm::tie(trueState, falseState) = state->assume(cast<DefinedSVal>(argVal));
-
+
// Is the value perfectly constrained to zero?
- if (falseState && !trueState) {
- ExplodedNode *N = C.generateSink(falseState);
- if (!N)
- return;
-
- // FIXME: Add reference to CERT advisory, and/or C99 standard in bug
- // output.
+ if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
+ (void) ReportZeroByteAllocation(C, falseState, arg, fn);
+ return;
+ }
+ // Assume the the value is non-zero going forward.
+ assert(trueState);
+ if (trueState != state)
+ C.addTransition(trueState);
+}
- LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");
-
- BugReport *report =
- new BugReport(*BT_mallocZero, "Call to 'malloc' has an allocation"
- " size of 0 bytes", N);
- report->addRange(CE->getArg(0)->getSourceRange());
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
- CE->getArg(0)));
- C.EmitReport(report);
+void UnixAPIChecker::CheckCallocZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ unsigned int nArgs = CE->getNumArgs();
+ if (nArgs != 2)
return;
+
+ const ProgramState *state = C.getState();
+ const ProgramState *trueState = NULL, *falseState = NULL;
+
+ unsigned int i;
+ for (i = 0; i < nArgs; i++) {
+ const Expr *arg = CE->getArg(i);
+ SVal argVal = state->getSVal(arg, C.getLocationContext());
+ if (argVal.isUnknownOrUndef()) {
+ if (i == 0)
+ continue;
+ else
+ return;
+ }
+
+ if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
+ if (ReportZeroByteAllocation(C, falseState, arg, "calloc"))
+ return;
+ else if (i == 0)
+ continue;
+ else
+ return;
+ }
}
+
// Assume the the value is non-zero going forward.
assert(trueState);
- if (trueState != state) {
+ if (trueState != state)
C.addTransition(trueState);
- }
}
-
+
+void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 1, 0, "malloc");
+}
+
+void UnixAPIChecker::CheckReallocZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 2, 1, "realloc");
+}
+
+void UnixAPIChecker::CheckAllocaZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 1, 0, "alloca");
+}
+
+void UnixAPIChecker::CheckVallocZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 1, 0, "valloc");
+}
+
+
//===----------------------------------------------------------------------===//
// Central dispatch function.
//===----------------------------------------------------------------------===//
-void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
+void UnixAPIChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
StringRef FName = C.getCalleeName(CE);
if (FName.empty())
return;
@@ -232,7 +330,11 @@
llvm::StringSwitch<SubChecker>(FName)
.Case("open", &UnixAPIChecker::CheckOpen)
.Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
+ .Case("calloc", &UnixAPIChecker::CheckCallocZero)
.Case("malloc", &UnixAPIChecker::CheckMallocZero)
+ .Case("realloc", &UnixAPIChecker::CheckReallocZero)
+ .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero)
+ .Case("valloc", &UnixAPIChecker::CheckVallocZero)
.Default(NULL);
if (SC)
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp Fri Jan 20 10:14:22 2012
@@ -50,7 +50,7 @@
// FIXME: Handle multi-dimensional VLAs.
const Expr *SE = VLA->getSizeExpr();
const ProgramState *state = C.getState();
- SVal sizeV = state->getSVal(SE);
+ SVal sizeV = state->getSVal(SE, C.getLocationContext());
if (sizeV.isUndef()) {
// Generate an error node.
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/AnalysisManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/AnalysisManager.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/AnalysisManager.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/AnalysisManager.cpp Fri Jan 20 10:14:22 2012
@@ -14,6 +14,8 @@
using namespace clang;
using namespace ento;
+void AnalysisManager::anchor() { }
+
AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
const LangOptions &lang,
PathDiagnosticConsumer *pd,
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/BugReporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/BugReporter.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/BugReporter.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/BugReporter.cpp Fri Jan 20 10:14:22 2012
@@ -34,6 +34,8 @@
BugReporterVisitor::~BugReporterVisitor() {}
+void BugReporterContext::anchor() {}
+
//===----------------------------------------------------------------------===//
// Helper routines for walking the ExplodedGraph and fetching statements.
//===----------------------------------------------------------------------===//
@@ -341,7 +343,7 @@
if (!DR)
continue;
- SVal Y = N->getState()->getSVal(DR);
+ SVal Y = N->getState()->getSVal(DR, N->getLocationContext());
if (X != Y)
continue;
@@ -1204,10 +1206,14 @@
void BugType::FlushReports(BugReporter &BR) {}
+void BuiltinBug::anchor() {}
+
//===----------------------------------------------------------------------===//
// Methods for BugReport and subclasses.
//===----------------------------------------------------------------------===//
+void BugReport::NodeResolver::anchor() {}
+
void BugReport::addVisitor(BugReporterVisitor* visitor) {
if (!visitor)
return;
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp Fri Jan 20 10:14:22 2012
@@ -339,7 +339,7 @@
}
}
- SVal V = state->getSValAsScalarOrLoc(S);
+ SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
// Uncomment this to find cases where we aren't properly getting the
// base value that was dereferenced.
@@ -389,7 +389,7 @@
if (!Receiver)
return 0;
const ProgramState *state = N->getState();
- const SVal &V = state->getSVal(Receiver);
+ const SVal &V = state->getSVal(Receiver, N->getLocationContext());
const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V);
if (!DV)
return 0;
@@ -428,7 +428,7 @@
StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
// What did we load?
- SVal V = state->getSVal(S);
+ SVal V = state->getSVal(S, N->getLocationContext());
if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) {
// Register a new visitor with the BugReport.
@@ -604,18 +604,26 @@
shouldInvert = !isVarLHS && isVarRHS;
}
+ BinaryOperator::Opcode Op = BExpr->getOpcode();
+
+ if (BinaryOperator::isAssignmentOp(Op)) {
+ // For assignment operators, all that we care about is that the LHS
+ // evaluates to "true" or "false".
+ return VisitConditionVariable(LhsString, BExpr->getLHS(), tookTrue,
+ BRC, LC);
+ }
+
+ // For non-assignment operations, we require that we can understand
+ // both the LHS and RHS.
if (LhsString.empty() || RhsString.empty())
return 0;
-
- // Should we invert the strings if the LHS is not a variable name?
+ // Should we invert the strings if the LHS is not a variable name?
llvm::SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
Out << "Assuming " << (shouldInvert ? RhsString : LhsString) << " is ";
// Do we need to invert the opcode?
- BinaryOperator::Opcode Op = BExpr->getOpcode();
-
if (shouldInvert)
switch (Op) {
default: break;
@@ -637,7 +645,7 @@
return 0;
}
- switch (BExpr->getOpcode()) {
+ switch (Op) {
case BO_EQ:
Out << "equal to ";
break;
@@ -654,6 +662,33 @@
PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC);
return new PathDiagnosticEventPiece(Loc, Out.str());
}
+
+PathDiagnosticPiece *
+ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
+ const Expr *CondVarExpr,
+ const bool tookTrue,
+ BugReporterContext &BRC,
+ const LocationContext *LC) {
+ llvm::SmallString<256> buf;
+ llvm::raw_svector_ostream Out(buf);
+ Out << "Assuming " << LhsString << " is ";
+
+ QualType Ty = CondVarExpr->getType();
+
+ if (Ty->isPointerType())
+ Out << (tookTrue ? "not null" : "null");
+ else if (Ty->isObjCObjectPointerType())
+ Out << (tookTrue ? "not nil" : "nil");
+ else if (Ty->isBooleanType())
+ Out << (tookTrue ? "true" : "false");
+ else if (Ty->isIntegerType())
+ Out << (tookTrue ? "non-zero" : "zero");
+ else
+ return 0;
+
+ PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LC);
+ return new PathDiagnosticEventPiece(Loc, Out.str());
+}
PathDiagnosticPiece *
ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/CMakeLists.txt?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/CMakeLists.txt (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/CMakeLists.txt Fri Jan 20 10:14:22 2012
@@ -36,6 +36,7 @@
SimpleConstraintManager.cpp
SimpleSValBuilder.cpp
Store.cpp
+ SubEngine.cpp
SymbolManager.cpp
TextPathDiagnostics.cpp
)
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/Checker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/Checker.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/Checker.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/Checker.cpp Fri Jan 20 10:14:22 2012
@@ -20,3 +20,11 @@
// FIXME: We want to return the package + name of the checker here.
return "A Checker";
}
+
+void Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck
+ >::anchor() { }
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/CheckerContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/CheckerContext.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/CheckerContext.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/CheckerContext.cpp Fri Jan 20 10:14:22 2012
@@ -13,22 +13,56 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Lex/Lexer.h"
+
using namespace clang;
using namespace ento;
const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const {
const ProgramState *State = getState();
const Expr *Callee = CE->getCallee();
- SVal L = State->getSVal(Callee);
+ SVal L = State->getSVal(Callee, Pred->getLocationContext());
return L.getAsFunctionDecl();
}
-StringRef CheckerContext::getCalleeName(const CallExpr *CE) const {
- const FunctionDecl *funDecl = getCalleeDecl(CE);
- if (!funDecl)
+StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const {
+ if (!FunDecl)
return StringRef();
- IdentifierInfo *funI = funDecl->getIdentifier();
+ IdentifierInfo *funI = FunDecl->getIdentifier();
if (!funI)
return StringRef();
return funI->getName();
}
+
+
+bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
+ StringRef Name){
+ // To avoid false positives (Ex: finding user defined functions with
+ // similar names), only perform fuzzy name matching when it's a builtin.
+ // Using a string compare is slow, we might want to switch on BuiltinID here.
+ unsigned BId = FD->getBuiltinID();
+ if (BId != 0) {
+ ASTContext &Context = getASTContext();
+ StringRef BName = Context.BuiltinInfo.GetName(BId);
+ if (StringRef(BName).find(Name) != StringRef::npos)
+ return true;
+ }
+
+ if (FD->isExternC() && FD->getIdentifier()->getName().equals(Name))
+ return true;
+
+ return false;
+}
+
+StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) {
+ if (!Loc.isMacroID()) {
+ SmallVector<char, 16> buf;
+ return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOptions());
+ } else {
+ return Lexer::getImmediateMacroName(Loc, getSourceManager(),
+ getLangOptions());
+ }
+ return StringRef();
+}
+
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/CoreEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/CoreEngine.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/CoreEngine.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/CoreEngine.cpp Fri Jan 20 10:14:22 2012
@@ -215,12 +215,11 @@
break;
case ProgramPoint::CallEnterKind:
- HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(),
- WU.getIndex(), Node);
+ SubEng.processCallEnter(cast<CallEnter>(Node->getLocation()), Node);
break;
case ProgramPoint::CallExitKind:
- HandleCallExit(cast<CallExit>(Node->getLocation()), Node);
+ SubEng.processCallExit(Node);
break;
default:
@@ -246,18 +245,6 @@
}
}
-void CoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
- unsigned Index, ExplodedNode *Pred) {
- CallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(),
- L.getCalleeContext(), Block, Index);
- SubEng.processCallEnter(Builder);
-}
-
-void CoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) {
- CallExitNodeBuilder Builder(*this, Pred);
- SubEng.processCallExit(Builder);
-}
-
void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
const CFGBlock *Blk = L.getDst();
@@ -537,6 +524,8 @@
}
+void NodeBuilder::anchor() { }
+
ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc,
const ProgramState *State,
ExplodedNode *FromN,
@@ -556,6 +545,8 @@
return N;
}
+void NodeBuilderWithSinks::anchor() { }
+
StmtNodeBuilder::~StmtNodeBuilder() {
if (EnclosingBldr)
for (ExplodedNodeSet::iterator I = Frontier.begin(),
@@ -563,6 +554,8 @@
EnclosingBldr->addNodes(*I);
}
+void BranchNodeBuilder::anchor() { }
+
ExplodedNode *BranchNodeBuilder::generateNode(const ProgramState *State,
bool branch,
ExplodedNode *NodePred) {
@@ -639,80 +632,3 @@
return Succ;
}
-
-void CallEnterNodeBuilder::generateNode(const ProgramState *state) {
- // Check if the callee is in the same translation unit.
- if (CalleeCtx->getTranslationUnit() !=
- Pred->getLocationContext()->getTranslationUnit()) {
- // Create a new engine. We must be careful that the new engine should not
- // reference data structures owned by the old engine.
-
- AnalysisManager &OldMgr = Eng.SubEng.getAnalysisManager();
-
- // Get the callee's translation unit.
- idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit();
-
- // Create a new AnalysisManager with components of the callee's
- // TranslationUnit.
- // The Diagnostic is actually shared when we create ASTUnits from AST files.
- AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), OldMgr);
-
- // Create the new engine.
- // FIXME: This cast isn't really safe.
- bool GCEnabled = static_cast<ExprEngine&>(Eng.SubEng).isObjCGCEnabled();
- ExprEngine NewEng(AMgr, GCEnabled);
-
- // Create the new LocationContext.
- AnalysisDeclContext *NewAnaCtx =
- AMgr.getAnalysisDeclContext(CalleeCtx->getDecl(),
- CalleeCtx->getTranslationUnit());
-
- const StackFrameContext *OldLocCtx = CalleeCtx;
- const StackFrameContext *NewLocCtx =
- NewAnaCtx->getStackFrame(OldLocCtx->getParent(),
- OldLocCtx->getCallSite(),
- OldLocCtx->getCallSiteBlock(),
- OldLocCtx->getIndex());
-
- // Now create an initial state for the new engine.
- const ProgramState *NewState =
- NewEng.getStateManager().MarshalState(state, NewLocCtx);
- ExplodedNodeSet ReturnNodes;
- NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(),
- NewState, ReturnNodes);
- return;
- }
-
- // Get the callee entry block.
- const CFGBlock *Entry = &(CalleeCtx->getCFG()->getEntry());
- assert(Entry->empty());
- assert(Entry->succ_size() == 1);
-
- // Get the solitary successor.
- const CFGBlock *SuccB = *(Entry->succ_begin());
-
- // Construct an edge representing the starting location in the callee.
- BlockEdge Loc(Entry, SuccB, CalleeCtx);
-
- bool isNew;
- ExplodedNode *Node = Eng.G->getNode(Loc, state, false, &isNew);
- Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
-
- if (isNew)
- Eng.WList->enqueue(Node);
-}
-
-void CallExitNodeBuilder::generateNode(const ProgramState *state) {
- // Get the callee's location context.
- const StackFrameContext *LocCtx
- = cast<StackFrameContext>(Pred->getLocationContext());
- // When exiting an implicit automatic obj dtor call, the callsite is the Stmt
- // that triggers the dtor.
- PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent());
- bool isNew;
- ExplodedNode *Node = Eng.G->getNode(Loc, state, false, &isNew);
- Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
- if (isNew)
- Eng.WList->enqueue(Node, LocCtx->getCallSiteBlock(),
- LocCtx->getIndex() + 1);
-}
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/Environment.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/Environment.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/Environment.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/Environment.cpp Fri Jan 20 10:14:22 2012
@@ -19,7 +19,7 @@
using namespace clang;
using namespace ento;
-SVal Environment::lookupExpr(const Stmt *E) const {
+SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
const SVal* X = ExprBindings.lookup(E);
if (X) {
SVal V = *X;
@@ -28,17 +28,21 @@
return UnknownVal();
}
-SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
- bool useOnlyDirectBindings) const {
+SVal Environment::getSVal(const EnvironmentEntry &Entry,
+ SValBuilder& svalBuilder,
+ bool useOnlyDirectBindings) const {
if (useOnlyDirectBindings) {
// This branch is rarely taken, but can be exercised by
// checkers that explicitly bind values to arbitrary
// expressions. It is crucial that we do not ignore any
// expression here, and do a direct lookup.
- return lookupExpr(E);
+ return lookupExpr(Entry);
}
+ const Stmt *E = Entry.getStmt();
+ const LocationContext *LCtx = Entry.getLocationContext();
+
for (;;) {
if (const Expr *Ex = dyn_cast<Expr>(E))
E = Ex->IgnoreParens();
@@ -61,7 +65,7 @@
return svalBuilder.makeIntVal(C->getValue(), C->getType());
}
case Stmt::CXXBoolLiteralExprClass: {
- const SVal *X = ExprBindings.lookup(E);
+ const SVal *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx));
if (X)
return *X;
else
@@ -69,7 +73,7 @@
}
case Stmt::IntegerLiteralClass: {
// In C++, this expression may have been bound to a temporary object.
- SVal const *X = ExprBindings.lookup(E);
+ SVal const *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx));
if (X)
return *X;
else
@@ -86,6 +90,14 @@
continue;
case Stmt::ObjCPropertyRefExprClass:
return loc::ObjCPropRef(cast<ObjCPropertyRefExpr>(E));
+ case Stmt::ReturnStmtClass: {
+ const ReturnStmt *RS = cast<ReturnStmt>(E);
+ if (const Expr *RE = RS->getRetValue()) {
+ E = RE;
+ continue;
+ }
+ return UndefinedVal();
+ }
// Handle all other Stmt* using a lookup.
default:
@@ -93,32 +105,33 @@
};
break;
}
- return lookupExpr(E);
+ return lookupExpr(EnvironmentEntry(E, LCtx));
}
-Environment EnvironmentManager::bindExpr(Environment Env, const Stmt *S,
- SVal V, bool Invalidate) {
- assert(S);
-
+Environment EnvironmentManager::bindExpr(Environment Env,
+ const EnvironmentEntry &E,
+ SVal V,
+ bool Invalidate) {
if (V.isUnknown()) {
if (Invalidate)
- return Environment(F.remove(Env.ExprBindings, S));
+ return Environment(F.remove(Env.ExprBindings, E));
else
return Env;
}
-
- return Environment(F.add(Env.ExprBindings, S, V));
+ return Environment(F.add(Env.ExprBindings, E, V));
}
-static inline const Stmt *MakeLocation(const Stmt *S) {
- return (const Stmt*) (((uintptr_t) S) | 0x1);
+static inline EnvironmentEntry MakeLocation(const EnvironmentEntry &E) {
+ const Stmt *S = E.getStmt();
+ S = (const Stmt*) (((uintptr_t) S) | 0x1);
+ return EnvironmentEntry(S, E.getLocationContext());
}
Environment EnvironmentManager::bindExprAndLocation(Environment Env,
- const Stmt *S,
+ const EnvironmentEntry &E,
SVal location, SVal V) {
- return Environment(F.add(F.add(Env.ExprBindings, MakeLocation(S), location),
- S, V));
+ return Environment(F.add(F.add(Env.ExprBindings, MakeLocation(E), location),
+ E, V));
}
namespace {
@@ -130,10 +143,11 @@
};
} // end anonymous namespace
-// In addition to mapping from Stmt * - > SVals in the Environment, we also
-// maintain a mapping from Stmt * -> SVals (locations) that were used during
-// a load and store.
-static inline bool IsLocation(const Stmt *S) {
+// In addition to mapping from EnvironmentEntry - > SVals in the Environment,
+// we also maintain a mapping from EnvironmentEntry -> SVals (locations)
+// that were used during a load and store.
+static inline bool IsLocation(const EnvironmentEntry &E) {
+ const Stmt *S = E.getStmt();
return (bool) (((uintptr_t) S) & 0x1);
}
@@ -154,12 +168,12 @@
// outnumber block-level expression bindings).
Environment NewEnv = getInitialEnvironment();
- SmallVector<std::pair<const Stmt*, SVal>, 10> deferredLocations;
+ SmallVector<std::pair<EnvironmentEntry, SVal>, 10> deferredLocations;
MarkLiveCallback CB(SymReaper);
ScanReachableSymbols RSScaner(ST, CB);
- llvm::ImmutableMapRef<const Stmt*,SVal>
+ llvm::ImmutableMapRef<EnvironmentEntry,SVal>
EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
F.getTreeFactory());
@@ -167,7 +181,7 @@
for (Environment::iterator I = Env.begin(), E = Env.end();
I != E; ++I) {
- const Stmt *BlkExpr = I.getKey();
+ const EnvironmentEntry &BlkExpr = I.getKey();
// For recorded locations (used when evaluating loads and stores), we
// consider them live only when their associated normal expression is
// also live.
@@ -179,7 +193,7 @@
}
const SVal &X = I.getData();
- if (SymReaper.isLive(BlkExpr)) {
+ if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
// Copy the binding to the new map.
EBMapRef = EBMapRef.add(BlkExpr, X);
@@ -204,13 +218,58 @@
// Go through he deferred locations and add them to the new environment if
// the correspond Stmt* is in the map as well.
- for (SmallVectorImpl<std::pair<const Stmt*, SVal> >::iterator
+ for (SmallVectorImpl<std::pair<EnvironmentEntry, SVal> >::iterator
I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) {
- const Stmt *S = (Stmt*) (((uintptr_t) I->first) & (uintptr_t) ~0x1);
- if (EBMapRef.lookup(S))
- EBMapRef = EBMapRef.add(I->first, I->second);
+ const EnvironmentEntry &En = I->first;
+ const Stmt *S = (Stmt*) (((uintptr_t) En.getStmt()) & (uintptr_t) ~0x1);
+ if (EBMapRef.lookup(EnvironmentEntry(S, En.getLocationContext())))
+ EBMapRef = EBMapRef.add(En, I->second);
}
NewEnv.ExprBindings = EBMapRef.asImmutableMap();
return NewEnv;
}
+
+void Environment::print(raw_ostream &Out, const char *NL,
+ const char *Sep) const {
+ printAux(Out, false, NL, Sep);
+ printAux(Out, true, NL, Sep);
+}
+
+void Environment::printAux(raw_ostream &Out, bool printLocations,
+ const char *NL,
+ const char *Sep) const{
+
+ bool isFirst = true;
+
+ for (Environment::iterator I = begin(), E = end(); I != E; ++I) {
+ const EnvironmentEntry &En = I.getKey();
+ if (IsLocation(En)) {
+ if (!printLocations)
+ continue;
+ }
+ else {
+ if (printLocations)
+ continue;
+ }
+
+ if (isFirst) {
+ Out << NL << NL
+ << (printLocations ? "Load/Store locations:" : "Expressions:")
+ << NL;
+ isFirst = false;
+ } else {
+ Out << NL;
+ }
+
+ const Stmt *S = En.getStmt();
+ if (printLocations) {
+ S = (Stmt*) (((uintptr_t) S) & ((uintptr_t) ~0x1));
+ }
+
+ Out << " (" << (void*) En.getLocationContext() << ',' << (void*) S << ") ";
+ LangOptions LO; // FIXME.
+ S->printPretty(Out, 0, PrintingPolicy(LO));
+ Out << " : " << I.getData();
+ }
+}
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/ExplodedGraph.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/ExplodedGraph.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/ExplodedGraph.cpp Fri Jan 20 10:14:22 2012
@@ -91,7 +91,8 @@
// Condition 3.
ProgramPoint progPoint = node->getLocation();
- if (!isa<PostStmt>(progPoint))
+ if (!isa<PostStmt>(progPoint) ||
+ (isa<CallEnter>(progPoint) || isa<CallExit>(progPoint)))
continue;
// Condition 4.
PostStmt ps = cast<PostStmt>(progPoint);
@@ -379,6 +380,8 @@
return G;
}
+void InterExplodedGraphMap::anchor() { }
+
ExplodedNode*
InterExplodedGraphMap::getMappedNode(const ExplodedNode *N) const {
llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I =
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngine.cpp Fri Jan 20 10:14:22 2012
@@ -24,7 +24,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/ImmutableList.h"
@@ -158,27 +157,6 @@
return state;
}
-bool
-ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const
-{
- if (callOrMessage.isFunctionCall() && !callOrMessage.isCXXCall()) {
- SVal calleeV = callOrMessage.getFunctionCallee();
- if (const FunctionTextRegion *codeR =
- dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) {
-
- const FunctionDecl *fd = codeR->getDecl();
- if (const IdentifierInfo *ii = fd->getIdentifier()) {
- StringRef fname = ii->getName();
- if (fname == "strlen")
- return false;
- }
- }
- }
-
- // The conservative answer: invalidates globals.
- return true;
-}
-
//===----------------------------------------------------------------------===//
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
@@ -388,7 +366,7 @@
const FieldDecl *FD = BMI->getAnyMember();
SVal FieldLoc = state->getLValue(FD, thisVal);
- SVal InitVal = state->getSVal(BMI->getInit());
+ SVal InitVal = state->getSVal(BMI->getInit(), Pred->getLocationContext());
state = state->bindLoc(FieldLoc, InitVal);
// Use a custom node building process.
@@ -556,7 +534,8 @@
case Stmt::GNUNullExprClass: {
// GNU __null is a pointer-width integer, not an actual pointer.
const ProgramState *state = Pred->getState();
- state = state->BindExpr(S, svalBuilder.makeIntValWithPtrWidth(0, false));
+ state = state->BindExpr(S, Pred->getLocationContext(),
+ svalBuilder.makeIntValWithPtrWidth(0, false));
Bldr.generateNode(S, Pred, state);
break;
}
@@ -575,7 +554,8 @@
const ProgramState *state = Pred->getState();
QualType ty = cast<ImplicitValueInitExpr>(S)->getType();
SVal val = svalBuilder.makeZeroVal(ty);
- Bldr.generateNode(S, Pred, state->BindExpr(S, val));
+ Bldr.generateNode(S, Pred, state->BindExpr(S, Pred->getLocationContext(),
+ val));
break;
}
@@ -657,7 +637,9 @@
else if (B->getOpcode() == BO_Comma) {
const ProgramState *state = Pred->getState();
Bldr.generateNode(B, Pred,
- state->BindExpr(B, state->getSVal(B->getRHS())));
+ state->BindExpr(B, Pred->getLocationContext(),
+ state->getSVal(B->getRHS(),
+ Pred->getLocationContext())));
break;
}
@@ -872,7 +854,9 @@
if (Expr *LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
const ProgramState *state = Pred->getState();
Bldr.generateNode(SE, Pred,
- state->BindExpr(SE, state->getSVal(LastExpr)));
+ state->BindExpr(SE, Pred->getLocationContext(),
+ state->getSVal(LastExpr,
+ Pred->getLocationContext())));
}
break;
}
@@ -880,7 +864,8 @@
case Stmt::StringLiteralClass: {
const ProgramState *state = Pred->getState();
SVal V = state->getLValue(cast<StringLiteral>(S));
- Bldr.generateNode(S, Pred, state->BindExpr(S, V));
+ Bldr.generateNode(S, Pred, state->BindExpr(S, Pred->getLocationContext(),
+ V));
return;
}
@@ -903,11 +888,14 @@
const ProgramState *state = Pred->getState();
const PseudoObjectExpr *PE = cast<PseudoObjectExpr>(S);
if (const Expr *Result = PE->getResultExpr()) {
- SVal V = state->getSVal(Result);
- Bldr.generateNode(S, Pred, state->BindExpr(S, V));
+ SVal V = state->getSVal(Result, Pred->getLocationContext());
+ Bldr.generateNode(S, Pred,
+ state->BindExpr(S, Pred->getLocationContext(), V));
}
else
- Bldr.generateNode(S, Pred, state->BindExpr(S, UnknownVal()));
+ Bldr.generateNode(S, Pred,
+ state->BindExpr(S, Pred->getLocationContext(),
+ UnknownVal()));
Bldr.addNodes(Dst);
break;
@@ -932,8 +920,9 @@
//===----------------------------------------------------------------------===//
const ProgramState *ExprEngine::MarkBranch(const ProgramState *state,
- const Stmt *Terminator,
- bool branchTaken) {
+ const Stmt *Terminator,
+ const LocationContext *LCtx,
+ bool branchTaken) {
switch (Terminator->getStmtClass()) {
default:
@@ -956,7 +945,7 @@
(Op == BO_LOr && !branchTaken)
? B->getRHS() : B->getLHS();
- return state->BindExpr(B, UndefinedVal(Ex));
+ return state->BindExpr(B, LCtx, UndefinedVal(Ex));
}
case Stmt::BinaryConditionalOperatorClass:
@@ -974,7 +963,7 @@
else
Ex = C->getFalseExpr();
- return state->BindExpr(C, UndefinedVal(Ex));
+ return state->BindExpr(C, LCtx, UndefinedVal(Ex));
}
case Stmt::ChooseExprClass: { // ?:
@@ -982,7 +971,7 @@
const ChooseExpr *C = cast<ChooseExpr>(Terminator);
const Expr *Ex = branchTaken ? C->getLHS() : C->getRHS();
- return state->BindExpr(C, UndefinedVal(Ex));
+ return state->BindExpr(C, LCtx, UndefinedVal(Ex));
}
}
}
@@ -995,6 +984,7 @@
static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr,
const ProgramState *state,
const Stmt *Condition,
+ const LocationContext *LCtx,
ASTContext &Ctx) {
const Expr *Ex = dyn_cast<Expr>(Condition);
@@ -1025,7 +1015,7 @@
if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits)
return UnknownVal();
- return state->getSVal(Ex);
+ return state->getSVal(Ex, LCtx);
}
void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
@@ -1064,7 +1054,7 @@
continue;
const ProgramState *PrevState = Pred->getState();
- SVal X = PrevState->getSVal(Condition);
+ SVal X = PrevState->getSVal(Condition, Pred->getLocationContext());
if (X.isUnknownOrUndef()) {
// Give it a chance to recover from unknown.
@@ -1076,6 +1066,7 @@
// underlying value and use that instead.
SVal recovered = RecoverCastedSymbol(getStateManager(),
PrevState, Condition,
+ Pred->getLocationContext(),
getContext());
if (!recovered.isUnknown()) {
@@ -1084,10 +1075,15 @@
}
}
}
+
+ const LocationContext *LCtx = PredI->getLocationContext();
+
// If the condition is still unknown, give up.
if (X.isUnknownOrUndef()) {
- builder.generateNode(MarkBranch(PrevState, Term, true), true, PredI);
- builder.generateNode(MarkBranch(PrevState, Term, false), false, PredI);
+ builder.generateNode(MarkBranch(PrevState, Term, LCtx, true),
+ true, PredI);
+ builder.generateNode(MarkBranch(PrevState, Term, LCtx, false),
+ false, PredI);
continue;
}
@@ -1096,7 +1092,8 @@
// Process the true branch.
if (builder.isFeasible(true)) {
if (const ProgramState *state = PrevState->assume(V, true))
- builder.generateNode(MarkBranch(state, Term, true), true, PredI);
+ builder.generateNode(MarkBranch(state, Term, LCtx, true),
+ true, PredI);
else
builder.markInfeasible(true);
}
@@ -1104,7 +1101,8 @@
// Process the false branch.
if (builder.isFeasible(false)) {
if (const ProgramState *state = PrevState->assume(V, false))
- builder.generateNode(MarkBranch(state, Term, false), false, PredI);
+ builder.generateNode(MarkBranch(state, Term, LCtx, false),
+ false, PredI);
else
builder.markInfeasible(false);
}
@@ -1117,7 +1115,7 @@
void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
const ProgramState *state = builder.getState();
- SVal V = state->getSVal(builder.getTarget());
+ SVal V = state->getSVal(builder.getTarget(), builder.getLocationContext());
// Three possibilities:
//
@@ -1171,7 +1169,7 @@
typedef SwitchNodeBuilder::iterator iterator;
const ProgramState *state = builder.getState();
const Expr *CondE = builder.getCondition();
- SVal CondV_untested = state->getSVal(CondE);
+ SVal CondV_untested = state->getSVal(CondE, builder.getLocationContext());
if (CondV_untested.isUndef()) {
//ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
@@ -1278,6 +1276,7 @@
StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
const ProgramState *state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
assert(Ex->isLValue());
@@ -1292,19 +1291,19 @@
V = UnknownVal();
}
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V), false, 0,
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0,
ProgramPoint::PostLValueKind);
return;
}
if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) {
assert(!Ex->isLValue());
SVal V = svalBuilder.makeIntVal(ED->getInitVal());
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V));
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V));
return;
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
SVal V = svalBuilder.getFunctionPointer(FD);
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V), false, 0,
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0,
ProgramPoint::PostLValueKind);
return;
}
@@ -1328,11 +1327,13 @@
for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(),
ei = checkerPreStmt.end(); it != ei; ++it) {
+ const LocationContext *LCtx = (*it)->getLocationContext();
const ProgramState *state = (*it)->getState();
- SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
- state->getSVal(Base));
+ SVal V = state->getLValue(A->getType(),
+ state->getSVal(Idx, LCtx),
+ state->getSVal(Base, LCtx));
assert(A->isLValue());
- Bldr.generateNode(A, *it, state->BindExpr(A, V),
+ Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V),
false, 0, ProgramPoint::PostLValueKind);
}
}
@@ -1358,14 +1359,15 @@
Expr *baseExpr = M->getBase()->IgnoreParens();
const ProgramState *state = Pred->getState();
- SVal baseExprVal = state->getSVal(baseExpr);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext());
if (isa<nonloc::LazyCompoundVal>(baseExprVal) ||
isa<nonloc::CompoundVal>(baseExprVal) ||
// FIXME: This can originate by conjuring a symbol for an unknown
// temporary struct object, see test/Analysis/fields.c:
// (p = getit()).x
isa<nonloc::SymbolVal>(baseExprVal)) {
- Bldr.generateNode(M, Pred, state->BindExpr(M, UnknownVal()));
+ Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, UnknownVal()));
return;
}
@@ -1376,7 +1378,7 @@
// For all other cases, compute an lvalue.
SVal L = state->getLValue(field, baseExprVal);
if (M->isLValue())
- Bldr.generateNode(M, Pred, state->BindExpr(M, L), false, 0,
+ Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), false, 0,
ProgramPoint::PostLValueKind);
else {
Bldr.takeNodes(Pred);
@@ -1487,7 +1489,7 @@
// Perform the load from the referenced value.
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) {
state = (*I)->getState();
- location = state->getSVal(Ex);
+ location = state->getSVal(Ex, (*I)->getLocationContext());
evalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
}
return;
@@ -1515,17 +1517,19 @@
// Proceed with the load.
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
state = (*NI)->getState();
+ const LocationContext *LCtx = (*NI)->getLocationContext();
if (location.isUnknown()) {
// This is important. We must nuke the old binding.
- Bldr.generateNode(Ex, *NI, state->BindExpr(Ex, UnknownVal()),
+ Bldr.generateNode(Ex, *NI, state->BindExpr(Ex, LCtx, UnknownVal()),
false, tag, ProgramPoint::PostLoadKind);
}
else {
if (LoadTy.isNull())
LoadTy = Ex->getType();
SVal V = state->getSVal(cast<Loc>(location), LoadTy);
- Bldr.generateNode(Ex, *NI, state->bindExprAndLocation(Ex, location, V),
+ Bldr.generateNode(Ex, *NI, state->bindExprAndLocation(Ex, LCtx,
+ location, V),
false, tag, ProgramPoint::PostLoadKind);
}
}
@@ -1565,82 +1569,6 @@
BldrTop.addNodes(Tmp);
}
-bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
- ExplodedNode *Pred) {
- return false;
-
- // Inlining isn't correct right now because we:
- // (a) don't generate CallExit nodes.
- // (b) we need a way to postpone doing post-visits of CallExprs until
- // the CallExit. This means we need CallExits for the non-inline
- // cases as well.
-
-#if 0
- const ProgramState *state = Pred->getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
-
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
-
- // Specially handle CXXMethods.
- const CXXMethodDecl *methodDecl = 0;
-
- switch (CE->getStmtClass()) {
- default: break;
- case Stmt::CXXOperatorCallExprClass: {
- const CXXOperatorCallExpr *opCall = cast<CXXOperatorCallExpr>(CE);
- methodDecl =
- dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl());
- break;
- }
- case Stmt::CXXMemberCallExprClass: {
- const CXXMemberCallExpr *memberCall = cast<CXXMemberCallExpr>(CE);
- const MemberExpr *memberExpr =
- cast<MemberExpr>(memberCall->getCallee()->IgnoreParens());
- methodDecl = cast<CXXMethodDecl>(memberExpr->getMemberDecl());
- break;
- }
- }
-
-
-
-
- // Check if the function definition is in the same translation unit.
- if (FD->hasBody(FD)) {
- const StackFrameContext *stackFrame =
- AMgr.getStackFrame(AMgr.getAnalysisDeclContext(FD),
- Pred->getLocationContext(),
- CE, currentBuilderContext->getBlock(), currentStmtIdx);
- // Now we have the definition of the callee, create a CallEnter node.
- CallEnter Loc(CE, stackFrame, Pred->getLocationContext());
-
- ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
- Dst.Add(N);
- return true;
- }
-
- // Check if we can find the function definition in other translation units.
- if (AMgr.hasIndexer()) {
- AnalysisDeclContext *C = AMgr.getAnalysisDeclContextInAnotherTU(FD);
- if (C == 0)
- return false;
- const StackFrameContext *stackFrame =
- AMgr.getStackFrame(C, Pred->getLocationContext(),
- CE, currentBuilderContext->getBlock(), currentStmtIdx);
- CallEnter Loc(CE, stackFrame, Pred->getLocationContext());
- ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
- Dst.Add(N);
- return true;
- }
-
- // Generate the CallExit node.
-
- return false;
-#endif
-}
-
std::pair<const ProgramPointTag *, const ProgramPointTag*>
ExprEngine::getEagerlyAssumeTags() {
static SimpleProgramPointTag
@@ -1664,7 +1592,7 @@
}
const ProgramState *state = Pred->getState();
- SVal V = state->getSVal(Ex);
+ SVal V = state->getSVal(Ex, Pred->getLocationContext());
nonloc::SymbolVal *SEV = dyn_cast<nonloc::SymbolVal>(&V);
if (SEV && SEV->isExpression()) {
const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
@@ -1673,14 +1601,14 @@
// First assume that the condition is true.
if (const ProgramState *StateTrue = state->assume(*SEV, true)) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
- StateTrue = StateTrue->BindExpr(Ex, Val);
+ StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateTrue, false, tags.first);
}
// Next, assume that the condition is false.
if (const ProgramState *StateFalse = state->assume(*SEV, false)) {
SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
- StateFalse = StateFalse->BindExpr(Ex, Val);
+ StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateFalse, false, tags.second);
}
}
@@ -1728,7 +1656,7 @@
for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
- SVal X = state->getSVal(*OI);
+ SVal X = state->getSVal(*OI, Pred->getLocationContext());
assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
if (isa<Loc>(X))
@@ -1933,7 +1861,7 @@
const ProgramState *state = N->getState();
Out << "\\|StateID: " << (void*) state
<< " NodeID: " << (void*) N << "\\|";
- state->printDOT(Out, *N->getLocationContext()->getCFG());
+ state->printDOT(Out);
Out << "\\l";
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineC.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineC.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineC.cpp Fri Jan 20 10:14:22 2012
@@ -35,8 +35,9 @@
it != ei; ++it) {
const ProgramState *state = (*it)->getState();
- SVal LeftV = state->getSVal(LHS);
- SVal RightV = state->getSVal(RHS);
+ const LocationContext *LCtx = (*it)->getLocationContext();
+ SVal LeftV = state->getSVal(LHS, LCtx);
+ SVal RightV = state->getSVal(RHS, LCtx);
BinaryOperator::Opcode Op = B->getOpcode();
@@ -50,7 +51,8 @@
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
SVal ExprVal = B->isLValue() ? LeftV : RightV;
- evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, ExprVal), LeftV, RightV);
+ evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, LCtx, ExprVal),
+ LeftV, RightV);
continue;
}
@@ -64,7 +66,7 @@
continue;
}
- state = state->BindExpr(B, Result);
+ state = state->BindExpr(B, LCtx, Result);
Bldr.generateNode(B, *it, state);
continue;
}
@@ -96,7 +98,8 @@
++I) {
state = (*I)->getState();
- SVal V = state->getSVal(LHS);
+ const LocationContext *LCtx = (*I)->getLocationContext();
+ SVal V = state->getSVal(LHS, LCtx);
// Get the computation type.
QualType CTy =
@@ -143,9 +146,9 @@
// In C++, assignment and compound assignment operators return an
// lvalue.
if (B->isLValue())
- state = state->BindExpr(B, location);
+ state = state->BindExpr(B, LCtx, location);
else
- state = state->BindExpr(B, Result);
+ state = state->BindExpr(B, LCtx, Result);
evalStore(Tmp2, B, LHS, *I, state, location, LHSVal);
}
@@ -164,7 +167,10 @@
ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
- Bldr.generateNode(BE, Pred, Pred->getState()->BindExpr(BE, V), false, 0,
+ Bldr.generateNode(BE, Pred,
+ Pred->getState()->BindExpr(BE, Pred->getLocationContext(),
+ V),
+ false, 0,
ProgramPoint::PostLValueKind);
// FIXME: Move all post/pre visits to ::Visit().
@@ -182,7 +188,8 @@
I!=E; ++I) {
ExplodedNode *subExprNode = *I;
const ProgramState *state = subExprNode->getState();
- evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex));
+ const LocationContext *LCtx = subExprNode->getLocationContext();
+ evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex, LCtx));
}
return;
}
@@ -211,13 +218,19 @@
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject: // Fall-through.
+ // The analyser can ignore atomic casts for now, although some future
+ // checkers may want to make certain that you're not modifying the same
+ // value through atomic and nonatomic pointers.
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
// True no-ops.
case CK_NoOp:
case CK_FunctionToPointerDecay: {
// Copy the SVal of Ex to CastE.
const ProgramState *state = Pred->getState();
- SVal V = state->getSVal(Ex);
- state = state->BindExpr(CastE, V);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal V = state->getSVal(Ex, LCtx);
+ state = state->BindExpr(CastE, LCtx, V);
Bldr.generateNode(CastE, Pred, state);
continue;
}
@@ -251,9 +264,10 @@
case CK_ObjCObjectLValueCast: {
// Delegate to SValBuilder to process.
const ProgramState *state = Pred->getState();
- SVal V = state->getSVal(Ex);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
- state = state->BindExpr(CastE, V);
+ state = state->BindExpr(CastE, LCtx, V);
Bldr.generateNode(CastE, Pred, state);
continue;
}
@@ -261,9 +275,10 @@
case CK_UncheckedDerivedToBase: {
// For DerivedToBase cast, delegate to the store manager.
const ProgramState *state = Pred->getState();
- SVal val = state->getSVal(Ex);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal val = state->getSVal(Ex, LCtx);
val = getStoreManager().evalDerivedToBase(val, T);
- state = state->BindExpr(CastE, val);
+ state = state->BindExpr(CastE, LCtx, val);
Bldr.generateNode(CastE, Pred, state);
continue;
}
@@ -287,7 +302,9 @@
svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType,
currentBuilderContext->getCurrentBlockCount());
- const ProgramState *state = Pred->getState()->BindExpr(CastE, result);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ const ProgramState *state = Pred->getState()->BindExpr(CastE, LCtx,
+ result);
Bldr.generateNode(CastE, Pred, state);
continue;
}
@@ -304,14 +321,14 @@
= cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
const ProgramState *state = Pred->getState();
- SVal ILV = state->getSVal(ILE);
+ SVal ILV = state->getSVal(ILE, Pred->getLocationContext());
const LocationContext *LC = Pred->getLocationContext();
state = state->bindCompoundLiteral(CL, LC, ILV);
if (CL->isLValue())
- B.generateNode(CL, Pred, state->BindExpr(CL, state->getLValue(CL, LC)));
+ B.generateNode(CL, Pred, state->BindExpr(CL, LC, state->getLValue(CL, LC)));
else
- B.generateNode(CL, Pred, state->BindExpr(CL, ILV));
+ B.generateNode(CL, Pred, state->BindExpr(CL, LC, ILV));
}
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
@@ -345,7 +362,7 @@
const LocationContext *LC = N->getLocationContext();
if (const Expr *InitEx = VD->getInit()) {
- SVal InitVal = state->getSVal(InitEx);
+ SVal InitVal = state->getSVal(InitEx, Pred->getLocationContext());
// We bound the temp obj region to the CXXConstructExpr. Now recover
// the lazy compound value when the variable is not a reference.
@@ -379,18 +396,19 @@
StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
const ProgramState *state = Pred->getState();
- SVal X = state->getSVal(B);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal X = state->getSVal(B, LCtx);
assert(X.isUndef());
const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData();
assert(Ex);
if (Ex == B->getRHS()) {
- X = state->getSVal(Ex);
+ X = state->getSVal(Ex, LCtx);
// Handle undefined values.
if (X.isUndef()) {
- Bldr.generateNode(B, Pred, state->BindExpr(B, X));
+ Bldr.generateNode(B, Pred, state->BindExpr(B, LCtx, X));
return;
}
@@ -404,11 +422,13 @@
// the payoff is not likely to be large. Instead, we do eager evaluation.
if (const ProgramState *newState = state->assume(XD, true))
Bldr.generateNode(B, Pred,
- newState->BindExpr(B, svalBuilder.makeIntVal(1U, B->getType())));
+ newState->BindExpr(B, LCtx,
+ svalBuilder.makeIntVal(1U, B->getType())));
if (const ProgramState *newState = state->assume(XD, false))
Bldr.generateNode(B, Pred,
- newState->BindExpr(B, svalBuilder.makeIntVal(0U, B->getType())));
+ newState->BindExpr(B, LCtx,
+ svalBuilder.makeIntVal(0U, B->getType())));
}
else {
// We took the LHS expression. Depending on whether we are '&&' or
@@ -416,7 +436,7 @@
// the short-circuiting.
X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U,
B->getType());
- Bldr.generateNode(B, Pred, state->BindExpr(B, X));
+ Bldr.generateNode(B, Pred, state->BindExpr(B, LCtx, X));
}
}
@@ -426,6 +446,7 @@
StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
const ProgramState *state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
QualType T = getContext().getCanonicalType(IE->getType());
unsigned NumInitElements = IE->getNumInits();
@@ -436,24 +457,27 @@
// e.g: static int* myArray[] = {};
if (NumInitElements == 0) {
SVal V = svalBuilder.makeCompoundVal(T, vals);
- B.generateNode(IE, Pred, state->BindExpr(IE, V));
+ B.generateNode(IE, Pred, state->BindExpr(IE, LCtx, V));
return;
}
for (InitListExpr::const_reverse_iterator it = IE->rbegin(),
ei = IE->rend(); it != ei; ++it) {
- vals = getBasicVals().consVals(state->getSVal(cast<Expr>(*it)), vals);
+ vals = getBasicVals().consVals(state->getSVal(cast<Expr>(*it), LCtx),
+ vals);
}
B.generateNode(IE, Pred,
- state->BindExpr(IE, svalBuilder.makeCompoundVal(T, vals)));
+ state->BindExpr(IE, LCtx,
+ svalBuilder.makeCompoundVal(T, vals)));
return;
}
if (Loc::isLocType(T) || T->isIntegerType()) {
assert(IE->getNumInits() == 1);
const Expr *initEx = IE->getInit(0);
- B.generateNode(IE, Pred, state->BindExpr(IE, state->getSVal(initEx)));
+ B.generateNode(IE, Pred, state->BindExpr(IE, LCtx,
+ state->getSVal(initEx, LCtx)));
return;
}
@@ -468,28 +492,30 @@
StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
const ProgramState *state = Pred->getState();
- SVal X = state->getSVal(Ex);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal X = state->getSVal(Ex, LCtx);
assert (X.isUndef());
const Expr *SE = (Expr*) cast<UndefinedVal>(X).getData();
assert(SE);
- X = state->getSVal(SE);
+ X = state->getSVal(SE, LCtx);
// Make sure that we invalidate the previous binding.
- B.generateNode(Ex, Pred, state->BindExpr(Ex, X, true));
+ B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, X, true));
}
void ExprEngine::
VisitOffsetOfExpr(const OffsetOfExpr *OOE,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
- Expr::EvalResult Res;
- if (OOE->EvaluateAsRValue(Res, getContext()) && Res.Val.isInt()) {
- const APSInt &IV = Res.Val.getInt();
+ APSInt IV;
+ if (OOE->EvaluateAsInt(IV, getContext())) {
assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
assert(OOE->getType()->isIntegerType());
assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType());
SVal X = svalBuilder.makeIntVal(IV);
- B.generateNode(OOE, Pred, Pred->getState()->BindExpr(OOE, X));
+ B.generateNode(OOE, Pred,
+ Pred->getState()->BindExpr(OOE, Pred->getLocationContext(),
+ X));
}
// FIXME: Handle the case where __builtin_offsetof is not a constant.
}
@@ -519,12 +545,12 @@
}
}
- Expr::EvalResult Result;
- Ex->EvaluateAsRValue(Result, getContext());
- CharUnits amt = CharUnits::fromQuantity(Result.Val.getInt().getZExtValue());
+ APSInt Value = Ex->EvaluateKnownConstInt(getContext());
+ CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue());
const ProgramState *state = Pred->getState();
- state = state->BindExpr(Ex, svalBuilder.makeIntVal(amt.getQuantity(),
+ state = state->BindExpr(Ex, Pred->getLocationContext(),
+ svalBuilder.makeIntVal(amt.getQuantity(),
Ex->getType()));
Bldr.generateNode(Ex, Pred, state);
}
@@ -557,7 +583,9 @@
// For all other types, UO_Real is an identity operation.
assert (U->getType() == Ex->getType());
const ProgramState *state = (*I)->getState();
- Bldr.generateNode(U, *I, state->BindExpr(U, state->getSVal(Ex)));
+ const LocationContext *LCtx = (*I)->getLocationContext();
+ Bldr.generateNode(U, *I, state->BindExpr(U, LCtx,
+ state->getSVal(Ex, LCtx)));
}
break;
@@ -578,8 +606,9 @@
// For all other types, UO_Imag returns 0.
const ProgramState *state = (*I)->getState();
+ const LocationContext *LCtx = (*I)->getLocationContext();
SVal X = svalBuilder.makeZeroVal(Ex->getType());
- Bldr.generateNode(U, *I, state->BindExpr(U, X));
+ Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, X));
}
break;
@@ -603,7 +632,9 @@
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
const ProgramState *state = (*I)->getState();
- Bldr.generateNode(U, *I, state->BindExpr(U, state->getSVal(Ex)));
+ const LocationContext *LCtx = (*I)->getLocationContext();
+ Bldr.generateNode(U, *I, state->BindExpr(U, LCtx,
+ state->getSVal(Ex, LCtx)));
}
break;
@@ -619,12 +650,13 @@
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
const ProgramState *state = (*I)->getState();
+ const LocationContext *LCtx = (*I)->getLocationContext();
// Get the value of the subexpression.
- SVal V = state->getSVal(Ex);
+ SVal V = state->getSVal(Ex, LCtx);
if (V.isUnknownOrUndef()) {
- Bldr.generateNode(U, *I, state->BindExpr(U, V));
+ Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V));
continue;
}
@@ -634,12 +666,12 @@
case UO_Not:
// FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, evalComplement(cast<NonLoc>(V)));
+ state = state->BindExpr(U, LCtx, evalComplement(cast<NonLoc>(V)));
break;
case UO_Minus:
// FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, evalMinus(cast<NonLoc>(V)));
+ state = state->BindExpr(U, LCtx, evalMinus(cast<NonLoc>(V)));
break;
case UO_LNot:
@@ -661,7 +693,7 @@
U->getType());
}
- state = state->BindExpr(U, Result);
+ state = state->BindExpr(U, LCtx, Result);
break;
}
@@ -683,9 +715,9 @@
Visit(Ex, Pred, Tmp);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
-
+ const LocationContext *LCtx = (*I)->getLocationContext();
const ProgramState *state = (*I)->getState();
- SVal loc = state->getSVal(Ex);
+ SVal loc = state->getSVal(Ex, LCtx);
// Perform a load.
ExplodedNodeSet Tmp2;
@@ -696,11 +728,12 @@
for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) {
state = (*I2)->getState();
- SVal V2_untested = state->getSVal(Ex);
+ assert(LCtx == (*I2)->getLocationContext());
+ SVal V2_untested = state->getSVal(Ex, LCtx);
// Propagate unknown and undefined values.
if (V2_untested.isUnknownOrUndef()) {
- Bldr.generateNode(U, *I2, state->BindExpr(U, V2_untested));
+ Bldr.generateNode(U, *I2, state->BindExpr(U, LCtx, V2_untested));
continue;
}
DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
@@ -751,9 +784,9 @@
// Since the lvalue-to-rvalue conversion is explicit in the AST,
// we bind an l-value if the operator is prefix and an lvalue (in C++).
if (U->isLValue())
- state = state->BindExpr(U, loc);
+ state = state->BindExpr(U, LCtx, loc);
else
- state = state->BindExpr(U, U->isPostfix() ? V2 : Result);
+ state = state->BindExpr(U, LCtx, U->isPostfix() ? V2 : Result);
// Perform the store.
Bldr.takeNodes(*I2);
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Fri Jan 20 10:14:22 2012
@@ -110,17 +110,17 @@
StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens();
const ProgramState *state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
// Bind the temporary object to the value of the expression. Then bind
// the expression to the location of the object.
- SVal V = state->getSVal(tempExpr);
+ SVal V = state->getSVal(tempExpr, Pred->getLocationContext());
const MemRegion *R =
- svalBuilder.getRegionManager().getCXXTempObjectRegion(ME,
- Pred->getLocationContext());
+ svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx);
state = state->bindLoc(loc::MemRegionVal(R), V);
- Bldr.generateNode(ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R)));
+ Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, loc::MemRegionVal(R)));
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
@@ -208,7 +208,7 @@
const LocationContext *LC = Pred->getLocationContext();
const ProgramState *state = Pred->getState();
- state = invalidateArguments(state, CallOrObjCMessage(E, state), LC);
+ state = invalidateArguments(state, CallOrObjCMessage(E, state, LC), LC);
Bldr.generateNode(E, Pred, state);
}
}
@@ -256,7 +256,8 @@
// FIXME: allocating an array requires simulating the constructors.
// For now, just return a symbolicated region.
const ProgramState *state = Pred->getState();
- state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
+ state = state->BindExpr(CNE, Pred->getLocationContext(),
+ loc::MemRegionVal(EleReg));
Bldr.generateNode(CNE, Pred, state);
return;
}
@@ -286,7 +287,7 @@
ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end();
ai != ae; ++ai)
{
- SVal val = state->getSVal(*ai);
+ SVal val = state->getSVal(*ai, (*I)->getLocationContext());
if (const MemRegion *region = val.getAsRegion())
regionsToInvalidate.push_back(region);
}
@@ -294,18 +295,21 @@
if (ObjTy->isRecordType()) {
regionsToInvalidate.push_back(EleReg);
// Invalidate the regions.
+ // TODO: Pass the call to new information as the last argument, to limit
+ // the globals which will get invalidated.
state = state->invalidateRegions(regionsToInvalidate,
- CNE, blockCount, 0,
- /* invalidateGlobals = */ true);
+ CNE, blockCount, 0, 0);
} else {
// Invalidate the regions.
+ // TODO: Pass the call to new information as the last argument, to limit
+ // the globals which will get invalidated.
state = state->invalidateRegions(regionsToInvalidate,
- CNE, blockCount, 0,
- /* invalidateGlobals = */ true);
+ CNE, blockCount, 0, 0);
if (CNE->hasInitializer()) {
- SVal V = state->getSVal(*CNE->constructor_arg_begin());
+ SVal V = state->getSVal(*CNE->constructor_arg_begin(),
+ (*I)->getLocationContext());
state = state->bindLoc(loc::MemRegionVal(EleReg), V);
} else {
// Explicitly set to undefined, because currently we retrieve symbolic
@@ -313,7 +317,8 @@
state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal());
}
}
- state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
+ state = state->BindExpr(CNE, (*I)->getLocationContext(),
+ loc::MemRegionVal(EleReg));
Bldr.generateNode(CNE, *I, state);
}
}
@@ -336,12 +341,13 @@
StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
// Get the this object region from StoreManager.
+ const LocationContext *LCtx = Pred->getLocationContext();
const MemRegion *R =
svalBuilder.getRegionManager().getCXXThisRegion(
getContext().getCanonicalType(TE->getType()),
- Pred->getLocationContext());
+ LCtx);
const ProgramState *state = Pred->getState();
SVal V = state->getSVal(loc::MemRegionVal(R));
- Bldr.generateNode(TE, Pred, state->BindExpr(TE, V));
+ Bldr.generateNode(TE, Pred, state->BindExpr(TE, LCtx, V));
}
Modified: cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=148545&r1=148544&r2=148545&view=diff
==============================================================================
--- cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/branches/tooling/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Fri Jan 20 10:14:22 2012
@@ -14,40 +14,72 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
#include "clang/AST/DeclCXX.h"
using namespace clang;
using namespace ento;
-namespace {
- // Trait class for recording returned expression in the state.
- struct ReturnExpr {
- static int TagInt;
- typedef const Stmt *data_type;
- };
- int ReturnExpr::TagInt;
+void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
+ // Get the entry block in the CFG of the callee.
+ const StackFrameContext *calleeCtx = CE.getCalleeContext();
+ const CFG *CalleeCFG = calleeCtx->getCFG();
+ const CFGBlock *Entry = &(CalleeCFG->getEntry());
+
+ // Validate the CFG.
+ assert(Entry->empty());
+ assert(Entry->succ_size() == 1);
+
+ // Get the solitary sucessor.
+ const CFGBlock *Succ = *(Entry->succ_begin());
+
+ // Construct an edge representing the starting location in the callee.
+ BlockEdge Loc(Entry, Succ, calleeCtx);
+
+ // Construct a new state which contains the mapping from actual to
+ // formal arguments.
+ const LocationContext *callerCtx = Pred->getLocationContext();
+ const ProgramState *state = Pred->getState()->enterStackFrame(callerCtx,
+ calleeCtx);
+
+ // Construct a new node and add it to the worklist.
+ bool isNew;
+ ExplodedNode *Node = G.getNode(Loc, state, false, &isNew);
+ Node->addPredecessor(Pred, G);
+ if (isNew)
+ Engine.getWorkList()->enqueue(Node);
}
-void ExprEngine::processCallEnter(CallEnterNodeBuilder &B) {
- const ProgramState *state =
- B.getState()->enterStackFrame(B.getCalleeContext());
- B.generateNode(state);
+static const ReturnStmt *getReturnStmt(const ExplodedNode *Node) {
+ while (Node) {
+ const ProgramPoint &PP = Node->getLocation();
+ // Skip any BlockEdges.
+ if (isa<BlockEdge>(PP) || isa<CallExit>(PP)) {
+ assert(Node->pred_size() == 1);
+ Node = *Node->pred_begin();
+ continue;
+ }
+ if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) {
+ const Stmt *S = SP->getStmt();
+ return dyn_cast<ReturnStmt>(S);
+ }
+ break;
+ }
+ return 0;
}
-void ExprEngine::processCallExit(CallExitNodeBuilder &B) {
- const ProgramState *state = B.getState();
- const ExplodedNode *Pred = B.getPredecessor();
+void ExprEngine::processCallExit(ExplodedNode *Pred) {
+ const ProgramState *state = Pred->getState();
const StackFrameContext *calleeCtx =
- cast<StackFrameContext>(Pred->getLocationContext());
+ Pred->getLocationContext()->getCurrentStackFrame();
+ const LocationContext *callerCtx = calleeCtx->getParent();
const Stmt *CE = calleeCtx->getCallSite();
// If the callee returns an expression, bind its value to CallExpr.
- const Stmt *ReturnedExpr = state->get<ReturnExpr>();
- if (ReturnedExpr) {
- SVal RetVal = state->getSVal(ReturnedExpr);
- state = state->BindExpr(CE, RetVal);
- // Clear the return expr GDM.
- state = state->remove<ReturnExpr>();
+ if (const ReturnStmt *RS = getReturnStmt(Pred)) {
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal V = state->getSVal(RS, LCtx);
+ state = state->BindExpr(CE, callerCtx, V);
}
// Bind the constructed object value to CXXConstructExpr.
@@ -57,10 +89,123 @@
SVal ThisV = state->getSVal(ThisR);
// Always bind the region to the CXXConstructExpr.
- state = state->BindExpr(CCE, ThisV);
+ state = state->BindExpr(CCE, Pred->getLocationContext(), ThisV);
+ }
+
+ static SimpleProgramPointTag returnTag("ExprEngine : Call Return");
+ PostStmt Loc(CE, callerCtx, &returnTag);
+ bool isNew;
+ ExplodedNode *N = G.getNode(Loc, state, false, &isNew);
+ N->addPredecessor(Pred, G);
+ if (!isNew)
+ return;
+
+ // Perform the post-condition check of the CallExpr.
+ ExplodedNodeSet Dst;
+ NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), N);
+ SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext,
+ &Ctx);
+ SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex());
+
+ getCheckerManager().runCheckersForPostStmt(Dst, N, CE, *this);
+
+ // Enqueue the next element in the block.
+ for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) {
+ Engine.getWorkList()->enqueue(*I,
+ calleeCtx->getCallSiteBlock(),
+ calleeCtx->getIndex()+1);
+ }
+}
+
+static unsigned getNumberStackFrames(const LocationContext *LCtx) {
+ unsigned count = 0;
+ while (LCtx) {
+ if (isa<StackFrameContext>(LCtx))
+ ++count;
+ LCtx = LCtx->getParent();
}
+ return count;
+}
+
+bool ExprEngine::InlineCall(ExplodedNodeSet &Dst,
+ const CallExpr *CE,
+ ExplodedNode *Pred) {
+ const ProgramState *state = Pred->getState();
+ const Expr *Callee = CE->getCallee();
+ const FunctionDecl *FD =
+ state->getSVal(Callee, Pred->getLocationContext()).getAsFunctionDecl();
+ if (!FD || !FD->hasBody(FD))
+ return false;
- B.generateNode(state);
+ switch (CE->getStmtClass()) {
+ default:
+ // FIXME: Handle C++.
+ break;
+ case Stmt::CallExprClass: {
+ // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
+ // These heuristics are a WIP.
+ if (getNumberStackFrames(Pred->getLocationContext()) == 5)
+ return false;
+
+ // Construct a new stack frame for the callee.
+ AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD);
+ const StackFrameContext *CallerSFC =
+ Pred->getLocationContext()->getCurrentStackFrame();
+ const StackFrameContext *CalleeSFC =
+ CalleeADC->getStackFrame(CallerSFC, CE,
+ currentBuilderContext->getBlock(),
+ currentStmtIdx);
+
+ CallEnter Loc(CE, CalleeSFC, Pred->getLocationContext());
+ bool isNew;
+ ExplodedNode *N = G.getNode(Loc, state, false, &isNew);
+ N->addPredecessor(Pred, G);
+ if (isNew)
+ Engine.getWorkList()->enqueue(N);
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool isPointerToConst(const ParmVarDecl *ParamDecl) {
+ QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType();
+ if (PointeeTy != QualType() && PointeeTy.isConstQualified() &&
+ !PointeeTy->isAnyPointerType() && !PointeeTy->isReferenceType()) {
+ return true;
+ }
+ return false;
+}
+
+// Try to retrieve the function declaration and find the function parameter
+// types which are pointers/references to a non-pointer const.
+// We do not invalidate the corresponding argument regions.
+static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
+ const CallOrObjCMessage &Call) {
+ const Decl *CallDecl = Call.getDecl();
+ if (!CallDecl)
+ return;
+
+ if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) {
+ for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) {
+ if (FDecl && Idx < FDecl->getNumParams()) {
+ if (isPointerToConst(FDecl->getParamDecl(Idx)))
+ PreserveArgs.insert(Idx);
+ }
+ }
+ return;
+ }
+
+ if (const ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(CallDecl)) {
+ assert(MDecl->param_size() <= Call.getNumArgs());
+ unsigned Idx = 0;
+ for (clang::ObjCMethodDecl::param_const_iterator
+ I = MDecl->param_begin(), E = MDecl->param_end(); I != E; ++I, ++Idx) {
+ if (isPointerToConst(*I))
+ PreserveArgs.insert(Idx);
+ }
+ return;
+ }
}
const ProgramState *
@@ -84,13 +229,21 @@
} else if (Call.isFunctionCall()) {
// Block calls invalidate all captured-by-reference values.
- if (const MemRegion *Callee = Call.getFunctionCallee().getAsRegion()) {
+ SVal CalleeVal = Call.getFunctionCallee();
+ if (const MemRegion *Callee = CalleeVal.getAsRegion()) {
if (isa<BlockDataRegion>(Callee))
RegionsToInvalidate.push_back(Callee);
}
}
+ // Indexes of arguments whose values will be preserved by the call.
+ llvm::SmallSet<unsigned, 1> PreserveArgs;
+ findPtrToConstParams(PreserveArgs, Call);
+
for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) {
+ if (PreserveArgs.count(idx))
+ continue;
+
SVal V = Call.getArgSVal(idx);
// If we are passing a location wrapped as an integer, unwrap it and
@@ -104,7 +257,7 @@
// Invalidate the value of the variable passed by reference.
// Are we dealing with an ElementRegion? If the element type is
- // a basic integer type (e.g., char, int) and the underying region
+ // a basic integer type (e.g., char, int) and the underlying region
// is a variable region then strip off the ElementRegion.
// FIXME: We really need to think about this for the general case
// as sometimes we are reasoning about arrays and other times
@@ -115,7 +268,7 @@
// we'll leave it in for now until we have a systematic way of
// handling all of these cases. Eventually we need to come up
// with an interface to StoreManager so that this logic can be
- // approriately delegated to the respective StoreManagers while
+ // appropriately delegated to the respective StoreManagers while
// still allowing us to do checker-specific logic (e.g.,
// invalidating reference counts), probably via callbacks.
if (ER->getElementType()->isIntegralOrEnumerationType()) {
@@ -152,7 +305,7 @@
// global variables.
return State->invalidateRegions(RegionsToInvalidate,
Call.getOriginExpr(), Count,
- &IS, doesInvalidateGlobals(Call));
+ &IS, &Call);
}
@@ -183,7 +336,7 @@
// Get the callee.
const Expr *Callee = CE->getCallee()->IgnoreParens();
const ProgramState *state = Pred->getState();
- SVal L = state->getSVal(Callee);
+ SVal L = state->getSVal(Callee, Pred->getLocationContext());
// Figure out the result type. We do this dance to handle references.
QualType ResultTy;
@@ -201,11 +354,12 @@
SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count);
// Generate a new state with the return value set.
- state = state->BindExpr(CE, RetVal);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ state = state->BindExpr(CE, LCtx, RetVal);
// Invalidate the arguments.
- const LocationContext *LC = Pred->getLocationContext();
- state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state), LC);
+ state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state, LCtx),
+ LCtx);
// And make the result node.
Bldr.generateNode(CE, Pred, state);
@@ -228,27 +382,19 @@
void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- ExplodedNodeSet Src;
- {
- StmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext);
- if (const Expr *RetE = RS->getRetValue()) {
- // Record the returned expression in the state. It will be used in
- // processCallExit to bind the return value to the call expr.
- {
- static SimpleProgramPointTag tag("ExprEngine: ReturnStmt");
- const ProgramState *state = Pred->getState();
- state = state->set<ReturnExpr>(RetE);
- Pred = Bldr.generateNode(RetE, Pred, state, false, &tag);
- }
- // We may get a NULL Pred because we generated a cached node.
- if (Pred) {
- Bldr.takeNodes(Pred);
- ExplodedNodeSet Tmp;
- Visit(RetE, Pred, Tmp);
- Bldr.addNodes(Tmp);
- }
+
+ ExplodedNodeSet dstPreVisit;
+ getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this);
+
+ StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext);
+
+ if (RS->getRetValue()) {
+ for (ExplodedNodeSet::iterator it = dstPreVisit.begin(),
+ ei = dstPreVisit.end(); it != ei; ++it) {
+ B.generateNode(RS, *it, (*it)->getState());
}
}
-
- getCheckerManager().runCheckersForPreStmt(Dst, Src, RS, *this);
+ else {
+ B.takeNodes(dstPreVisit);
+ }
}
More information about the llvm-branch-commits
mailing list