Index: lldb/trunk/include/lldb/Target/StackFrame.h =================================================================== --- lldb/trunk/include/lldb/Target/StackFrame.h +++ lldb/trunk/include/lldb/Target/StackFrame.h @@ -466,6 +466,16 @@ TrackGlobalVariable (const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic); //------------------------------------------------------------------ + /// Query this frame to determine what the default language should be + /// when parsing expressions given the execution context. + /// + /// @return + /// The language of the frame if known, else lldb::eLanguageTypeUnknown. + //------------------------------------------------------------------ + lldb::LanguageType + GetLanguage (); + + //------------------------------------------------------------------ // lldb::ExecutionContextScope pure virtual functions //------------------------------------------------------------------ lldb::TargetSP Index: lldb/trunk/source/Commands/CommandObjectExpression.cpp =================================================================== --- lldb/trunk/source/Commands/CommandObjectExpression.cpp +++ lldb/trunk/source/Commands/CommandObjectExpression.cpp @@ -289,8 +289,8 @@ if (target) { lldb::ValueObjectSP result_valobj_sp; - bool keep_in_memory = true; + StackFrame *frame = exe_ctx.GetFramePtr(); EvaluateExpressionOptions options; options.SetCoerceToId(m_varobj_options.use_objc); @@ -301,11 +301,15 @@ options.SetTryAllThreads(m_command_options.try_all_threads); options.SetDebug(m_command_options.debug); - // If the language was not specified, set it from target's properties + // If the language was not specified in the expression command, + // set it to the language in the target's properties if + // specified, else default to the langage for the frame. if (m_command_options.language != eLanguageTypeUnknown) options.SetLanguage(m_command_options.language); - else + else if (target->GetLanguage() != eLanguageTypeUnknown) options.SetLanguage(target->GetLanguage()); + else if (frame) + options.SetLanguage(frame->GetLanguage()); // If there is any chance we are going to stop and want to see // what went wrong with our expression, we should generate debug info @@ -318,8 +322,7 @@ else options.SetTimeoutUsec(0); - target->EvaluateExpression(expr, exe_ctx.GetFramePtr(), - result_valobj_sp, options); + target->EvaluateExpression(expr, frame, result_valobj_sp, options); if (result_valobj_sp) { Index: lldb/trunk/source/Expression/ClangExpressionParser.cpp =================================================================== --- lldb/trunk/source/Expression/ClangExpressionParser.cpp +++ lldb/trunk/source/Expression/ClangExpressionParser.cpp @@ -210,17 +210,38 @@ switch (language) { case lldb::eLanguageTypeC: + case lldb::eLanguageTypeC89: + case lldb::eLanguageTypeC99: + case lldb::eLanguageTypeC11: + // FIXME: the following language option is a temporary workaround, + // to "ask for C, get C++." + // For now, the expression parser must use C++ anytime the + // language is a C family language, because the expression parser + // uses features of C++ to capture values. + m_compiler->getLangOpts().CPlusPlus = true; break; case lldb::eLanguageTypeObjC: m_compiler->getLangOpts().ObjC1 = true; m_compiler->getLangOpts().ObjC2 = true; + // FIXME: the following language option is a temporary workaround, + // to "ask for ObjC, get ObjC++" (see comment above). + m_compiler->getLangOpts().CPlusPlus = true; break; case lldb::eLanguageTypeC_plus_plus: - m_compiler->getLangOpts().CPlusPlus = true; + case lldb::eLanguageTypeC_plus_plus_11: + case lldb::eLanguageTypeC_plus_plus_14: m_compiler->getLangOpts().CPlusPlus11 = true; m_compiler->getHeaderSearchOpts().UseLibcxx = true; + // fall thru ... + case lldb::eLanguageTypeC_plus_plus_03: + m_compiler->getLangOpts().CPlusPlus = true; + // FIXME: the following language option is a temporary workaround, + // to "ask for C++, get ObjC++". Apple hopes to remove this requirement + // on non-Apple platforms, but for now it is needed. + m_compiler->getLangOpts().ObjC1 = true; break; case lldb::eLanguageTypeObjC_plus_plus: + case lldb::eLanguageTypeUnknown: default: m_compiler->getLangOpts().ObjC1 = true; m_compiler->getLangOpts().ObjC2 = true; Index: lldb/trunk/source/Target/StackFrame.cpp =================================================================== --- lldb/trunk/source/Target/StackFrame.cpp +++ lldb/trunk/source/Target/StackFrame.cpp @@ -1316,6 +1316,15 @@ return false; } +lldb::LanguageType +StackFrame::GetLanguage () +{ + CompileUnit *cu = GetSymbolContext(eSymbolContextCompUnit).comp_unit; + if (cu) + return cu->GetLanguage(); + return lldb::eLanguageTypeUnknown; +} + TargetSP StackFrame::CalculateTarget () { Index: lldb/trunk/test/expression_command/options/TestExprOptions.py =================================================================== --- lldb/trunk/test/expression_command/options/TestExprOptions.py +++ lldb/trunk/test/expression_command/options/TestExprOptions.py @@ -26,15 +26,7 @@ self.line = line_number('main.cpp', '// breakpoint_in_main') self.exe = os.path.join(os.getcwd(), "a.out") - @skipUnlessDarwin - def test_expr_options_objc_cpp(self): - self.expr_options(test_objc = True, test_cpp = True) - - @skipIfDarwin # Already covered by test_expr_options_objc_cpp - def test_expr_options_cpp(self): - self.expr_options(test_objc = False, test_cpp = True) - - def expr_options(self, test_objc, test_cpp): + def test_expr_options(self): """These expression command options should work as expected.""" self.buildDefault() @@ -59,49 +51,26 @@ frame = threads[0].GetFrameAtIndex(0) options = lldb.SBExpressionOptions() - if test_objc: - # -- test --language on ObjC builtin type using the SB API's -- - # Make sure we can evaluate the ObjC builtin type 'id': - val = frame.EvaluateExpression('id my_id = 0; my_id') - self.assertTrue(val.IsValid()) - self.assertTrue(val.GetError().Success()) - self.assertEqual(val.GetValueAsUnsigned(0), 0) - self.DebugSBValue(val) - - # Make sure it still works if language is set to ObjC++: - options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) - val = frame.EvaluateExpression('id my_id = 0; my_id', options) - self.assertTrue(val.IsValid()) - self.assertTrue(val.GetError().Success()) - self.assertEqual(val.GetValueAsUnsigned(0), 0) - self.DebugSBValue(val) - - # Make sure it fails if language is set to C: - options.SetLanguage(lldb.eLanguageTypeC) - val = frame.EvaluateExpression('id my_id = 0; my_id', options) - self.assertTrue(val.IsValid()) - self.assertFalse(val.GetError().Success()) - - if test_cpp: - # -- test --language on C++ expression using the SB API's -- - # Make sure we can evaluate 'ns::func'. - val = frame.EvaluateExpression('ns::func') - self.assertTrue(val.IsValid()) - self.assertTrue(val.GetError().Success()) - self.DebugSBValue(val) - - # Make sure it still works if language is set to C++: - options.SetLanguage(lldb.eLanguageTypeC_plus_plus) - val = frame.EvaluateExpression('ns::func', options) - self.assertTrue(val.IsValid()) - self.assertTrue(val.GetError().Success()) - self.DebugSBValue(val) - - # Make sure it fails if language is set to C: - options.SetLanguage(lldb.eLanguageTypeC) - val = frame.EvaluateExpression('ns::func', options) - self.assertTrue(val.IsValid()) - self.assertFalse(val.GetError().Success()) + # test --language on C++ expression using the SB API's + + # Make sure we can evaluate 'ns::func'. + val = frame.EvaluateExpression('foo != nullptr') + self.assertTrue(val.IsValid()) + self.assertTrue(val.GetError().Success()) + self.DebugSBValue(val) + + # Make sure it still works if language is set to C++11: + options.SetLanguage(lldb.eLanguageTypeC_plus_plus_11) + val = frame.EvaluateExpression('foo != nullptr', options) + self.assertTrue(val.IsValid()) + self.assertTrue(val.GetError().Success()) + self.DebugSBValue(val) + + # Make sure it fails if language is set to C: + options.SetLanguage(lldb.eLanguageTypeC) + val = frame.EvaluateExpression('foo != nullptr', options) + self.assertTrue(val.IsValid()) + self.assertFalse(val.GetError().Success()) if __name__ == '__main__': import atexit Index: lldb/trunk/test/expression_command/persistent_ptr_update/TestPersistentPtrUpdate.py =================================================================== --- lldb/trunk/test/expression_command/persistent_ptr_update/TestPersistentPtrUpdate.py +++ lldb/trunk/test/expression_command/persistent_ptr_update/TestPersistentPtrUpdate.py @@ -42,7 +42,7 @@ self.runCmd("run", RUN_SUCCEEDED) - self.runCmd("expr void* $foo = nullptr") + self.runCmd("expr void* $foo = 0") self.runCmd("continue") Index: lldb/trunk/test/lang/mixed/Makefile =================================================================== --- lldb/trunk/test/lang/mixed/Makefile +++ lldb/trunk/test/lang/mixed/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../make + +CXX_SOURCES := foo.cpp +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules Index: lldb/trunk/test/lang/mixed/TestMixedLanguages.py =================================================================== --- lldb/trunk/test/lang/mixed/TestMixedLanguages.py +++ lldb/trunk/test/lang/mixed/TestMixedLanguages.py @@ -0,0 +1,59 @@ +"""Test that lldb works correctly on compile units form different languages.""" + +import os, time, re +import unittest2 +import lldb +from lldbtest import * + +class MixedLanguagesTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def test_language_of_frame(self): + """Test that the language defaults to the language of the current frame.""" + self.buildDefault() + exe = os.path.join(os.getcwd(), "a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # Execute the cleanup function during test case tear down + # to restore the frame format. + def cleanup(): + self.runCmd("settings set frame-format %s" % self.format_string, check=False) + self.addTearDownHook(cleanup) + self.runCmd("settings show frame-format") + m = re.match( + '^frame-format \(format-string\) = "(.*)\"$', + self.res.GetOutput()) + self.assertTrue(m, "Bad settings string") + self.format_string = m.group(1) + + # Change the default format to print the language. + format_string = "frame #${frame.index}: ${frame.pc}{ ${module.file.basename}`${function.name}{${function.pc-offset}}}{, lang=${language}}\n" + self.runCmd("settings set frame-format %s" % format_string) + self.expect("settings show frame-format", SETTING_MSG("frame-format"), + substrs = [format_string]) + + # Run to BP at main (in main.c) and test that the language is C. + self.runCmd("breakpoint set -n main") + self.runCmd("run") + self.expect("thread backtrace", + substrs = ["`main", "lang=c"]) + # Make sure evaluation of C++11 fails. + self.expect("expr foo != nullptr", error=True, + startstr = "error") + + # Run to BP at foo (in foo.cpp) and test that the language is C++. + self.runCmd("breakpoint set -n foo") + self.runCmd("continue") + self.expect("thread backtrace", + substrs = ["`::foo()", "lang=c++"]) + # Make sure we can evaluate an expression requiring C++11 + # (note: C++11 is enabled by default for C++). + self.expect("expr foo != nullptr", + patterns = ["true"]) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: lldb/trunk/test/lang/mixed/foo.cpp =================================================================== --- lldb/trunk/test/lang/mixed/foo.cpp +++ lldb/trunk/test/lang/mixed/foo.cpp @@ -0,0 +1,11 @@ +namespace ns { + int func(void) + { + return 0; + } +} + +extern "C" int foo(void) +{ + return ns::func(); +} Index: lldb/trunk/test/lang/mixed/main.c =================================================================== --- lldb/trunk/test/lang/mixed/main.c +++ lldb/trunk/test/lang/mixed/main.c @@ -0,0 +1,15 @@ +int foo(void); +static int static_value = 0; + +int +bar() +{ + static_value++; + return static_value; +} + +int main (int argc, char const *argv[]) +{ + bar(); // breakpoint_in_main + return foo(); +}